diff --git a/changelog.txt b/changelog.txt index d0b41ca39..1f71612b5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,9 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- -== 02/2/2014 == -Kayen: Revised how spell/dot damage is calculated to properly incorporated all current focus effects/bonuses. +== 02/7/2014 == +Kayen: Revised how heal amount is calculated to properly incorporate all current focus effects/bonuses. +== 02/2/2014 == +Kayen: Revised how spell/dot damage is calculated to properly incorporate all current focus effects/bonuses. Required SQL: utils/sql/git/2014_02_02_SpellCriticalsAA.sql diff --git a/common/spdat.h b/common/spdat.h index a59dd88e5..d8ed6fb17 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -538,11 +538,11 @@ typedef enum { #define SE_Forceful_Rejuv 389 // Refresh spell icons #define SE_SetRecastTimer 390 // *not implemented - Sets recast timers to specific value, focus limited. #define SE_IncreaseHitDmgTaken 391 // implemented - Most likely a simple negative mitigation modifier (Warlords fury: 23528) -#define SE_AdditionalHeal2 392 // implemented - Adds or removes healing from spells -#define SE_HealRate2 393 // implemented - HealRate with focus restrictions. +#define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells +#define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions. #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. -#define SE_CriticalHealRate 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] -#define SE_AdditionalHeal 396 // implemented - Adds a direct healing amount to spells +#define SE_FcHealPctCritIncoming 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] +#define SE_FcHealAmtCrit 396 // implemented - Adds a direct healing amount to spells #define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets. #define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets #define SE_Twincast 399 // implemented - cast 2 spells for every 1 diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index b60381687..04e8103dc 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1212,6 +1212,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) case SE_CriticalMend: newbon->CriticalMend += base1; break; + + case SE_HealRate: + newbon->HealRate += base1; + break; } } } @@ -2792,8 +2796,8 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff return focusFcDamageAmtIncoming; case SE_FcHealAmtIncoming: return focusFcHealAmtIncoming; - case SE_HealRate2: - return focusHealRate; + case SE_FcHealPctIncoming: + return focusFcHealPctIncoming; case SE_FcBaseEffects: return focusFcBaseEffects; case SE_IncreaseNumHits: @@ -2804,12 +2808,12 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff return focusFcMute; case SE_FcStunTimeMod: return focusFcStunTimeMod; - case SE_CriticalHealRate: - return focusCriticalHealRate; - case SE_AdditionalHeal2: - return focusAdditionalHeal2; - case SE_AdditionalHeal: - return focusAdditionalHeal; + case SE_FcHealPctCritIncoming: + return focusFcHealPctCritIncoming; + case SE_FcHealAmt: + return focusFcHealAmt; + case SE_FcHealAmtCrit: + return focusFcHealAmtCrit; } return 0; } diff --git a/zone/bot.cpp b/zone/bot.cpp index 1bb6eb3e7..6b040139c 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -9119,23 +9119,6 @@ void Bot::SetAttackTimer() { } } -int32 Bot::Additional_SpellDmg(uint16 spell_id, bool bufftick) -{ - int32 spell_dmg = 0; - spell_dmg += GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id); - spell_dmg += GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - - //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it) - if (bufftick){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return spell_dmg /= duration; - else - return 0; - } - return spell_dmg; -} - int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spells[spell_id].targettype == ST_Self) @@ -9195,8 +9178,8 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100; + if(itembonuses.SpellDmg && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value); @@ -9219,71 +9202,74 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value); + if(itembonuses.SpellDmg && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); return value; } -int32 Bot::Additional_Heal(uint16 spell_id) -{ - int32 heal_amt = 0; +int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { + + if (target == nullptr) + target = this; - heal_amt += GetBotFocusEffect(BotfocusAdditionalHeal, spell_id); - heal_amt += GetBotFocusEffect(BotfocusAdditionalHeal2, spell_id); - - if (heal_amt){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return heal_amt /= duration; - } - - return heal_amt; -} - -int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value) { - int32 modifier = 100; - int16 heal_amt = 0; - modifier += GetBotFocusEffect(BotfocusImprovedHeal, spell_id); - modifier += GetBotFocusEffect(BotfocusFcBaseEffects, spell_id); - heal_amt += Additional_Heal(spell_id); - int chance = 0; + int32 value_BaseEffect = 0; + int16 chance = 0; + int8 modifier = 1; + bool Critical = false; + + value_BaseEffect = value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id)/100); + + value = value_BaseEffect; + value += int(value_BaseEffect*GetBotFocusEffect(BotfocusImprovedHeal, spell_id)/100); + + // Instant Heals if(spells[spell_id].buffduration < 1) { - uint8 botlevel = GetLevel(); - uint8 botclass = GetClass(); - // Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself. - if(this->itembonuses.HealAmt && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) { - heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000; - if(heal_amt > value) - heal_amt = value; - } - // Check for buffs that affect the healrate of the target and critical heal rate of target - if(GetTarget()) { - value += value * GetHealRate(spell_id) / 100; - chance += GetCriticalHealRate(spell_id); - } + chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - //Live AA - Healing Gift, Theft of Life - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + chance += target->GetBotFocusIncoming(BotfocusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalHealDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) { + Critical = true; + modifier = 2; //At present time no critical heal amount modifier SPA exists. + } + + value *= modifier; + value += GetBotFocusEffect(BotfocusFcHealAmtCrit, spell_id) * modifier; + value += GetBotFocusEffect(BotfocusFcHealAmt, spell_id); + value += target->GetBotFocusIncoming(BotfocusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + + if(itembonuses.HealAmt && spells[spell_id].classes[(botclass%16) - 1] >= botlevel - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - if(MakeRandomInt(0,99) < chance) { - entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2)); - return ((value * modifier / 50) + heal_amt*2); - } - else{ - return ((value * modifier / 100) + heal_amt); - } + value += value*target->GetHealRate(spell_id, this)/100; + + if (Critical) + entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); + + return value; } - // Hots + + //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] else { - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - if(MakeRandomInt(0,99) < chance) - return ((value * modifier / 50) + heal_amt*2); + + chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance += target->GetBotFocusIncoming(BotfocusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) + return (value * 2); } - return ((value * modifier / 100) + heal_amt); + return value; } int32 Bot::GetActSpellCasttime(uint16 spell_id, int32 casttime) { diff --git a/zone/bot.h b/zone/bot.h index 9412abe02..66e283116 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -86,13 +86,13 @@ public: BotfocusSwarmPetDuration, BotfocusReduceRecastTime, BotfocusBlockNextSpell, - BotfocusHealRate, + BotfocusFcHealPctIncoming, BotfocusFcDamageAmtIncoming, BotfocusFcBaseEffects, BotfocusIncreaseNumHits, - BotfocusCriticalHealRate, - BotfocusAdditionalHeal2, - BotfocusAdditionalHeal, + BotfocusFcHealPctCritIncoming, + BotfocusFcHealAmt, + BotfocusFcHealAmtCrit, }; enum BotTradeType { // types of trades a bot can do @@ -301,10 +301,8 @@ public: // Mob Spell Virtual Override Methods virtual void SpellProcess(); - int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false); - int32 Additional_Heal(uint16 spell_id); - virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target); - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value); + virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target == nullptr); + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target == nullptr); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); virtual int32 GetActSpellCost(uint16 spell_id, int32 cost); virtual float GetActSpellRange(uint16 spell_id, float range); diff --git a/zone/client.h b/zone/client.h index 4d736ce18..c2ef8675e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -472,11 +472,9 @@ public: inline virtual int16 GetDelayDeath() const { return aabonuses.DelayDeath + spellbonuses.DelayDeath + itembonuses.DelayDeath + 11; } - int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false); - int32 Additional_Heal(uint16 spell_id); float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); - int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob *target = nullptr); - int32 GetActSpellHealing(uint16 spell_id, int32 value); + int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); + int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); int32 GetActSpellCost(uint16 spell_id, int32); int32 GetActSpellDuration(uint16 spell_id, int32); int32 GetActSpellCasttime(uint16 spell_id, int32); diff --git a/zone/common.h b/zone/common.h index 92cd91ea6..67aae10e7 100644 --- a/zone/common.h +++ b/zone/common.h @@ -71,7 +71,7 @@ typedef enum { //focus types focusSwarmPetDuration, focusReduceRecastTime, focusBlockNextSpell, - focusHealRate, + focusFcHealPctIncoming, focusFcDamageAmtIncoming, focusFcHealAmtIncoming, focusFcBaseEffects, @@ -79,11 +79,11 @@ typedef enum { //focus types focusFcLimitUse, focusFcMute, focusFcStunTimeMod, - focusCriticalHealRate, - focusAdditionalHeal2, - focusAdditionalHeal, + focusFcHealPctCritIncoming, + focusFcHealAmt, + focusFcHealAmtCrit, } focusType; //Any new FocusType needs to be added to the Mob::IsFocus function -#define HIGHEST_FOCUS focusAdditionalHeal //Should always be last focusType in enum +#define HIGHEST_FOCUS focusFcHealAmtCrit //Should always be last focusType in enum enum { SPECATK_SUMMON = 1, diff --git a/zone/effects.cpp b/zone/effects.cpp index d446852c2..59bd52d47 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -40,23 +40,6 @@ float Client::GetActSpellRange(uint16 spell_id, float range, bool IsBard) } -int32 Client::Additional_SpellDmg(uint16 spell_id, bool bufftick) -{ - int32 spell_dmg = 0; - spell_dmg += GetFocusEffect(focusFcDamageAmtCrit, spell_id); - spell_dmg += GetFocusEffect(focusFcDamageAmt, spell_id); - - //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it) - if (bufftick){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return spell_dmg /= duration; - else - return 0; - } - return spell_dmg; -} - int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { //Quest scale all NPC spell damage via $npc->SetSpellFocusDMG(value) @@ -138,7 +121,7 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100; + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value); @@ -162,7 +145,7 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value); + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); return value; } @@ -199,8 +182,11 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + GetFocusEffect(focusFcDamageAmt, spell_id); - if (extra_dmg) - extra_dmg /= CalcBuffDuration(this, this, spell_id); + if (extra_dmg) { + int duration = CalcBuffDuration(this, this, spell_id); + if (duration > 0) + extra_dmg /= duration; + } value -= extra_dmg; @@ -220,41 +206,18 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { GetFocusEffect(focusFcDamageAmtCrit, spell_id) + GetFocusEffect(focusFcDamageAmt, spell_id); - if (extra_dmg) - extra_dmg /= CalcBuffDuration(this, this, spell_id); + if (extra_dmg) { + int duration = CalcBuffDuration(this, this, spell_id); + if (duration > 0) + extra_dmg /= duration; + } value -= extra_dmg; return value; } - /* - int32 modifier = 100; - int16 spell_dmg = 0; - int16 critChance = 0; - int32 ratio = 0; - - modifier += GetFocusEffect(focusImprovedDamage, spell_id); - critChance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance; - ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; - spell_dmg += Additional_SpellDmg(spell_id,true); - - if (spellbonuses.CriticalDotDecay) - critChance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay); - - if (critChance > 0){ - if (MakeRandomInt(0, 99) < critChance){ - modifier += modifier*ratio/100; - return (((value*modifier/100)-spell_dmg)*2); - } - } - - return ((value*modifier/100)-spell_dmg); - */ - - - -int32 Mob::GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_spell_dmg) +int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg) { int total_cast_time = 0; @@ -264,54 +227,100 @@ int32 Mob::GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_s total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; if (total_cast_time > 0 && total_cast_time <= 2500) - extra_spell_dmg = extra_spell_dmg*25/100; + extra_spell_amt = extra_spell_amt*25/100; else if (total_cast_time > 2500 && total_cast_time < 7000) - extra_spell_dmg = extra_spell_dmg*(0.167*((total_cast_time - 1000)/1000)); + extra_spell_amt = extra_spell_amt*(0.167*((total_cast_time - 1000)/1000)); else - extra_spell_dmg = extra_spell_dmg * total_cast_time / 7000; + extra_spell_amt = extra_spell_amt * total_cast_time / 7000; - extra_spell_dmg = -extra_spell_dmg; - - if(extra_spell_dmg*2 < base_spell_dmg) + if(extra_spell_amt*2 < base_spell_dmg) return 0; - return extra_spell_dmg; + return extra_spell_amt; } -//Scale all NPC spell healing via SetSpellFocusHeal(value) -int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value) { +int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { - int32 modifier = 100; - modifier += SpellFocusHeal; + //Scale all NPC spell healing via SetSpellFocusHeal(value) - // Check for buffs that affect the healrate of the target - if(this->GetTarget()) - { - value += value * GetHealRate(spell_id) / 100; + value += value*SpellFocusHeal/100; + + if (target) { + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + value += value*target->GetHealRate(spell_id, this)/100; + } + + return value; +} + +int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { + + if (target == nullptr) + target = this; + + int32 value_BaseEffect = 0; + int16 chance = 0; + int8 modifier = 1; + bool Critical = false; + + value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); + + value = value_BaseEffect; + + value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100); + + // Instant Heals + if(spells[spell_id].buffduration < 1) { + + chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalHealDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) { + Critical = true; + modifier = 2; //At present time no critical heal amount modifier SPA exists. } + + value *= modifier; + value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier; + value += GetFocusEffect(focusFcHealAmt, spell_id); + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + + if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - return (value * modifier / 100); -} + value += value*target->GetHealRate(spell_id, this)/100; -int32 Client::Additional_Heal(uint16 spell_id) -{ - int32 heal_amt = 0; + if (Critical) + entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); - heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id); - heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id); - heal_amt -= GetFocusEffect(focusFcHealAmtIncoming, spell_id); - - if (heal_amt){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return heal_amt /= duration; + return value; } - return heal_amt; + //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] + else { + + chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) + return (value * 2); + } + + return value; } -int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) { + +/* +int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 modifier = 100; int16 heal_amt = 0; @@ -362,6 +371,7 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) { } return ((value * modifier / 100) + heal_amt); } +*/ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) { diff --git a/zone/merc.cpp b/zone/merc.cpp index 7c7dcf60c..6da94f3e3 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -2771,22 +2771,6 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) { return realTotal + realTotal2 + realTotal3; } -int32 Merc::Additional_SpellDmg(uint16 spell_id, bool bufftick) -{ - int32 spell_dmg = 0; - spell_dmg += GetFocusEffect(focusFcDamageAmtCrit, spell_id); - spell_dmg += GetFocusEffect(focusFcDamageAmt, spell_id); - - //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it) - if (bufftick){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return spell_dmg /= duration; - else - return 0; - } - return spell_dmg; -} int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { @@ -2836,7 +2820,7 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value)*ratio/100; + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; value = (value * GetSpellScale() / 100); @@ -2862,76 +2846,75 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellDmg(spell_id, itembonuses.SpellDmg, value); + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); value = (value * GetSpellScale() / 100); return value; } -int32 Merc::Additional_Heal(uint16 spell_id) -{ - int32 heal_amt = 0; +int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { + + if (target == nullptr) + target = this; - heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id); - heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id); - heal_amt += GetFocusEffect(focusFcHealAmtIncoming, spell_id); - - if (heal_amt){ - int duration = CalcBuffDuration(this, this, spell_id); - if (duration > 0) - return heal_amt /= duration; - } - - return heal_amt; -} - -int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value) { - - int32 modifier = 100; - int16 heal_amt = 0; - modifier += GetFocusEffect(focusImprovedHeal, spell_id); - modifier += GetFocusEffect(focusFcBaseEffects, spell_id); - heal_amt += Additional_Heal(spell_id); - int chance = 0; + int32 value_BaseEffect = 0; + int16 chance = 0; + int8 modifier = 1; + bool Critical = false; + + value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); + + value = value_BaseEffect; + value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100); + // Instant Heals - if(spells[spell_id].buffduration < 1) - { - // Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself. - if(this->itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) { - heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000; - if(heal_amt > value) - heal_amt = value; - } + if(spells[spell_id].buffduration < 1) { - // Check for buffs that affect the healrate of the target and critical heal rate of target - if(GetTarget()){ - value += value * GetHealRate(spell_id) / 100; - chance += GetCriticalHealRate(spell_id); - } + chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - //Live AA - Healing Gift, Theft of Life - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalHealDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) { + Critical = true; + modifier = 2; //At present time no critical heal amount modifier SPA exists. + } + + value *= modifier; + value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier; + value += GetFocusEffect(focusFcHealAmt, spell_id); + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + + if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - if(MakeRandomInt(0,99) < chance) { - entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2)); - heal_amt = ((value * modifier / 50) + heal_amt*2); - } - else{ - heal_amt = ((value * modifier / 100) + heal_amt); - } + value += value*target->GetHealRate(spell_id, this)/100; + + if (Critical) + entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); + + return value; } - // Hots + + //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] else { - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - if(MakeRandomInt(0,99) < chance) - heal_amt = ((value * modifier / 50) + heal_amt*2); + + chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); + + if(chance && (MakeRandomInt(0,99) < chance)) + return (value * 2); } - heal_amt = (heal_amt * GetHealScale() / 100); - - return heal_amt; + return value; } int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) diff --git a/zone/merc.h b/zone/merc.h index 09b9df811..fd7f69fa4 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -77,10 +77,8 @@ public: Corpse* GetGroupMemberCorpse(); // Merc Spell Casting Methods - int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false); - int32 Additional_Heal(uint16 spell_id); virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value); + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); virtual int32 GetActSpellCost(uint16 spell_id, int32 cost); int8 GetChanceToCastBySpellType(int16 spellType); diff --git a/zone/mob.cpp b/zone/mob.cpp index 8e423bbfe..c9f96e6a7 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3429,37 +3429,19 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) return skilldmg_mod; } -int16 Mob::GetHealRate(uint16 spell_id) -{ - Mob* target = GetTarget(); - +int16 Mob::GetHealRate(uint16 spell_id, Mob* caster) { + int16 heal_rate = 0; - if (target){ - heal_rate = target->itembonuses.HealRate + target->spellbonuses.HealRate; - - if (target->IsClient()) - heal_rate += target->CastToClient()->GetFocusEffect(focusHealRate, spell_id); - - if(heal_rate < -99) - heal_rate = -99; - } + heal_rate += itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; + heal_rate += GetFocusIncoming(focusFcHealPctIncoming, SE_FcHealPctIncoming, caster, spell_id); + if(heal_rate < -99) + heal_rate = -99; + return heal_rate; } -int16 Mob::GetCriticalHealRate(uint16 spell_id) -{ - Mob* target = GetTarget(); - - int16 critical_heal_rate = 0; - - if (target && target->IsClient()) - critical_heal_rate = target->CastToClient()->GetFocusEffect(focusCriticalHealRate, spell_id); - - return critical_heal_rate; -} - bool Mob::TryFadeEffect(int slot) { if(IsValidSpell(buffs[slot].spellid)) @@ -4669,7 +4651,7 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { if (!IsValidSpell(spell_id)) return false; - int spell_level = spells[spell_id].classes[(GetClass()%16) - 1]; + int spell_level = spells[spell_id].classes[(GetClass()%16) - 1]; int effect_value = 0; int lvlModifier = 100; @@ -4679,15 +4661,15 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { for (int i = 0; i < EFFECT_COUNT; i++){ if(spells[buffs[slot].spellid].effectid[i] == spelleffect) { - int critchance = spells[buffs[slot].spellid].base[i]; + int critchance = spells[buffs[slot].spellid].base[i]; int decay = spells[buffs[slot].spellid].base2[i]; - int lvldiff = spell_level - spells[buffs[slot].spellid].max[i]; + int lvldiff = spell_level - spells[buffs[slot].spellid].max[i]; if(lvldiff > 0 && decay > 0) { - lvlModifier -= decay*lvldiff; + lvlModifier -= decay*lvldiff; if (lvlModifier > 0){ - critchance = (critchance*lvlModifier)/100; + critchance = (critchance*lvlModifier)/100; effect_value += critchance; } } diff --git a/zone/mob.h b/zone/mob.h index 796170b34..a0ad73578 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -172,7 +172,7 @@ public: void NegateSpellsBonuses(uint16 spell_id); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false) { return range;} virtual int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr) { return value; } - virtual int32 GetActSpellHealing(uint16 spell_id, int32 value) { return value; } + virtual int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr) { return value; } virtual int32 GetActSpellCost(uint16 spell_id, int32 cost){ return cost;} virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration){ return duration;} virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); @@ -548,10 +548,10 @@ public: void TrySympatheticProc(Mob *target, uint32 spell_id); bool TryFadeEffect(int slot); uint16 GetSpellEffectResistChance(uint16 spell_id); - int16 GetHealRate(uint16 spell_id); - int16 GetCriticalHealRate(uint16 spell_id); + int16 GetHealRate(uint16 spell_id, Mob* caster = nullptr); int32 GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining); int32 GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0); + int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id); int16 GetSkillDmgTaken(const SkillUseTypes skill_used); void DoKnockback(Mob *caster, uint32 pushback, uint32 pushup); int16 CalcResistChanceBonus(); @@ -574,7 +574,7 @@ public: bool DoHPToManaCovert(uint16 mana_cost = 0); int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false); int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect); - int32 GetExtraSpellDmg(uint16 spell_id, int32 extra_spell_dmg, int32 base_spell_dmg); + int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg); void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); diff --git a/zone/npc.h b/zone/npc.h index 324826b37..bcb69e0d7 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -110,7 +110,7 @@ public: int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr); - int32 GetActSpellHealing(uint16 spell_id, int32 value); + int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr); inline void SetSpellFocusDMG(int32 NewSpellFocusDMG) {SpellFocusDMG = NewSpellFocusDMG;} inline void SetSpellFocusHeal(int32 NewSpellFocusHeal) {SpellFocusHeal = NewSpellFocusHeal;} int32 SpellFocusDMG; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index bb875f90f..638e55fe9 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -363,7 +363,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(caster) - dmg = caster->GetActSpellHealing(spell_id, dmg); + dmg = caster->GetActSpellHealing(spell_id, dmg, this); HealDamage(dmg, caster); } @@ -415,7 +415,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) int32 val = spell.max[i]; if(caster) - val = caster->GetActSpellHealing(spell_id, val); + val = caster->GetActSpellHealing(spell_id, val, this); int32 mhp = GetMaxHP(); int32 cap = mhp * spell.base[i] / 100; @@ -2396,7 +2396,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } else if(dmg > 0) { //healing spell... if(caster) - dmg = caster->GetActSpellHealing(spell_id, dmg); + dmg = caster->GetActSpellHealing(spell_id, dmg, this); HealDamage(dmg, caster); } #ifdef SPELL_EFFECT_SPAM @@ -2867,7 +2867,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_AntiGate: case SE_Fearless: case SE_FcDamageAmtCrit: - case SE_AdditionalHeal: + case SE_FcHealAmtCrit: case SE_CastOnCurer: case SE_CastOnCure: case SE_CastonNumHitFade: @@ -2878,8 +2878,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ACv2: case SE_ManaRegen_v2: case SE_FcDamagePctCrit: - case SE_AdditionalHeal2: - case SE_HealRate2: + case SE_FcHealAmt: + case SE_FcHealPctIncoming: case SE_CriticalHealDecay: case SE_CriticalRegenDecay: case SE_FcDamageAmtIncoming: @@ -2922,7 +2922,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_UnfailingDivinity: case SE_ChannelChanceSpells: case SE_ChannelChanceItems: - case SE_CriticalHealRate: + case SE_FcHealPctCritIncoming: case SE_IncreaseNumHits: case SE_CastonFocusEffect: case SE_FcHealAmtIncoming: @@ -3341,7 +3341,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste effect_value = CalcSpellEffectValue(spell_id, i, caster_level); if(caster) effect_value = caster->GetActSpellHealing(spell_id, effect_value); - effect_value += effect_value * (itembonuses.HealRate + spellbonuses.HealRate) / 100; + //effect_value += effect_value * (itembonuses.HealRate + spellbonuses.HealRate) / 100; HealDamage(effect_value, caster); //healing aggro would go here; removed for now break; @@ -4357,33 +4357,33 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; } - case SE_CriticalHealRate: + case SE_FcHealPctCritIncoming: { - if (type == focusCriticalHealRate) + if (type == focusFcHealPctCritIncoming) value = base1; break; } - case SE_AdditionalHeal: + case SE_FcHealAmtCrit: { - if(type == focusAdditionalHeal) + if(type == focusFcHealAmtCrit) value = base1; break; } - case SE_AdditionalHeal2: + case SE_FcHealAmt: { - if(type == focusAdditionalHeal2) + if(type == focusFcHealAmt) value = base1; break; } - case SE_HealRate2: + case SE_FcHealPctIncoming: { - if(type == focusHealRate) + if(type == focusFcHealPctIncoming) value = base1; break; @@ -4890,33 +4890,33 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; } - case SE_CriticalHealRate: + case SE_FcHealPctCritIncoming: { - if (type == focusCriticalHealRate) + if (type == focusFcHealPctCritIncoming) value = focus_spell.base[i]; break; } - case SE_AdditionalHeal: + case SE_FcHealAmtCrit: { - if(type == focusAdditionalHeal) + if(type == focusFcHealAmtCrit) value = focus_spell.base[i]; break; } - case SE_AdditionalHeal2: + case SE_FcHealAmt: { - if(type == focusAdditionalHeal2) + if(type == focusFcHealAmt) value = focus_spell.base[i]; break; } - case SE_HealRate2: + case SE_FcHealPctIncoming: { - if(type == focusHealRate) + if(type == focusFcHealPctIncoming) value = focus_spell.base[i]; break; @@ -5662,6 +5662,58 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, return dmg; } +int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id) { + + /* + This is a general function for calculating best focus effect values for focus effects that exist on targets but modify incoming spells. + Should be used when checking for foci that can exist on clients or npcs ect. + Example: When your target has a focus limited buff that increases amount of healing on them. + */ + + if (!caster) + return 0; + + int value = 0; + + if (spellbonuses.FocusEffects[type]){ + uint32 buff_count = GetMaxTotalSlots(); + for(int i = 0; i < buff_count; i++){ + + int32 tmp_focus = 0; + int tmp_buffslot = -1; + + int buff_count = GetMaxTotalSlots(); + for(int i = 0; i < buff_count; i++) { + + if((IsValidSpell(buffs[i].spellid) && IsEffectInSpell(buffs[i].spellid, effect))){ + + int32 focus = caster->CalcFocusEffect(type, buffs[i].spellid, spell_id); + + if (!focus) + continue; + + if (tmp_focus && focus > tmp_focus){ + tmp_focus = focus; + tmp_buffslot = i; + } + + else if (!tmp_focus){ + tmp_focus = focus; + tmp_buffslot = i; + } + } + } + + value = tmp_focus; + + if (tmp_buffslot >= 0) + CheckNumHitsRemaining(7, tmp_buffslot); + } + + } + return value; +} + int32 Mob::ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard) { // 9-17-12: This is likely causing crashes, disabled till can resolve.