Scripts/Spells: Implemented monk stagger (#26295)

This commit is contained in:
Matan Shukry
2021-04-22 23:45:26 +03:00
committed by GitHub
parent 60df74933f
commit c99f93d53d
2 changed files with 238 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
-- Stagger
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_monk_stagger', 'spell_monk_stagger_damage_aura', 'spell_monk_stagger_debuff_aura');
INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
(115069, 'spell_monk_stagger'),
(124255, 'spell_monk_stagger_damage_aura'),
(124273, 'spell_monk_stagger_debuff_aura'),
(124274, 'spell_monk_stagger_debuff_aura'),
(124275, 'spell_monk_stagger_debuff_aura');

View File

@@ -21,6 +21,7 @@
*/
#include "ScriptMgr.h"
#include "DB2Stores.h"
#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
@@ -38,6 +39,10 @@ enum MonkSpells
SPELL_MONK_PROVOKE_AOE = 118635,
SPELL_MONK_SOOTHING_MIST = 115175,
SPELL_MONK_STANCE_OF_THE_SPIRITED_CRANE = 154436,
SPELL_MONK_STAGGER_DAMAGE_AURA = 124255,
SPELL_MONK_STAGGER_HEAVY = 124273,
SPELL_MONK_STAGGER_LIGHT = 124275,
SPELL_MONK_STAGGER_MODERATE = 124274,
SPELL_MONK_SURGING_MIST_HEAL = 116995,
};
@@ -159,9 +164,234 @@ class spell_monk_provoke : public SpellScript
}
};
// Utility for stagger scripts
Aura* FindExistingStaggerEffect(Unit* unit)
{
if (Aura* auraLight = unit->GetAura(SPELL_MONK_STAGGER_LIGHT))
return auraLight;
if (Aura* auraModerate = unit->GetAura(SPELL_MONK_STAGGER_MODERATE))
return auraModerate;
if (Aura* auraHeavy = unit->GetAura(SPELL_MONK_STAGGER_HEAVY))
return auraHeavy;
return nullptr;
}
static constexpr SpellEffIndex AuraStaggerEffectTick = EFFECT_0;
static constexpr SpellEffIndex AuraStaggerEffectTotal = EFFECT_1;
// 115069 - Stagger
class spell_monk_stagger : public AuraScript
{
PrepareAuraScript(spell_monk_stagger);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MONK_STAGGER_LIGHT, SPELL_MONK_STAGGER_MODERATE, SPELL_MONK_STAGGER_HEAVY });
}
void AbsorbNormal(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& /*absorbAmount*/)
{
Absorb(dmgInfo, 1.0f);
}
void AbsorbMagic(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& /*absorbAmount*/)
{
AuraEffect const* effect = GetEffect(EFFECT_4);
if (!effect)
return;
Absorb(dmgInfo, float(effect->GetAmount()) / 100.0f);
}
void Absorb(DamageInfo& dmgInfo, float multiplier)
{
// Prevent default action (which would remove the aura)
PreventDefaultAction();
// make sure damage doesn't come from stagger damage spell SPELL_MONK_STAGGER_DAMAGE_AURA
if (SpellInfo const* dmgSpellInfo = dmgInfo.GetSpellInfo())
if (dmgSpellInfo->Id == SPELL_MONK_STAGGER_DAMAGE_AURA)
return;
AuraEffect const* effect = GetEffect(AuraStaggerEffectTick);
if (!effect)
return;
Unit* target = GetTarget();
float agility = target->GetStat(STAT_AGILITY);
float base = CalculatePct(agility, float(effect->GetAmount()));
float K = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, target->getLevel(), -2, 0, Classes(target->getClass()));
float newAmount = (base / (base + K));
newAmount *= multiplier;
// Absorb X percentage of the damage
float absorbAmount = float(dmgInfo.GetDamage()) * newAmount;
if (absorbAmount > 0)
{
dmgInfo.AbsorbDamage(absorbAmount);
// Cast stagger and make it tick on each tick
AddAndRefreshStagger(absorbAmount);
}
}
void Register() override
{
OnEffectAbsorb += AuraEffectAbsorbFn(spell_monk_stagger::AbsorbNormal, EFFECT_1);
OnEffectAbsorb += AuraEffectAbsorbFn(spell_monk_stagger::AbsorbMagic, EFFECT_2);
}
private:
void AddAndRefreshStagger(float amount)
{
Unit* target = GetTarget();
if (Aura* auraStagger = FindExistingStaggerEffect(target))
{
AuraEffect* effStaggerRemaining = auraStagger->GetEffect(AuraStaggerEffectTotal);
if (!effStaggerRemaining)
return;
float newAmount = effStaggerRemaining->GetAmount() + amount;
uint32 spellId = GetStaggerSpellId(target, newAmount);
if (spellId == effStaggerRemaining->GetSpellInfo()->Id)
{
auraStagger->RefreshDuration();
effStaggerRemaining->ChangeAmount(newAmount, false, true /* reapply */);
}
else
{
// amount changed the stagger type so we need to change the stagger amount (e.g. from medium to light)
GetTarget()->RemoveAura(auraStagger);
AddNewStagger(target, spellId, newAmount);
}
}
else
AddNewStagger(target, GetStaggerSpellId(target, amount), amount);
}
uint32 GetStaggerSpellId(Unit* unit, float amount)
{
const float StaggerHeavy = 0.6f;
const float StaggerModerate = 0.3f;
float staggerPct = amount / float(unit->GetMaxHealth());
return (staggerPct >= StaggerHeavy) ? SPELL_MONK_STAGGER_HEAVY :
(staggerPct >= StaggerModerate) ? SPELL_MONK_STAGGER_MODERATE :
SPELL_MONK_STAGGER_LIGHT;
}
void AddNewStagger(Unit* unit, uint32 staggerSpellId, float staggerAmount)
{
// We only set the total stagger amount. The amount per tick will be set by the stagger spell script
unit->CastSpell(unit, staggerSpellId, CastSpellExtraArgs(SPELLVALUE_BASE_POINT1, staggerAmount).SetTriggerFlags(TRIGGERED_FULL_MASK));
}
};
// 124255 - Stagger - SPELL_MONK_STAGGER_DAMAGE_AURA
class spell_monk_stagger_damage_aura : public AuraScript
{
PrepareAuraScript(spell_monk_stagger_damage_aura);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MONK_STAGGER_LIGHT, SPELL_MONK_STAGGER_MODERATE, SPELL_MONK_STAGGER_HEAVY });
}
void OnPeriodicDamage(AuraEffect const* aurEff)
{
// Update our light/medium/heavy stagger with the correct stagger amount left
if (Aura* auraStagger = FindExistingStaggerEffect(GetTarget()))
{
if (AuraEffect* auraEff = auraStagger->GetEffect(AuraStaggerEffectTotal))
{
float total = float(auraEff->GetAmount());
float tickDamage = float(aurEff->GetDamage());
auraEff->ChangeAmount(total - tickDamage);
}
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_monk_stagger_damage_aura::OnPeriodicDamage, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
}
};
// 124273, 124274, 124275 - Light/Moderate/Heavy Stagger - SPELL_MONK_STAGGER_LIGHT / SPELL_MONK_STAGGER_MODERATE / SPELL_MONK_STAGGER_HEAVY
class spell_monk_stagger_debuff_aura : public AuraScript
{
PrepareAuraScript(spell_monk_stagger_debuff_aura);
bool Load() override
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_MONK_STAGGER_DAMAGE_AURA, GetCastDifficulty());
SpellEffectInfo const* effInfo = !spellInfo ? nullptr : spellInfo->GetEffect(EFFECT_0);
if (!effInfo)
return false;
_period = float(effInfo->ApplyAuraPeriod);
return true;
}
void OnReapply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
// Calculate damage per tick
float total = float(aurEff->GetAmount());
float perTick = total * _period / float(GetDuration()); // should be same as GetMaxDuration() TODO: verify
// Set amount on effect for tooltip
AuraEffect* effInfo = GetAura()->GetEffect(AuraStaggerEffectTick);
if (effInfo)
effInfo->ChangeAmount(perTick);
// Set amount on damage aura (or cast it if needed)
CastOrChangeTickDamage(perTick);
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes mode)
{
if (mode != AURA_EFFECT_HANDLE_REAL)
return;
// Remove damage aura
GetTarget()->RemoveAura(SPELL_MONK_STAGGER_DAMAGE_AURA);
}
void Register() override
{
AfterEffectApply += AuraEffectRemoveFn(spell_monk_stagger_debuff_aura::OnReapply, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
AfterEffectRemove += AuraEffectRemoveFn(spell_monk_stagger_debuff_aura::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
private:
float _period = 0.0f;
void CastOrChangeTickDamage(float tickDamage)
{
Unit* unit = GetTarget();
Aura* auraDamage = unit->GetAura(SPELL_MONK_STAGGER_DAMAGE_AURA);
if (!auraDamage)
{
unit->CastSpell(unit, SPELL_MONK_STAGGER_DAMAGE_AURA, true);
auraDamage = unit->GetAura(SPELL_MONK_STAGGER_DAMAGE_AURA);
}
if (auraDamage)
if (AuraEffect* eff = auraDamage->GetEffect(AuraStaggerEffectTick))
eff->SetDamage(tickDamage);
}
};
void AddSC_monk_spell_scripts()
{
RegisterAuraScript(spell_monk_crackling_jade_lightning);
RegisterAuraScript(spell_monk_crackling_jade_lightning_knockback_proc_aura);
RegisterSpellScript(spell_monk_provoke);
RegisterAuraScript(spell_monk_stagger);
RegisterAuraScript(spell_monk_stagger_damage_aura);
RegisterAuraScript(spell_monk_stagger_debuff_aura);
}