Heal calculations revised.

This commit is contained in:
KayenEQ 2014-02-07 23:51:28 -05:00
parent a602f70bf4
commit e7a68f3804
14 changed files with 327 additions and 314 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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)
{

View File

@ -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)

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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.