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

View File

@@ -47,6 +47,7 @@ enum Spells
SPELL_LEVEL_UP = 24312,
SPELL_EXECUTE = 7160,
SPELL_MANDOKIR_CLEAVE = 20691,
SPELL_SUMMON_PLAYER = 25104,
SPELL_REVIVE = 24341 // chained spirit
};
@@ -63,8 +64,7 @@ enum Events
EVENT_WATCH_PLAYER = 8,
EVENT_CHARGE_PLAYER = 9,
EVENT_EXECUTE = 10,
EVENT_FRIGHTENING_SHOUT = 11,
EVENT_CLEAVE = 12
EVENT_CLEAVE = 11
};
enum Action
@@ -113,6 +113,32 @@ Position const PosMandokir[2] =
{ -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
{
public:
@@ -147,14 +173,11 @@ public:
void JustDied(Unit* /*killer*/) override
{
// Do not want to unsummon Ohgan
for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
{
if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpiritGUIDs[i]))
{
unsummon->DespawnOrUnsummon();
}
}
std::list<Creature*> chainedSpirits;
GetCreatureListWithEntryInGrid(chainedSpirits, me, NPC_CHAINED_SPIRIT, 200.f);
for (Creature* spirit : chainedSpirits)
spirit->DespawnOrUnsummon();
instance->SetBossState(DATA_MANDOKIR, DONE);
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);
for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
{
Creature* chainedSpirit = me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
chainedSpiritGUIDs[i] = chainedSpirit->GetGUID();
me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
}
DoZoneInCombat();
}
@@ -188,7 +210,7 @@ public:
return;
reviveGUID = victim->GetGUID();
DoAction(ACTION_START_REVIVE);
RevivePlayer(victim, reviveGUID);
if (++killCount == 3)
{
Talk(SAY_DING_KILL);
@@ -199,32 +221,11 @@ public:
jindo->AI()->Talk(SAY_GRATS_JINDO);
}
}
DoCast(me, SPELL_LEVEL_UP, true);
DoCastSelf(SPELL_LEVEL_UP, true);
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
{
reviveGUID = guid;
@@ -297,7 +298,7 @@ public:
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
return;
while (uint32 eventId = events.ExecuteEvent())
@@ -342,11 +343,21 @@ public:
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
break;
case EVENT_CHARGE_PLAYER:
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 40, true), SPELL_CHARGE);
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 1500);
if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f))
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, [this](Unit const* target)
{
if (!me || !target)
return false;
if (target->GetTypeId() != TYPEID_PLAYER || !me->IsWithinLOSInMap(target))
return false;
return true;
}))
{
me->GetThreatMgr().modifyThreatPercent(mainTarget, -100);
DoCast(target, SPELL_CHARGE);
events.DelayEvents(1500);
if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f))
{
me->GetThreatMgr().modifyThreatPercent(mainTarget, -100);
}
}
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000));
break;
@@ -354,9 +365,6 @@ public:
DoCastVictim(SPELL_EXECUTE, true);
events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000));
break;
case EVENT_FRIGHTENING_SHOUT:
DoCastAOE(SPELL_FRIGHTENING_SHOUT);
break;
case EVENT_CLEAVE:
{
std::list<Unit*> meleeRangeTargets;
@@ -384,12 +392,12 @@ public:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 killCount;
ObjectGuid chainedSpiritGUIDs[CHAINED_SPIRIT_COUNT];
ObjectGuid reviveGUID;
bool _useExecute;
};
@@ -401,7 +409,6 @@ public:
};
// Ohgan
enum OhganSpells
{
SPELL_SUNDERARMOR = 24317,
@@ -422,9 +429,9 @@ public:
me->AddAura(SPELL_THRASH, me);
_scheduler.CancelAll();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
reviveGUID.Clear();
}
@@ -434,12 +441,10 @@ public:
if (victim->GetTypeId() != TYPEID_PLAYER)
return;
reviveGUID = victim->GetGUID();
DoAction(ACTION_START_REVIVE);
_scheduler.Schedule(6s, 12s, [this](TaskContext context)
{
DoCastVictim(SPELL_SUNDERARMOR);
context.Repeat(6s, 12s);
DoCastVictim(SPELL_SUNDERARMOR);
context.Repeat(6s, 12s);
});
}
@@ -449,25 +454,7 @@ public:
return;
reviveGUID = victim->GetGUID();
DoAction(ACTION_START_REVIVE);
}
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();
}
}
RevivePlayer(victim, reviveGUID);
}
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
@@ -553,15 +540,6 @@ public:
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();
}
@@ -579,61 +557,50 @@ enum VilebranchSpells
SPELL_CLEAVE = 15284
};
class npc_vilebranch_speaker : public CreatureScript
struct npc_vilebranch_speaker : public ScriptedAI
{
public:
npc_vilebranch_speaker() : CreatureScript("npc_vilebranch_speaker") { }
npc_vilebranch_speaker(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { }
struct npc_vilebranch_speakerAI : public ScriptedAI
void Reset() override
{
npc_vilebranch_speakerAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { }
_scheduler.CancelAll();
}
void Reset() override
{
demoralizing_Shout_Timer = urand(2000, 4000);
cleave_Timer = urand(5000, 8000);
}
void EnterCombat(Unit* /*who*/) override { }
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_MANDOKIR, SPECIAL);
}
void UpdateAI(uint32 diff) override
{
// Return since we have no target
if (!UpdateVictim())
return;
if (demoralizing_Shout_Timer <= diff)
void EnterCombat(Unit* /*who*/) override
{
_scheduler
.Schedule(2s, 4s, [this](TaskContext context)
{
DoCast(me, SPELL_DEMORALIZING_SHOUT);
demoralizing_Shout_Timer = urand(22000, 30000);
}
else demoralizing_Shout_Timer -= diff;
if (cleave_Timer <= diff)
DoCastAOE(SPELL_DEMORALIZING_SHOUT);
context.Repeat(22s, 30s);
})
.Schedule(5s, 8s, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE, true);
cleave_Timer = urand(6000, 9000);
}
else cleave_Timer -= diff;
DoMeleeAttackIfReady();
}
private:
uint32 demoralizing_Shout_Timer;
uint32 cleave_Timer;
InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI<npc_vilebranch_speakerAI>(creature);
context.Repeat(6s, 9s);
});
}
void JustDied(Unit* /*killer*/) override
{
instance->SetBossState(DATA_MANDOKIR, SPECIAL);
}
void UpdateAI(uint32 diff) override
{
// Return since we have no target
if (!UpdateVictim())
return;
_scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
private:
TaskScheduler _scheduler;
InstanceScript* instance;
};
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()
{
new boss_mandokir();
new npc_ohgan();
RegisterZulGurubCreatureAI(npc_chained_spirit);
new npc_vilebranch_speaker();
RegisterZulGurubCreatureAI(npc_vilebranch_speaker);
new spell_threatening_gaze();
RegisterSpellScript(spell_mandokir_charge);
}