Core/Auras: Implemented SPELL_AURA_SCHOOL_ABSORB_OVERKILL

Port From (https://github.com/TrinityCore/TrinityCore/commit/530631e0a73c0bcd540f063cef975ecd827307b2)
This commit is contained in:
hondacrx
2021-04-19 10:36:03 -04:00
parent c925d7af40
commit 3ac625e8ff
3 changed files with 67 additions and 15 deletions
+61 -5
View File
@@ -1125,15 +1125,68 @@ namespace Game.Entities
victim.ToCreature().LowerPlayerDamageReq(health < damage ? health : damage); victim.ToCreature().LowerPlayerDamageReq(health < damage ? health : damage);
} }
bool killed = false;
bool skipSettingDeathState = false;
if (health <= damage) if (health <= damage)
{ {
killed = true;
Log.outDebug(LogFilter.Unit, "DealDamage: victim just died"); Log.outDebug(LogFilter.Unit, "DealDamage: victim just died");
if (victim.IsTypeId(TypeId.Player) && victim != this) if (victim.IsTypeId(TypeId.Player) && victim != this)
victim.ToPlayer().UpdateCriteria(CriteriaTypes.TotalDamageReceived, health); victim.ToPlayer().UpdateCriteria(CriteriaTypes.TotalDamageReceived, health);
Kill(victim, durabilityLoss); if (damagetype != DamageEffectType.NoDamage && damagetype != DamageEffectType.Self && victim.HasAuraType(AuraType.SchoolAbsorbOverkill))
{
var vAbsorbOverkill = victim.GetAuraEffectsByType(AuraType.SchoolAbsorbOverkill);
DamageInfo damageInfo = new(this, victim, damage, spellProto, damageSchoolMask, damagetype, cleanDamage != null ? cleanDamage.attackType : WeaponAttackType.BaseAttack);
foreach (var absorbAurEff in vAbsorbOverkill)
{
Aura baseAura = absorbAurEff.GetBase();
AuraApplication aurApp = baseAura.GetApplicationOfTarget(victim.GetGUID());
if (aurApp == null)
continue;
if ((absorbAurEff.GetMiscValue() & (int)damageInfo.GetSchoolMask()) == 0)
continue;
// cannot absorb over limit
if (damage >= victim.CountPctFromMaxHealth(100 + absorbAurEff.GetMiscValueB()))
continue;
// get amount which can be still absorbed by the aura
int 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;
uint tempAbsorb = (uint)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, ref tempAbsorb, ref deathFullyPrevented);
currentAbsorb = (int)tempAbsorb;
// absorb must be smaller than the damage itself
currentAbsorb = MathFunctions.RoundToInterval(ref currentAbsorb, 0, (int)damageInfo.GetDamage());
damageInfo.AbsorbDamage((uint)currentAbsorb);
if (deathFullyPrevented)
killed = false;
skipSettingDeathState = true;
}
damage = damageInfo.GetDamage();
}
} }
if (killed)
Kill(victim, durabilityLoss, skipSettingDeathState);
else else
{ {
Log.outDebug(LogFilter.Unit, "DealDamageAlive"); Log.outDebug(LogFilter.Unit, "DealDamageAlive");
@@ -1484,7 +1537,7 @@ namespace Game.Entities
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange()); Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
} }
public void Kill(Unit victim, bool durabilityLoss = true) public void Kill(Unit victim, bool durabilityLoss = true, bool skipSettingDeathState = false)
{ {
// Prevent killing unit twice (and giving reward from kill twice) // Prevent killing unit twice (and giving reward from kill twice)
if (victim.GetHealth() == 0) if (victim.GetHealth() == 0)
@@ -1599,8 +1652,11 @@ namespace Game.Entities
if (player != null) if (player != null)
player.UpdateCriteria(CriteriaTypes.GetKillingBlows, 1, 0, 0, victim); player.UpdateCriteria(CriteriaTypes.GetKillingBlows, 1, 0, 0, victim);
Log.outDebug(LogFilter.Unit, "SET JUST_DIED"); if (!skipSettingDeathState)
victim.SetDeathState(DeathState.JustDied); {
Log.outDebug(LogFilter.Unit, "SET JUST_DIED");
victim.SetDeathState(DeathState.JustDied);
}
// Inform pets (if any) when player kills target) // Inform pets (if any) when player kills target)
// MUST come after victim.setDeathState(JUST_DIED); or pet next target // MUST come after victim.setDeathState(JUST_DIED); or pet next target
@@ -1760,7 +1816,7 @@ namespace Game.Entities
} }
} }
public void KillSelf(bool durabilityLoss = true) { Kill(this, durabilityLoss); } public void KillSelf(bool durabilityLoss = true, bool skipSettingDeathState = false) { Kill(this, durabilityLoss, skipSettingDeathState); }
public virtual float GetBlockPercent(uint attackerLevel) { return 30.0f; } public virtual float GetBlockPercent(uint attackerLevel) { return 30.0f; }
+2 -2
View File
@@ -940,8 +940,8 @@ namespace Game.Scripting
} }
public class EffectAbsorbHandler : EffectBase public class EffectAbsorbHandler : EffectBase
{ {
public EffectAbsorbHandler(AuraEffectAbsorbDelegate _pEffectHandlerScript, byte _effIndex) public EffectAbsorbHandler(AuraEffectAbsorbDelegate _pEffectHandlerScript, byte _effIndex, bool overKill = false)
: base(_effIndex, AuraType.SchoolAbsorb) : base(_effIndex, overKill ? AuraType.SchoolAbsorbOverkill : AuraType.SchoolAbsorb)
{ {
pEffectHandlerScript = _pEffectHandlerScript; pEffectHandlerScript = _pEffectHandlerScript;
} }
+4 -8
View File
@@ -615,19 +615,15 @@ namespace Scripts.Spells.Priest
void HandleAbsorb(AuraEffect aurEff, DamageInfo dmgInfo, ref uint absorbAmount) void HandleAbsorb(AuraEffect aurEff, DamageInfo dmgInfo, ref uint absorbAmount)
{ {
Unit target = GetTarget(); Unit target = GetTarget();
if (dmgInfo.GetDamage() >= target.GetHealth()) target.CastSpell(target, SpellIds.SpiritOfRedemption, new CastSpellExtraArgs(aurEff));
{ target.SetFullHealth();
target.CastSpell(target, SpellIds.SpiritOfRedemption, new CastSpellExtraArgs(aurEff));
target.SetFullHealth();
return;
}
PreventDefaultAction(); absorbAmount = dmgInfo.GetDamage();
} }
public override void Register() public override void Register()
{ {
OnEffectAbsorb.Add(new EffectAbsorbHandler(HandleAbsorb, 0)); OnEffectAbsorb.Add(new EffectAbsorbHandler(HandleAbsorb, 0, true));
} }
} }