fix(Scripts/ZulGurub): Mandokir's Threatening Gaze. (#12095)

* fix(Scripts/ZulGurub: Mandokir's Threatening Gaze.

Boss can melee attack while casting.
Boss charges after the debuff run out.
Guillotine is casted on hit rather than on launch.
Properly coded Threatening Gaze Charge (with dot/hot exceptions)
Whirlwind is removed during charge.
Fixes #11748

* Update

* missing

* Update

* Update.

* Update.

* Update.

* Update.

* Update.
This commit is contained in:
UltraNix
2022-06-26 09:50:50 +02:00
committed by GitHub
parent 255c5d8b72
commit ea24a7b231
9 changed files with 166 additions and 23 deletions

View File

@@ -80,7 +80,8 @@ enum Misc
MODEL_OHGAN_MOUNT = 15271,
PATH_MANDOKIR = 492861,
POINT_MANDOKIR_END = 24,
CHAINED_SPIRIT_COUNT = 20
CHAINED_SPIRIT_COUNT = 20,
ACTION_CHARGE = 1
};
Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] =
@@ -169,6 +170,7 @@ public:
me->Mount(MODEL_OHGAN_MOUNT);
reviveGUID.Clear();
_useExecute = false;
_chargeTarget.first.Clear();
}
void JustDied(Unit* /*killer*/) override
@@ -226,9 +228,44 @@ public:
}
}
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
void DoAction(int32 action) override
{
reviveGUID = guid;
if (action == ACTION_START_REVIVE)
{
std::list<Creature*> creatures;
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
if (creatures.empty())
return;
for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr)
{
if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID()))
{
chainedSpirit->AI()->SetGUID(reviveGUID);
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
reviveGUID.Clear();
}
}
}
}
void SetGUID(ObjectGuid const guid, int32 type) override
{
if (type == ACTION_CHARGE)
{
if (_chargeTarget.first == guid && _chargeTarget.second > 0.f)
{
if (Unit* target = ObjectAccessor::GetUnit(*me, _chargeTarget.first))
{
me->RemoveAurasDueToSpell(SPELL_WHIRLWIND);
DoCast(target, SPELL_WATCH_CHARGE, true);
}
}
}
else
{
reviveGUID = guid;
}
}
void MovementInform(uint32 type, uint32 id) override
@@ -244,6 +281,18 @@ public:
}
}
void CalculateThreat(Unit* hatedUnit, float& threat, SpellInfo const* threatSpell) override
{
if (_chargeTarget.first == hatedUnit->GetGUID())
{
// Do not count DOTs/HOTs
if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT))
{
_chargeTarget.second += threat;
}
}
}
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/) override
{
if (doneTo && doneTo == me->GetVictim())
@@ -264,6 +313,43 @@ public:
}
}
void DoMeleeAttackIfReady(bool ignoreCasting)
{
if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
Unit* victim = me->GetVictim();
if (!victim || !victim->IsInWorld())
return;
if (!me->IsWithinMeleeRange(victim))
return;
//Make sure our attack is ready and we aren't currently casting before checking distance
if (me->isAttackReady())
{
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec
if (me->haveOffhandWeapon())
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
me->AttackerStateUpdate(victim, BASE_ATTACK, false, ignoreCasting);
me->resetAttackTimer();
}
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
{
// xinef: delay main hand attack if both will hit at the same time (players code)
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
me->setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
me->AttackerStateUpdate(victim, OFF_ATTACK, false, ignoreCasting);
me->resetAttackTimer(OFF_ATTACK);
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
@@ -299,7 +385,14 @@ public:
}
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
{
if (me->GetCurrentSpellCastTime(SPELL_WATCH) >= 0)
{
DoMeleeAttackIfReady(true);
}
return;
}
while (uint32 eventId = events.ExecuteEvent())
{
@@ -339,6 +432,7 @@ public:
{
DoCast(player, SPELL_WATCH);
Talk(SAY_WATCH, player);
_chargeTarget = std::make_pair(player->GetGUID(), 0.f);
}
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
break;
@@ -393,13 +487,14 @@ public:
}
}
DoMeleeAttackIfReady();
DoMeleeAttackIfReady(false);
}
private:
uint8 killCount;
ObjectGuid reviveGUID;
bool _useExecute;
std::pair<ObjectGuid, float> _chargeTarget;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -614,13 +709,16 @@ public:
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
if (Unit* target = GetTarget())
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
if (Creature* caster = GetCaster()->ToCreature())
{
caster->CastSpell(target, SPELL_WATCH_CHARGE, true);
if (caster->IsAIEnabled)
{
caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
}
}
}
}
@@ -656,6 +754,29 @@ class spell_mandokir_charge : public SpellScript
}
};
class spell_threatening_gaze_charge : public SpellScript
{
PrepareSpellScript(spell_threatening_gaze_charge)
void PreventLaunchHit(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
}
void LaunchHit(SpellEffIndex effIndex)
{
if (Unit* caster = GetCaster())
if (Unit* target = GetHitUnit())
caster->CastSpell(target, GetSpellInfo()->Effects[effIndex].TriggerSpell, true);
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_threatening_gaze_charge::PreventLaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
OnEffectHitTarget += SpellEffectFn(spell_threatening_gaze_charge::LaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
}
};
void AddSC_boss_mandokir()
{
new boss_mandokir();
@@ -664,4 +785,5 @@ void AddSC_boss_mandokir()
RegisterZulGurubCreatureAI(npc_vilebranch_speaker);
new spell_threatening_gaze();
RegisterSpellScript(spell_mandokir_charge);
RegisterSpellScript(spell_threatening_gaze_charge);
}