From 84a915e1b1984d5048e33c8028acb15a191d8c05 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 12 Sep 2010 02:38:29 +0400 Subject: [PATCH] [10475] Implement SPELL_AURA_HEAL_ABSORB (301) Used for example in spells 66237 and 70659. Also rename CalculateAbsorbAndResist -> CalculateDamageAbsorbAndResist --- src/game/Level3.cpp | 2 +- src/game/Player.cpp | 4 +- src/game/Spell.cpp | 12 +++++- src/game/SpellAuraDefines.h | 2 +- src/game/SpellAuras.cpp | 17 ++++++--- src/game/SpellEffects.cpp | 17 +++++++-- src/game/Unit.cpp | 75 +++++++++++++++++++++++++++++++++---- src/game/Unit.h | 9 +++-- src/shared/revision_nr.h | 2 +- 9 files changed, 112 insertions(+), 28 deletions(-) diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 44afcfe2d..6b4298bfa 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -3733,7 +3733,7 @@ bool ChatHandler::HandleDamageCommand(char* args) uint32 absorb = 0; uint32 resist = 0; - target->CalculateAbsorbAndResist(m_session->GetPlayer(),schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + target->CalculateDamageAbsorbAndResist(m_session->GetPlayer(),schoolmask, SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); if (damage <= absorb + resist) return true; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index ee961bb49..3d29ebb59 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -948,9 +948,9 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) uint32 absorb = 0; uint32 resist = 0; if (type == DAMAGE_LAVA) - CalculateAbsorbAndResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist); + CalculateDamageAbsorbAndResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist); else if (type == DAMAGE_SLIME) - CalculateAbsorbAndResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist); + CalculateDamageAbsorbAndResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist); damage-=absorb+resist; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 5ce881f66..65d8cbf52 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1010,13 +1010,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) else procEx |= PROC_EX_NORMAL_HIT; + uint32 absorb = 0; + unitTarget->CalculateHealAbsorb(addhealth, &absorb); + addhealth -= absorb; + // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (m_canTrigger && missInfo != SPELL_MISS_REFLECT) { caster->ProcDamageAndSpell(unitTarget, real_caster ? procAttacker : PROC_FLAG_NONE, procVictim, procEx, addhealth, m_attackType, m_spellInfo); } - int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo, crit); + int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo, crit, absorb); if (real_caster) unitTarget->getHostileRefManager().threatAssist(real_caster, float(gain) * 0.5f, m_spellInfo); @@ -3291,7 +3295,11 @@ void Spell::finish(bool ok) // Heal caster for all health leech from all targets if (m_healthLeech) - m_caster->DealHeal(m_caster, uint32(m_healthLeech), m_spellInfo); + { + uint32 absorb = 0; + m_caster->CalculateHealAbsorb(uint32(m_healthLeech), &absorb); + m_caster->DealHeal(m_caster, uint32(m_healthLeech) - absorb, m_spellInfo, false, absorb); + } if (IsMeleeAttackResetSpell()) { diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h index e6ec33c87..8524a73c7 100644 --- a/src/game/SpellAuraDefines.h +++ b/src/game/SpellAuraDefines.h @@ -336,7 +336,7 @@ enum AuraType SPELL_AURA_298 = 298, SPELL_AURA_299 = 299, SPELL_AURA_300 = 300, - SPELL_AURA_301 = 301, + SPELL_AURA_HEAL_ABSORB = 301, SPELL_AURA_302 = 302, SPELL_AURA_303 = 303, SPELL_AURA_304 = 304, diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 36eb94235..7c8a85351 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -351,7 +351,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleUnused, //298 unused (3.2.2a) &Aura::HandleUnused, //299 unused (3.2.2a) &Aura::HandleNULL, //300 3 spells (share damage?) - &Aura::HandleNULL, //301 5 spells + &Aura::HandleNULL, //301 SPELL_AURA_HEAL_ABSORB 5 spells &Aura::HandleUnused, //302 unused (3.2.2a) &Aura::HandleNULL, //303 17 spells &Aura::HandleNULL, //304 2 spells (alcohol effect?) @@ -1153,8 +1153,10 @@ void Aura::TriggerSpell() // case 23184: break; case 23493: // Restoration { - int32 heal = triggerTarget->GetMaxHealth() / 10; - triggerTarget->DealHeal(triggerTarget, heal, auraSpellInfo); + uint32 heal = triggerTarget->GetMaxHealth() / 10; + uint32 absorb = 0; + triggerTarget->CalculateHealAbsorb(heal, &absorb); + triggerTarget->DealHeal(triggerTarget, heal - absorb, auraSpellInfo, false, absorb); if (int32 mana = triggerTarget->GetMaxPower(POWER_MANA)) { @@ -6562,7 +6564,7 @@ void Aura::PeriodicTick() if (pCaster->GetTypeId() == TYPEID_PLAYER) pdamage -= target->GetSpellDamageReduction(pdamage); - target->CalculateAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), DOT, pdamage, &absorb, &resist, !(GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); + target->CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), DOT, pdamage, &absorb, &resist, !(GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u", GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), pdamage, GetId(),absorb); @@ -6651,7 +6653,7 @@ void Aura::PeriodicTick() if (IS_PLAYER_GUID(GetCasterGUID())) pdamage -= target->GetSpellDamageReduction(pdamage); - target->CalculateAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), DOT, pdamage, &absorb, &resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); + target->CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), DOT, pdamage, &absorb, &resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); if(target->GetHealth() < pdamage) pdamage = uint32(target->GetHealth()); @@ -6686,7 +6688,10 @@ void Aura::PeriodicTick() int32 heal = pCaster->SpellHealingBonusTaken(pCaster, spellProto, int32(new_damage * multiplier), DOT, GetStackAmount()); - int32 gain = pCaster->DealHeal(pCaster, heal, spellProto); + uint32 absorbHeal = 0; + pCaster->CalculateHealAbsorb(heal, &absorbHeal); + + int32 gain = pCaster->DealHeal(pCaster, heal, spellProto, false, absorbHeal); pCaster->getHostileRefManager().threatAssist(pCaster, gain * 0.5f, spellProto); break; } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 1dd2f28e2..e14e5a4c1 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -285,7 +285,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffectIndex eff_idx) // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc damage = m_spellInfo->CalculateSimpleValue(eff_idx); - m_caster->CalculateAbsorbAndResist(m_caster, GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); + m_caster->CalculateDamageAbsorbAndResist(m_caster, GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false); if(m_caster->GetTypeId() == TYPEID_PLAYER) @@ -3309,7 +3309,10 @@ void Spell::EffectHealPct(SpellEffectIndex /*eff_idx*/) addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL); addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL); - int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo); + uint32 absorb = 0; + unitTarget->CalculateHealAbsorb(addhealth, &absorb); + + int32 gain = caster->DealHeal(unitTarget, addhealth - absorb, m_spellInfo, false, absorb); unitTarget->getHostileRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo); } } @@ -3327,7 +3330,10 @@ void Spell::EffectHealMechanical(SpellEffectIndex /*eff_idx*/) uint32 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, damage, HEAL); addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL); - caster->DealHeal(unitTarget, addhealth, m_spellInfo); + uint32 absorb = 0; + unitTarget->CalculateHealAbsorb(addhealth, &absorb); + + caster->DealHeal(unitTarget, addhealth, m_spellInfo, false, absorb); } } @@ -3358,7 +3364,10 @@ void Spell::EffectHealthLeech(SpellEffectIndex eff_idx) { heal = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, heal, HEAL); - m_caster->DealHeal(m_caster, heal, m_spellInfo); + uint32 absorb = 0; + m_caster->CalculateHealAbsorb(heal, &absorb); + + m_caster->DealHeal(m_caster, heal - absorb, m_spellInfo, false, absorb); } } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 0a4958273..1865e8eb0 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -1584,7 +1584,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da // Calculate absorb & resists uint32 absorb_affected_damage = CalcNotIgnoreAbsorbDamage(damageInfo->damage,damageInfo->damageSchoolMask); - damageInfo->target->CalculateAbsorbAndResist(this, damageInfo->damageSchoolMask, DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, true); + damageInfo->target->CalculateDamageAbsorbAndResist(this, damageInfo->damageSchoolMask, DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, true); damageInfo->damage-=damageInfo->absorb + damageInfo->resist; if (damageInfo->absorb) { @@ -1822,7 +1822,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) return (newdamage > 1) ? newdamage : 1; } -void Unit::CalculateAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, bool canReflect) +void Unit::CalculateDamageAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, bool canReflect) { if(!pCaster || !isAlive() || !damage) return; @@ -2354,10 +2354,71 @@ void Unit::CalculateAbsorbResistBlock(Unit *pCaster, SpellNonMeleeDamage *damage } uint32 absorb_affected_damage = pCaster->CalcNotIgnoreAbsorbDamage(damageInfo->damage,GetSpellSchoolMask(spellProto),spellProto); - CalculateAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); + CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED)); damageInfo->damage-= damageInfo->absorb + damageInfo->resist; } +void Unit::CalculateHealAbsorb(const uint32 heal, uint32 *absorb) +{ + if (!isAlive() || !heal) + return; + + int32 RemainingHeal = heal; + + // Need remove expired auras after + bool existExpired = false; + + // absorb + AuraList const& vHealAbsorb = GetAurasByType(SPELL_AURA_HEAL_ABSORB); + for(AuraList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i) + { + Modifier* mod = (*i)->GetModifier(); + SpellEntry const* spellProto = (*i)->GetSpellProto(); + + // Max Amount can be absorbed by this aura + int32 currentAbsorb = mod->m_amount; + + // Found empty aura (impossible but..) + if (currentAbsorb <=0) + { + existExpired = true; + continue; + } + + // currentAbsorb - heal can be absorbed + // If need absorb less heal + if (RemainingHeal < currentAbsorb) + currentAbsorb = RemainingHeal; + + RemainingHeal -= currentAbsorb; + + // Reduce aura amount + mod->m_amount -= currentAbsorb; + if ((*i)->GetHolder()->DropAuraCharge()) + mod->m_amount = 0; + // Need remove it later + if (mod->m_amount<=0) + existExpired = true; + } + + // Remove all expired absorb auras + if (existExpired) + { + for(AuraList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();) + { + if ((*i)->GetModifier()->m_amount<=0) + { + RemoveAurasDueToSpell((*i)->GetId(), NULL, AURA_REMOVE_BY_SHIELD_BREAK); + i = vHealAbsorb.begin(); + } + else + ++i; + } + } + + *absorb = heal - RemainingHeal; +} + void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) { if(hasUnitState(UNIT_STAT_CAN_NOT_REACT) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) @@ -5866,7 +5927,7 @@ void Unit::UnsummonAllTotems() totem->UnSummon(); } -int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical) +int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical, uint32 absorb) { int32 gain = pVictim->ModifyHealth(int32(addhealth)); @@ -5878,7 +5939,7 @@ int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellPro if (unit->GetTypeId()==TYPEID_PLAYER) { // overheal = addhealth - gain - unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical); + unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical, absorb); if (BattleGround *bg = ((Player*)unit)->GetBattleGround()) bg->UpdatePlayerScore((Player*)unit, SCORE_HEALING_DONE, gain); @@ -5927,7 +5988,7 @@ Unit* Unit::SelectMagnetTarget(Unit *victim, SpellEntry const *spellInfo) return victim; } -void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical) +void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical, uint32 absorb) { // we guess size WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+1)); @@ -5936,7 +5997,7 @@ void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, uint32 data << uint32(SpellID); data << uint32(Damage); data << uint32(OverHeal); - data << uint32(0); // absorb, not implemented, look 301 aura + data << uint32(absorb); data << uint8(critical ? 1 : 0); data << uint8(0); // unused in client? SendMessageToSet(&data, true); diff --git a/src/game/Unit.h b/src/game/Unit.h index 828b37bde..5bb6aaa7d 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -342,7 +342,7 @@ enum AuraRemoveMode AURA_REMOVE_BY_DISPEL, AURA_REMOVE_BY_DEATH, AURA_REMOVE_BY_DELETE, // use for speedup and prevent unexpected effects at player logout/pet unsummon (must be used _only_ after save), delete. - AURA_REMOVE_BY_SHIELD_BREAK, // when absorb shield is removed by damage + AURA_REMOVE_BY_SHIELD_BREAK, // when absorb shield is removed by damage, heal absorb debuf AURA_REMOVE_BY_EXPIRE, // at duration end }; @@ -1275,7 +1275,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } void DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb); uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss); - int32 DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical = false); + int32 DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical = false, uint32 absorb = 0); void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL); void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage ); @@ -1398,7 +1398,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject virtual bool IsUnderWater() const; bool isInAccessablePlaceFor(Creature const* c) const; - void SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical = false); + void SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, uint32 OverHeal, bool critical = false, uint32 absorb = 0); void SendEnergizeSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage,Powers powertype); void EnergizeBySpell(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers powertype); uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage); @@ -1824,8 +1824,9 @@ class MANGOS_DLL_SPEC Unit : public WorldObject // redefined in Creature uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage); - void CalculateAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, bool canReflect = false); + void CalculateDamageAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, bool canReflect = false); void CalculateAbsorbResistBlock(Unit *pCaster, SpellNonMeleeDamage *damageInfo, SpellEntry const* spellProto, WeaponAttackType attType = BASE_ATTACK); + void CalculateHealAbsorb(uint32 heal, uint32 *absorb); void UpdateWalkMode(Unit* source, bool self = true); void UpdateSpeed(UnitMoveType mtype, bool forced, float ratio = 1.0f); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index cfc80758e..38df54c50 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10474" + #define REVISION_NR "10475" #endif // __REVISION_NR_H__