diff options
author | Matan Shukry <matanshukry@gmail.com> | 2021-04-17 23:42:34 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-17 22:42:34 +0200 |
commit | 530631e0a73c0bcd540f063cef975ecd827307b2 (patch) | |
tree | 6c80c5495198ed256a10d9a3ee9ce2acbea8637c | |
parent | 5b4f61d915475e44369430994cb636d14c2976b8 (diff) |
Core/Auras: Implemented SPELL_AURA_SCHOOL_ABSORB_OVERKILL (#26269)
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 64 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 5 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.h | 5 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_priest.cpp | 14 |
7 files changed, 75 insertions, 20 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a1143318983..20b4957e604 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -866,15 +866,68 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage); } + bool killed = false; + bool skipSettingDeathState = false; + if (health <= damage) { + killed = true; + TC_LOG_DEBUG("entities.unit", "DealDamage: victim just died"); if (victim->GetTypeId() == TYPEID_PLAYER && victim != this) victim->ToPlayer()->UpdateCriteria(CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health); - Kill(victim, durabilityLoss); + if (damagetype != NODAMAGE && damagetype != SELF_DAMAGE && victim->HasAuraType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL)) + { + AuraEffectList vAbsorbOverkill = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL); + DamageInfo damageInfo = DamageInfo(this, victim, damage, spellProto, damageSchoolMask, damagetype, + cleanDamage ? cleanDamage->attackType : BASE_ATTACK); + for (AuraEffect* absorbAurEff : vAbsorbOverkill) + { + Aura* base = absorbAurEff->GetBase(); + AuraApplication const* aurApp = base->GetApplicationOfTarget(victim->GetGUID()); + if (!aurApp) + continue; + + if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask())) + continue; + + // cannot absorb over limit + if (damage >= victim->CountPctFromMaxHealth(100 + absorbAurEff->GetMiscValueB())) + continue; + + // get amount which can be still absorbed by the aura + int32 currentAbsorb = absorbAurEff->GetAmount(); + // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety + if (currentAbsorb < 0) + currentAbsorb = 0; + + uint32 tempAbsorb = uint32(currentAbsorb); + + // This aura type is used both by Spirit of Redemption (death not really prevented, must grant all credit immediately) and Cheat Death (death prevented) + // repurpose PreventDefaultAction for this + bool deathFullyPrevented = false; + + absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, deathFullyPrevented); + currentAbsorb = tempAbsorb; + + // absorb must be smaller than the damage itself + currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage())); + damageInfo.AbsorbDamage(currentAbsorb); + + if (deathFullyPrevented) + killed = false; + + skipSettingDeathState = true; + } + + damage = damageInfo.GetDamage(); + } } + + if (killed) + Kill(victim, durabilityLoss, skipSettingDeathState); else { TC_LOG_DEBUG("entities.unit", "DealDamageAlive"); @@ -11471,7 +11524,7 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId) SendMessageToSet(data.Write(), true); } -void Unit::Kill(Unit* victim, bool durabilityLoss) +void Unit::Kill(Unit* victim, bool durabilityLoss /*= true*/, bool skipSettingDeathState /*= false*/) { // Prevent killing unit twice (and giving reward from kill twice) if (!victim->GetHealth()) @@ -11586,8 +11639,11 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) if (Player* killerPlayer = GetCharmerOrOwnerPlayerOrPlayerItself()) killerPlayer->UpdateCriteria(CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, 0, victim); - TC_LOG_DEBUG("entities.unit", "SET JUST_DIED"); - victim->setDeathState(JUST_DIED); + if (!skipSettingDeathState) + { + TC_LOG_DEBUG("entities.unit", "SET JUST_DIED"); + victim->setDeathState(JUST_DIED); + } // Inform pets (if any) when player kills target) // MUST come after victim->setDeathState(JUST_DIED); or pet next target diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 92da6ccbb20..6af545a36a3 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1043,8 +1043,8 @@ class TC_GAME_API Unit : public WorldObject uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? GetLevelForTarget(target) : getLevel()) * 5; } void DealDamageMods(Unit const* victim, uint32 &damage, uint32* absorb) const; uint32 DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true); - void Kill(Unit* victim, bool durabilityLoss = true); - void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); } + void Kill(Unit* victim, bool durabilityLoss = true, bool skipSettingDeathState = false); + void KillSelf(bool durabilityLoss = true, bool skipSettingDeathState = false) { Kill(this, durabilityLoss, skipSettingDeathState); } void DealHeal(HealInfo& healInfo); void ProcSkillsAndAuras(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, @@ -1414,6 +1414,7 @@ class TC_GAME_API Unit : public WorldObject void _ApplyAllAuraStatMods(); AuraEffectList const& GetAuraEffectsByType(AuraType type) const { return m_modAuras[type]; } + AuraEffectList& GetAuraEffectsByType(AuraType type) { return m_modAuras[type]; } AuraList & GetSingleCastAuras() { return m_scAuras; } AuraList const& GetSingleCastAuras() const { return m_scAuras; } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index cf5ed8a765d..786af2bf428 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -383,7 +383,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //313 SPELL_AURA_MOUNT_ANIM_REPLACEMENT_SET implemented clientside &AuraEffect::HandlePreventResurrection, //314 SPELL_AURA_PREVENT_RESURRECTION todo &AuraEffect::HandleNoImmediateEffect, //315 SPELL_AURA_UNDERWATER_WALKING todo - &AuraEffect::HandleNULL, //316 SPELL_AURA_SCHOOL_ABSORB_OVERKILL + &AuraEffect::HandleNoImmediateEffect, //316 SPELL_AURA_SCHOOL_ABSORB_OVERKILL implemented in Unit::DealDamage() &AuraEffect::HandleNULL, //317 SPELL_AURA_MOD_SPELL_POWER_PCT &AuraEffect::HandleMastery, //318 SPELL_AURA_MASTERY &AuraEffect::HandleModMeleeSpeedPct, //319 SPELL_AURA_MOD_MELEE_HASTE_3 diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 12e9547b4d6..8f5f1eb2efb 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -309,6 +309,7 @@ class TC_GAME_API AuraEffect void HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleAbsorbOverkill(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleMastery(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 62b57b3a36a..12337bd0c67 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -928,8 +928,8 @@ void AuraScript::EffectApplyHandler::Call(AuraScript* auraScript, AuraEffect con (auraScript->*pEffectHandlerScript)(_aurEff, _mode); } -AuraScript::EffectAbsorbHandler::EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) - : AuraScript::EffectBase(_effIndex, SPELL_AURA_SCHOOL_ABSORB) +AuraScript::EffectAbsorbHandler::EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex, bool overKill) + : AuraScript::EffectBase(_effIndex, overKill ? SPELL_AURA_SCHOOL_ABSORB_OVERKILL : SPELL_AURA_SCHOOL_ABSORB) { pEffectHandlerScript = _pEffectHandlerScript; } diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index efda8bc4d3d..7325f75b3f6 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -654,7 +654,7 @@ class TC_GAME_API AuraScript : public _SpellScript class TC_GAME_API EffectAbsorbHandler : public EffectBase { public: - EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex); + EffectAbsorbHandler(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex, bool overKill); void Call(AuraScript* auraScript, AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount); private: AuraEffectAbsorbFnType pEffectHandlerScript; @@ -726,7 +726,7 @@ class TC_GAME_API AuraScript : public _SpellScript class EffectCalcSpellModHandlerFunction : public AuraScript::EffectCalcSpellModHandler { public: EffectCalcSpellModHandlerFunction(AuraEffectCalcSpellModFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName) : AuraScript::EffectCalcSpellModHandler((AuraScript::AuraEffectCalcSpellModFnType)_pEffectHandlerScript, _effIndex, _effName) { } }; \ class EffectCalcCritChanceHandlerFunction : public AuraScript::EffectCalcCritChanceHandler { public: EffectCalcCritChanceHandlerFunction(AuraEffectCalcCritChanceFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectCalcCritChanceHandler((AuraScript::AuraEffectCalcCritChanceFnType)effectHandlerScript, effIndex, effName) { } }; \ class EffectApplyHandlerFunction : public AuraScript::EffectApplyHandler { public: EffectApplyHandlerFunction(AuraEffectApplicationModeFnType _pEffectHandlerScript, uint8 _effIndex, uint16 _effName, AuraEffectHandleModes _mode) : AuraScript::EffectApplyHandler((AuraScript::AuraEffectApplicationModeFnType)_pEffectHandlerScript, _effIndex, _effName, _mode) { } }; \ - class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) { } }; \ + class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex, bool overkill = false) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex, overkill) { } }; \ class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) { } }; \ class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) { } }; \ class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) { } }; \ @@ -847,6 +847,7 @@ class TC_GAME_API AuraScript : public _SpellScript // where function is: void function (AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount); HookList<EffectAbsorbHandler> OnEffectAbsorb; #define AuraEffectAbsorbFn(F, I) EffectAbsorbFunction(&F, I) + #define AuraEffectAbsorbOverkillFn(F, I) EffectAbsorbFunction(&F, I, true) // executed after absorb aura effect reduced damage to target - absorbAmount is real amount absorbed by aura // example: AfterEffectAbsorb += AuraEffectAbsorbFn(class::function, EffectIndexSpecifier); diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 7e377f496a8..8a0995098af 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -759,22 +759,18 @@ class spell_priest_spirit_of_redemption : public AuraScript return ValidateSpellInfo({ SPELL_PRIEST_SPIRIT_OF_REDEMPTION }); } - void HandleAbsorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& /*absorbAmount*/) + void HandleAbsorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) { Unit* target = GetTarget(); - if (dmgInfo.GetDamage() >= target->GetHealth()) - { - target->CastSpell(target, SPELL_PRIEST_SPIRIT_OF_REDEMPTION, aurEff); - target->SetFullHealth(); - return; - } + target->CastSpell(target, SPELL_PRIEST_SPIRIT_OF_REDEMPTION, aurEff); + target->SetFullHealth(); - PreventDefaultAction(); + absorbAmount = dmgInfo.GetDamage(); } void Register() override { - OnEffectAbsorb += AuraEffectAbsorbFn(spell_priest_spirit_of_redemption::HandleAbsorb, EFFECT_0); + OnEffectAbsorb += AuraEffectAbsorbOverkillFn(spell_priest_spirit_of_redemption::HandleAbsorb, EFFECT_0); } }; |