mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-15 12:31:31 +00:00
[Feature] Legacy Fizzle Code (#3868)
* [Feature] Legacy Fizzle Code Enabling UseLegacyFizzleCode will enable the legacy fizzle code system. New fizzle codes modeled on extensive testing in 2001/2002 (thank you druid's grove and graffe) * requested adjustments * Requested Changes
This commit is contained in:
parent
2c971fb2de
commit
079f612730
@ -468,6 +468,7 @@ RULE_INT(Spells, DefensiveProcPenaltyLevelGap, 6, "Defensive Proc Penalty Level
|
|||||||
RULE_REAL(Spells, DefensiveProcPenaltyLevelGapModifier, 10.0f, "Defensive Proc Penalty Level Gap Modifier where procs start losing their proc rate at defined % after RuleI(Spells, DefensiveProcLevelGap) level difference")
|
RULE_REAL(Spells, DefensiveProcPenaltyLevelGapModifier, 10.0f, "Defensive Proc Penalty Level Gap Modifier where procs start losing their proc rate at defined % after RuleI(Spells, DefensiveProcLevelGap) level difference")
|
||||||
RULE_BOOL(Spells, DOTBonusDamageSplitOverDuration, true, "Disable to have Damage Over Time total bonus damage added to each tick instead of divided across duration")
|
RULE_BOOL(Spells, DOTBonusDamageSplitOverDuration, true, "Disable to have Damage Over Time total bonus damage added to each tick instead of divided across duration")
|
||||||
RULE_BOOL(Spells, HOTBonusHealingSplitOverDuration, true, "Disable to have Heal Over Time total bonus healing added to each tick instead of divided across duration")
|
RULE_BOOL(Spells, HOTBonusHealingSplitOverDuration, true, "Disable to have Heal Over Time total bonus healing added to each tick instead of divided across duration")
|
||||||
|
RULE_BOOL(Spells, UseLegacyFizzleCode, false, "Enable will turn on the legacy fizzle code which is far stricter and more accurate to 2001/2002 testing.")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
|
|||||||
112
zone/spells.cpp
112
zone/spells.cpp
@ -1040,15 +1040,89 @@ bool Mob::CheckFizzle(uint16 spell_id)
|
|||||||
bool Client::CheckFizzle(uint16 spell_id)
|
bool Client::CheckFizzle(uint16 spell_id)
|
||||||
{
|
{
|
||||||
// GMs don't fizzle
|
// GMs don't fizzle
|
||||||
if (GetGM()) return(true);
|
if (GetGM()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint8 no_fizzle_level = 0;
|
uint8 no_fizzle_level = 0;
|
||||||
|
|
||||||
//Live AA - Spell Casting Expertise, Mastery of the Past
|
//Live AA - Spell Casting Expertise, Mastery of the Past
|
||||||
no_fizzle_level = aabonuses.MasteryofPast + itembonuses.MasteryofPast + spellbonuses.MasteryofPast;
|
no_fizzle_level = aabonuses.MasteryofPast + itembonuses.MasteryofPast + spellbonuses.MasteryofPast;
|
||||||
|
|
||||||
if (spells[spell_id].classes[GetClass()-1] < no_fizzle_level)
|
if (spells[spell_id].classes[GetClass()-1] < no_fizzle_level) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuleB(Spells, UseLegacyFizzleCode)) {
|
||||||
|
// CALCULATE SPELL DIFFICULTY - THIS IS CAPPED AT 255
|
||||||
|
// calculates minimum level this spell is available - ensures similar casting difficulty for all classes
|
||||||
|
|
||||||
|
int minimum_level = UINT8_MAX;
|
||||||
|
for (int a = 0; a < Class::PLAYER_CLASS_COUNT; a++) {
|
||||||
|
int this_lvl = spells[spell_id].classes[a];
|
||||||
|
if (this_lvl < minimum_level) {
|
||||||
|
minimum_level = this_lvl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spell_difficulty = (minimum_level * 5 < UINT8_MAX) ? minimum_level * 5 : UINT8_MAX;
|
||||||
|
|
||||||
|
// CALCULATE EFFECTIVE CASTING SKILL WITH BONUSES
|
||||||
|
int bonus_casting_level = itembonuses.adjusted_casting_skill + spellbonuses.adjusted_casting_skill + aabonuses.adjusted_casting_skill;
|
||||||
|
int caster_skill = GetSkill(spells[spell_id].skill) + bonus_casting_level * 5;
|
||||||
|
caster_skill = (caster_skill < UINT8_MAX) ? caster_skill : UINT8_MAX;
|
||||||
|
|
||||||
|
LogSpellsDetail("Caster Skill - itembonus.ACS(112) [{}] + spellbonus.ACS(112) [{}] + aabonus.ACS(112) [{}] = TotalBonusCastingLevel [{}] | caster_skill [{}] (Max 255)", itembonuses.adjusted_casting_skill, spellbonuses.adjusted_casting_skill, aabonuses.adjusted_casting_skill, bonus_casting_level, caster_skill);
|
||||||
|
|
||||||
|
// CALCULATE EFFECTIVE SPECIALIZATION SKILL VALUE
|
||||||
|
float specialize_skill_value = GetSpecializeSkillValue(spell_id);
|
||||||
|
switch (GetAA(aaSpellCastingMastery)) {
|
||||||
|
case 1:
|
||||||
|
specialize_skill_value = specialize_skill_value * 1.05;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
specialize_skill_value = specialize_skill_value * 1.15;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
specialize_skill_value = specialize_skill_value * 1.3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
float specialize_reduction = (specialize_skill_value > 50) ? (specialize_skill_value - 50) / 10 : 0.0f;
|
||||||
|
|
||||||
|
// CALCULATE EFFECTIVE CASTING STAT VALUE
|
||||||
|
float prime_stat_reduction = 0.0f;
|
||||||
|
|
||||||
|
if (GetCasterClass() == 'W') {
|
||||||
|
prime_stat_reduction = (GetWIS() - 75) / 10.0;
|
||||||
|
} else if (GetCasterClass() == 'I') {
|
||||||
|
prime_stat_reduction = (GetINT() - 75) / 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BARDS ARE SPECIAL - they add both CHA and DEX mods to get casting rates similar to full casters without spec skill
|
||||||
|
if (GetClass() == Class::Bard) {
|
||||||
|
prime_stat_reduction = (GetCHA() - 75 + GetDEX() - 75) / 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET SPELL-SPECIFIC FIZZLE CHANCE (note that specialization is only used to reduce the Fizzle_adjust!)
|
||||||
|
float spell_fizzle_adjust = static_cast<float>(spells[spell_id].base_difficulty);
|
||||||
|
spell_fizzle_adjust = (spell_fizzle_adjust - specialize_reduction > 0) ? spell_fizzle_adjust - specialize_reduction : 0.0f;
|
||||||
|
|
||||||
|
// CALCULATE FINAL FIZZLE CHANCE
|
||||||
|
float fizzle_chance = spell_difficulty + spell_fizzle_adjust - caster_skill - prime_stat_reduction;
|
||||||
|
|
||||||
|
if (fizzle_chance > 95.0f) {
|
||||||
|
fizzle_chance = 95.0f;
|
||||||
|
} else if (fizzle_chance < 2.0f) {
|
||||||
|
fizzle_chance = 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fizzle_roll = zone->random.Real(0, 100);
|
||||||
|
|
||||||
|
LogSpells("Check Fizzle [{}] spell: [{}] fizzle_chance: [{}] roll: [{}]", GetName(), spell_id, fizzle_chance, fizzle_roll);
|
||||||
|
|
||||||
|
return fizzle_roll > fizzle_chance;
|
||||||
|
}
|
||||||
|
|
||||||
//is there any sort of focus that affects fizzling?
|
//is there any sort of focus that affects fizzling?
|
||||||
|
|
||||||
@ -1056,20 +1130,21 @@ bool Client::CheckFizzle(uint16 spell_id)
|
|||||||
int act_skill;
|
int act_skill;
|
||||||
|
|
||||||
par_skill = spells[spell_id].classes[GetClass()-1] * 5 - 10;//IIRC even if you are lagging behind the skill levels you don't fizzle much
|
par_skill = spells[spell_id].classes[GetClass()-1] * 5 - 10;//IIRC even if you are lagging behind the skill levels you don't fizzle much
|
||||||
if (par_skill > 235)
|
if (par_skill > 235) {
|
||||||
par_skill = 235;
|
par_skill = 235;
|
||||||
|
}
|
||||||
|
|
||||||
par_skill += spells[spell_id].classes[GetClass()-1]; // maximum of 270 for level 65 spell
|
par_skill += spells[spell_id].classes[GetClass()-1]; // maximum of 270 for level 65 spell
|
||||||
|
|
||||||
act_skill = GetSkill(spells[spell_id].skill);
|
act_skill = GetSkill(spells[spell_id].skill);
|
||||||
act_skill += GetLevel(); // maximum of whatever the client can cheat
|
act_skill += GetLevel(); // maximum of whatever the client can cheat
|
||||||
act_skill += itembonuses.adjusted_casting_skill + spellbonuses.adjusted_casting_skill + aabonuses.adjusted_casting_skill;
|
act_skill += itembonuses.adjusted_casting_skill + spellbonuses.adjusted_casting_skill + aabonuses.adjusted_casting_skill;
|
||||||
LogSpells("Adjusted casting skill: [{}]+[{}]+[{}]+[{}]+[{}]=[{}]", GetSkill(spells[spell_id].skill), GetLevel(), itembonuses.adjusted_casting_skill, spellbonuses.adjusted_casting_skill, aabonuses.adjusted_casting_skill, act_skill);
|
LogSpellsDetail("Adjusted casting skill: [{}]+[{}]+[{}]+[{}]+[{}]=[{}]", GetSkill(spells[spell_id].skill), GetLevel(), itembonuses.adjusted_casting_skill, spellbonuses.adjusted_casting_skill, aabonuses.adjusted_casting_skill, act_skill);
|
||||||
|
|
||||||
//spell specialization
|
//spell specialization
|
||||||
float specialize = GetSpecializeSkillValue(spell_id);
|
float specialize = GetSpecializeSkillValue(spell_id);
|
||||||
if(specialize > 0) {
|
if (specialize > 0) {
|
||||||
switch(GetAA(aaSpellCastingMastery)){
|
switch (GetAA(aaSpellCastingMastery)) {
|
||||||
case 1:
|
case 1:
|
||||||
specialize = specialize * 1.05;
|
specialize = specialize * 1.05;
|
||||||
break;
|
break;
|
||||||
@ -1080,7 +1155,7 @@ bool Client::CheckFizzle(uint16 spell_id)
|
|||||||
specialize = specialize * 1.3;
|
specialize = specialize * 1.3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(((specialize/6.0f) + 15.0f) < zone->random.Real(0, 100)) {
|
if (((specialize / 6.0f) + 15.0f) < zone->random.Real(0, 100)) {
|
||||||
specialize *= SPECIALIZE_FIZZLE / 200.0f;
|
specialize *= SPECIALIZE_FIZZLE / 200.0f;
|
||||||
} else {
|
} else {
|
||||||
specialize = 0.0f;
|
specialize = 0.0f;
|
||||||
@ -1094,33 +1169,26 @@ bool Client::CheckFizzle(uint16 spell_id)
|
|||||||
float diff = par_skill + static_cast<float>(spells[spell_id].base_difficulty) - act_skill;
|
float diff = par_skill + static_cast<float>(spells[spell_id].base_difficulty) - act_skill;
|
||||||
|
|
||||||
// if you have high int/wis you fizzle less, you fizzle more if you are stupid
|
// if you have high int/wis you fizzle less, you fizzle more if you are stupid
|
||||||
if(GetClass() == Class::Bard)
|
if (GetClass() == Class::Bard) {
|
||||||
{
|
|
||||||
diff -= (GetCHA() - 110) / 20.0;
|
diff -= (GetCHA() - 110) / 20.0;
|
||||||
}
|
} else if (GetCasterClass() == 'W') {
|
||||||
else if (GetCasterClass() == 'W')
|
|
||||||
{
|
|
||||||
diff -= (GetWIS() - 125) / 20.0;
|
diff -= (GetWIS() - 125) / 20.0;
|
||||||
}
|
} else if (GetCasterClass() == 'I') {
|
||||||
else if (GetCasterClass() == 'I')
|
|
||||||
{
|
|
||||||
diff -= (GetINT() - 125) / 20.0;
|
diff -= (GetINT() - 125) / 20.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// base fizzlechance is lets say 5%, we can make it lower for AA skills or whatever
|
// base fizzlechance is lets say 5%, we can make it lower for AA skills or whatever
|
||||||
float basefizzle = 10;
|
float base_fizzle = 10;
|
||||||
float fizzlechance = basefizzle - specialize + diff / 5.0;
|
float fizzle_chance = base_fizzle - specialize + diff / 5.0;
|
||||||
|
|
||||||
// always at least 1% chance to fail or 5% to succeed
|
// always at least 1% chance to fail or 5% to succeed
|
||||||
fizzlechance = fizzlechance < 1 ? 1 : (fizzlechance > 95 ? 95 : fizzlechance);
|
fizzle_chance = fizzle_chance < 1 ? 1 : (fizzle_chance > 95 ? 95 : fizzle_chance);
|
||||||
|
|
||||||
float fizzle_roll = zone->random.Real(0, 100);
|
float fizzle_roll = zone->random.Real(0, 100);
|
||||||
|
|
||||||
LogSpells("Check Fizzle [{}] spell [{}] fizzlechance: [{}] diff: [{}] roll: [{}]", GetName(), spell_id, fizzlechance, diff, fizzle_roll);
|
LogSpells("Check Fizzle [{}] spell [{}] fizzlechance: [{}] diff: [{}] roll: [{}]", GetName(), spell_id, fizzle_chance, diff, fizzle_roll);
|
||||||
|
|
||||||
if(fizzle_roll > fizzlechance)
|
return fizzle_roll > fizzle_chance;
|
||||||
return(true);
|
|
||||||
return(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::ZeroCastingVars()
|
void Mob::ZeroCastingVars()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user