fix(Core/ZulGurub): Mandokir charge and chained spirits (#12072)

* fix(Core/ZulGurub): Mandokir charge and chained spirits

* build

* properly script threatening gaze

* refactor vilebranch speaker script

* remove useless trigger spell for Frightening Shout

* blank spaces

* build...

* sadly you can cheese threatening gaze

* revert threatening gaze part

* style

* charge should target the farthest one

* revert last thing of threatening gaze

* mod charge
This commit is contained in:
Nefertumm
2022-06-19 08:50:52 -03:00
committed by GitHub
parent 1bb343c847
commit 2db5f9a231
3 changed files with 124 additions and 128 deletions
@@ -0,0 +1,4 @@
--
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_mandokir_charge';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(24408, 'spell_mandokir_charge');
@@ -1369,6 +1369,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST; spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST;
}); });
// Frightening Shout
ApplySpellFix({ 19134 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_DUMMY;
});
// Isle of Conquest // Isle of Conquest
ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo) ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
{ {
@@ -47,6 +47,7 @@ enum Spells
SPELL_LEVEL_UP = 24312, SPELL_LEVEL_UP = 24312,
SPELL_EXECUTE = 7160, SPELL_EXECUTE = 7160,
SPELL_MANDOKIR_CLEAVE = 20691, SPELL_MANDOKIR_CLEAVE = 20691,
SPELL_SUMMON_PLAYER = 25104,
SPELL_REVIVE = 24341 // chained spirit SPELL_REVIVE = 24341 // chained spirit
}; };
@@ -63,8 +64,7 @@ enum Events
EVENT_WATCH_PLAYER = 8, EVENT_WATCH_PLAYER = 8,
EVENT_CHARGE_PLAYER = 9, EVENT_CHARGE_PLAYER = 9,
EVENT_EXECUTE = 10, EVENT_EXECUTE = 10,
EVENT_FRIGHTENING_SHOUT = 11, EVENT_CLEAVE = 11
EVENT_CLEAVE = 12
}; };
enum Action enum Action
@@ -113,6 +113,32 @@ Position const PosMandokir[2] =
{ -12197.86f, -1949.392f, 130.2745f, 0.0f } { -12197.86f, -1949.392f, 130.2745f, 0.0f }
}; };
void RevivePlayer(Unit* victim, ObjectGuid& reviveGUID)
{
std::list<Creature*> chainedSpirits;
GetCreatureListWithEntryInGrid(chainedSpirits, victim, NPC_CHAINED_SPIRIT, 200.f);
if (chainedSpirits.empty())
return;
// Sort the list by distance to the victim.
chainedSpirits.sort([victim](Creature const* c1, Creature const* c2)
{
return c1->GetDistance2d(victim) < c2->GetDistance2d(victim);
});
// Now we have to check if the spirit is already reviving someone...
for (Creature* spirit : chainedSpirits)
{
if (!spirit->isMoving() && !spirit->HasUnitState(UNIT_STATE_CASTING))
{
spirit->AI()->SetGUID(reviveGUID);
spirit->AI()->DoAction(ACTION_REVIVE);
reviveGUID.Clear();
break;
}
}
}
class boss_mandokir : public CreatureScript class boss_mandokir : public CreatureScript
{ {
public: public:
@@ -147,14 +173,11 @@ public:
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
// Do not want to unsummon Ohgan std::list<Creature*> chainedSpirits;
for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i) GetCreatureListWithEntryInGrid(chainedSpirits, me, NPC_CHAINED_SPIRIT, 200.f);
{ for (Creature* spirit : chainedSpirits)
if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpiritGUIDs[i])) spirit->DespawnOrUnsummon();
{
unsummon->DespawnOrUnsummon();
}
}
instance->SetBossState(DATA_MANDOKIR, DONE); instance->SetBossState(DATA_MANDOKIR, DONE);
instance->SaveToDB(); instance->SaveToDB();
} }
@@ -176,8 +199,7 @@ public:
me->SummonCreature(NPC_OHGAN, me->GetPositionX() - 3, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); me->SummonCreature(NPC_OHGAN, me->GetPositionX() - 3, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000);
for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i) for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
{ {
Creature* chainedSpirit = me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN); me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
chainedSpiritGUIDs[i] = chainedSpirit->GetGUID();
} }
DoZoneInCombat(); DoZoneInCombat();
} }
@@ -188,7 +210,7 @@ public:
return; return;
reviveGUID = victim->GetGUID(); reviveGUID = victim->GetGUID();
DoAction(ACTION_START_REVIVE); RevivePlayer(victim, reviveGUID);
if (++killCount == 3) if (++killCount == 3)
{ {
Talk(SAY_DING_KILL); Talk(SAY_DING_KILL);
@@ -199,32 +221,11 @@ public:
jindo->AI()->Talk(SAY_GRATS_JINDO); jindo->AI()->Talk(SAY_GRATS_JINDO);
} }
} }
DoCast(me, SPELL_LEVEL_UP, true); DoCastSelf(SPELL_LEVEL_UP, true);
killCount = 0; killCount = 0;
} }
} }
void DoAction(int32 action) override
{
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 = 0 */) override void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
{ {
reviveGUID = guid; reviveGUID = guid;
@@ -297,7 +298,7 @@ public:
return; return;
} }
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
return; return;
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
@@ -342,21 +343,28 @@ public:
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000)); events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
break; break;
case EVENT_CHARGE_PLAYER: case EVENT_CHARGE_PLAYER:
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 40, true), SPELL_CHARGE); if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, [this](Unit const* target)
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 1500); {
if (!me || !target)
return false;
if (target->GetTypeId() != TYPEID_PLAYER || !me->IsWithinLOSInMap(target))
return false;
return true;
}))
{
DoCast(target, SPELL_CHARGE);
events.DelayEvents(1500);
if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f)) if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f))
{ {
me->GetThreatMgr().modifyThreatPercent(mainTarget, -100); me->GetThreatMgr().modifyThreatPercent(mainTarget, -100);
} }
}
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000)); events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000));
break; break;
case EVENT_EXECUTE: case EVENT_EXECUTE:
DoCastVictim(SPELL_EXECUTE, true); DoCastVictim(SPELL_EXECUTE, true);
events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000)); events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000));
break; break;
case EVENT_FRIGHTENING_SHOUT:
DoCastAOE(SPELL_FRIGHTENING_SHOUT);
break;
case EVENT_CLEAVE: case EVENT_CLEAVE:
{ {
std::list<Unit*> meleeRangeTargets; std::list<Unit*> meleeRangeTargets;
@@ -384,12 +392,12 @@ public:
break; break;
} }
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
private: private:
uint8 killCount; uint8 killCount;
ObjectGuid chainedSpiritGUIDs[CHAINED_SPIRIT_COUNT];
ObjectGuid reviveGUID; ObjectGuid reviveGUID;
bool _useExecute; bool _useExecute;
}; };
@@ -401,7 +409,6 @@ public:
}; };
// Ohgan // Ohgan
enum OhganSpells enum OhganSpells
{ {
SPELL_SUNDERARMOR = 24317, SPELL_SUNDERARMOR = 24317,
@@ -434,8 +441,6 @@ public:
if (victim->GetTypeId() != TYPEID_PLAYER) if (victim->GetTypeId() != TYPEID_PLAYER)
return; return;
reviveGUID = victim->GetGUID();
DoAction(ACTION_START_REVIVE);
_scheduler.Schedule(6s, 12s, [this](TaskContext context) _scheduler.Schedule(6s, 12s, [this](TaskContext context)
{ {
DoCastVictim(SPELL_SUNDERARMOR); DoCastVictim(SPELL_SUNDERARMOR);
@@ -449,25 +454,7 @@ public:
return; return;
reviveGUID = victim->GetGUID(); reviveGUID = victim->GetGUID();
DoAction(ACTION_START_REVIVE); RevivePlayer(victim, reviveGUID);
}
void DoAction(int32 action) override
{
if (action == ACTION_START_REVIVE)
{
std::list<Creature*> creatures;
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
if (creatures.empty())
return;
for (Creature* chainedSpirit : creatures)
{
chainedSpirit->AI()->SetGUID(reviveGUID);
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
reviveGUID.Clear();
}
}
} }
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
@@ -553,15 +540,6 @@ public:
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID);
if (!target || target->IsAlive())
return;
if (Creature* mandokir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MANDOKIR)))
{
mandokir->GetAI()->SetGUID(target->GetGUID());
mandokir->GetAI()->DoAction(ACTION_START_REVIVE);
}
me->DespawnOrUnsummon(); me->DespawnOrUnsummon();
} }
@@ -579,22 +557,29 @@ enum VilebranchSpells
SPELL_CLEAVE = 15284 SPELL_CLEAVE = 15284
}; };
class npc_vilebranch_speaker : public CreatureScript struct npc_vilebranch_speaker : public ScriptedAI
{ {
public: npc_vilebranch_speaker(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { }
npc_vilebranch_speaker() : CreatureScript("npc_vilebranch_speaker") { }
struct npc_vilebranch_speakerAI : public ScriptedAI
{
npc_vilebranch_speakerAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { }
void Reset() override void Reset() override
{ {
demoralizing_Shout_Timer = urand(2000, 4000); _scheduler.CancelAll();
cleave_Timer = urand(5000, 8000);
} }
void EnterCombat(Unit* /*who*/) override { } void EnterCombat(Unit* /*who*/) override
{
_scheduler
.Schedule(2s, 4s, [this](TaskContext context)
{
DoCastAOE(SPELL_DEMORALIZING_SHOUT);
context.Repeat(22s, 30s);
})
.Schedule(5s, 8s, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE, true);
context.Repeat(6s, 9s);
});
}
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
@@ -607,33 +592,15 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
if (demoralizing_Shout_Timer <= diff) _scheduler.Update(diff, [this]
{ {
DoCast(me, SPELL_DEMORALIZING_SHOUT);
demoralizing_Shout_Timer = urand(22000, 30000);
}
else demoralizing_Shout_Timer -= diff;
if (cleave_Timer <= diff)
{
DoCastVictim(SPELL_CLEAVE, true);
cleave_Timer = urand(6000, 9000);
}
else cleave_Timer -= diff;
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
});
} }
private: private:
uint32 demoralizing_Shout_Timer; TaskScheduler _scheduler;
uint32 cleave_Timer;
InstanceScript* instance; InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI<npc_vilebranch_speakerAI>(creature);
}
}; };
class spell_threatening_gaze : public SpellScriptLoader class spell_threatening_gaze : public SpellScriptLoader
@@ -671,11 +638,30 @@ public:
} }
}; };
class spell_mandokir_charge : public SpellScript
{
PrepareSpellScript(spell_mandokir_charge);
void LaunchHit(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (caster && target)
caster->CastSpell(target, SPELL_FRIGHTENING_SHOUT, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_mandokir_charge::LaunchHit, EFFECT_0, SPELL_EFFECT_CHARGE);
}
};
void AddSC_boss_mandokir() void AddSC_boss_mandokir()
{ {
new boss_mandokir(); new boss_mandokir();
new npc_ohgan(); new npc_ohgan();
RegisterZulGurubCreatureAI(npc_chained_spirit); RegisterZulGurubCreatureAI(npc_chained_spirit);
new npc_vilebranch_speaker(); RegisterZulGurubCreatureAI(npc_vilebranch_speaker);
new spell_threatening_gaze(); new spell_threatening_gaze();
RegisterSpellScript(spell_mandokir_charge);
} }