Core/Auras: Implemented SPELL_AURA_SCHOOL_ABSORB_OVERKILL (#26269)

This commit is contained in:
Matan Shukry
2021-04-17 23:42:34 +03:00
committed by GitHub
parent 5b4f61d915
commit 530631e0a7
7 changed files with 75 additions and 20 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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