fix(Scripts/SethekkHalls): Update Talon King Ikiss script (#15098)

This commit is contained in:
Skjalf
2023-02-18 17:26:52 -03:00
committed by GitHub
parent e759ac3c71
commit c2208318ea
6 changed files with 279 additions and 323 deletions

View File

@@ -17,6 +17,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "sethekk_halls.h"
enum TailonkingIkiss
@@ -26,143 +27,146 @@ enum TailonkingIkiss
SAY_SLAY = 2,
SAY_DEATH = 3,
EMOTE_ARCANE_EXP = 4,
};
enum Spells
{
SPELL_BLINK = 38194,
SPELL_BLINK_TELEPORT = 38203,
SPELL_MANA_SHIELD = 38151,
SPELL_ARCANE_BUBBLE = 9438,
SPELL_SLOW = 35032,
SPELL_POLYMORPH_N = 38245, // Difficulty data
SPELL_POLYMORPH_H = 43309,
SPELL_ARCANE_VOLLEY_N = 35059, // Difficulty data
SPELL_ARCANE_VOLLEY_H = 40424,
SPELL_ARCANE_EXPLOSION_N = 38197, // Difficulty data
SPELL_ARCANE_EXPLOSION_H = 40425,
EVENT_SPELL_BLINK = 1,
EVENT_SPELL_POLYMORPH = 2,
EVENT_SPELL_SLOW = 3,
EVENT_SPELL_ARCANE_VOLLEY = 4,
EVENT_SPELL_ARCANE_EXPLO = 5,
EVENT_HEALTH_CHECK = 6,
EVENT_SPELL_BLINK_2 = 7
SPELL_POLYMORPH = 38245,
SPELL_ARCANE_VOLLEY = 35059,
SPELL_ARCANE_EXPLOSION = 38197,
};
class boss_talon_king_ikiss : public CreatureScript
struct boss_talon_king_ikiss : public BossAI
{
public:
boss_talon_king_ikiss() : CreatureScript("boss_talon_king_ikiss") { }
CreatureAI* GetAI(Creature* creature) const override
boss_talon_king_ikiss(Creature* creature) : BossAI(creature, DATA_IKISS), _spoken(false), _manaShield(false)
{
return GetSethekkHallsAI<boss_talon_king_ikissAI>(creature);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_talon_king_ikissAI : public ScriptedAI
void Reset() override
{
boss_talon_king_ikissAI(Creature* creature) : ScriptedAI(creature)
_Reset();
_spoken = false;
_manaShield = false;
}
void MoveInLineOfSight(Unit* who) override
{
if (!_spoken && who->IsPlayer())
{
Talk(SAY_INTRO);
_spoken = true;
}
EventMap events;
ScriptedAI::MoveInLineOfSight(who);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
Talk(SAY_AGGRO);
scheduler.Schedule(35s, [this](TaskContext context)
{
me->InterruptNonMeleeSpells(false);
DoCastAOE(SPELL_BLINK);
Talk(EMOTE_ARCANE_EXP);
context.Repeat(35s, 40s);
scheduler.Schedule(1s, [this](TaskContext)
{
DoCastAOE(SPELL_ARCANE_EXPLOSION);
DoCastSelf(SPELL_ARCANE_BUBBLE, true);
});
}).Schedule(5s, [this](TaskContext context)
{
DoCastAOE(SPELL_ARCANE_VOLLEY);
context.Repeat(7s, 12s);
}).Schedule(8s, [this](TaskContext context)
{
IsHeroic() ? DoCastRandomTarget(SPELL_POLYMORPH) : DoCastMaxThreat(SPELL_POLYMORPH);
context.Repeat(15s, 17500ms);
});
if (IsHeroic())
{
scheduler.Schedule(15s, 25s, [this](TaskContext context)
{
DoCastAOE(SPELL_SLOW);
context.Repeat(15s, 30s);
});
}
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
if (GameObject* coffer = instance->GetGameObject(DATA_GO_TALON_KING_COFFER))
{
coffer->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_INTERACT_COND);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (!_manaShield && me->HealthBelowPctDamaged(20, damage))
{
DoCast(me, SPELL_MANA_SHIELD);
_manaShield = true;
}
}
void KilledUnit(Unit* /*victim*/) override
{
if (urand(0, 1))
Talk(SAY_SLAY);
}
private:
bool _spoken;
bool _manaShield;
};
void Reset() override
// 38194 - Blink
class spell_talon_king_ikiss_blink : public SpellScript
{
PrepareSpellScript(spell_talon_king_ikiss_blink);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return sSpellMgr->GetSpellInfo(SPELL_BLINK);
}
void FilterTargets(std::list<WorldObject*>& targets)
{
uint8 maxSize = 1;
if (targets.size() > maxSize)
{
_spoken = false;
Acore::Containers::RandomResize(targets, maxSize);
}
}
void MoveInLineOfSight(Unit* who) override
{
if (!_spoken && who->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_INTRO);
_spoken = true;
}
void HandleDummyHitTarget(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
GetHitUnit()->CastSpell(GetCaster(), SPELL_BLINK_TELEPORT, true);
}
ScriptedAI::MoveInLineOfSight(who);
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_BLINK, 35000);
events.ScheduleEvent(EVENT_SPELL_ARCANE_VOLLEY, 5000);
events.ScheduleEvent(EVENT_SPELL_POLYMORPH, 8000);
events.ScheduleEvent(EVENT_HEALTH_CHECK, 2000);
if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_SLOW, urand(15000, 25000));
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (InstanceScript* instance = me->GetInstanceScript())
instance->SetData(DATA_IKISSDOOREVENT, DONE);
}
void KilledUnit(Unit* /*victim*/) override
{
if (urand(0, 1))
Talk(SAY_SLAY);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_ARCANE_VOLLEY:
me->CastSpell(me, SPELL_ARCANE_VOLLEY_N, false);
events.RepeatEvent(urand(7000, 12000));
break;
case EVENT_SPELL_POLYMORPH:
if (Unit* target = (IsHeroic() ? SelectTarget(SelectTargetMethod::Random, 0) : SelectTarget(SelectTargetMethod::MaxThreat, 1)))
me->CastSpell(target, SPELL_POLYMORPH_N, false);
events.RepeatEvent(urand(15000, 17500));
break;
case EVENT_SPELL_SLOW:
me->CastSpell(me, SPELL_SLOW, false);
events.RepeatEvent(urand(15000, 30000));
break;
case EVENT_HEALTH_CHECK:
if (me->HealthBelowPct(20))
{
me->CastSpell(me, SPELL_MANA_SHIELD, false);
return;
}
events.RepeatEvent(1000);
break;
case EVENT_SPELL_BLINK:
Talk(EMOTE_ARCANE_EXP);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
me->CastSpell(target, SPELL_BLINK, false);
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
DoCast(target, SPELL_BLINK_TELEPORT);
}
events.RepeatEvent(urand(35000, 40000));
events.DelayEvents(500);
events.ScheduleEvent(EVENT_SPELL_BLINK_2, 0);
return;
case EVENT_SPELL_BLINK_2:
me->CastSpell(me, SPELL_ARCANE_EXPLOSION_N, false);
me->CastSpell(me, SPELL_ARCANE_BUBBLE, true);
break;
}
DoMeleeAttackIfReady();
}
};
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_talon_king_ikiss_blink::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_talon_king_ikiss_blink::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
enum Anzu
@@ -184,150 +188,116 @@ enum Anzu
EVENT_ANZU_HEALTH2 = 5
};
class boss_anzu : public CreatureScript
struct boss_anzu : public BossAI
{
public:
boss_anzu() : CreatureScript("boss_anzu") { }
CreatureAI* GetAI(Creature* creature) const override
boss_anzu(Creature* creature) : BossAI(creature, DATA_ANZU)
{
return GetSethekkHallsAI<boss_anzuAI>(creature);
talkTimer = 1;
me->ReplaceAllUnitFlags(UNIT_FLAG_NON_ATTACKABLE);
me->AddAura(SPELL_SHADOWFORM, me);
}
struct boss_anzuAI : public ScriptedAI
uint32 talkTimer;
void SummonedCreatureDies(Creature* summon, Unit*) override
{
boss_anzuAI(Creature* creature) : ScriptedAI(creature), summons(me)
summons.Despawn(summon);
summons.RemoveNotExisting();
if (summons.empty())
me->RemoveAurasDueToSpell(SPELL_BANISH_SELF);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.Reset();
events.ScheduleEvent(EVENT_SPELL_SCREECH, 14000);
events.ScheduleEvent(EVENT_SPELL_BOMB, 5000);
events.ScheduleEvent(EVENT_SPELL_CYCLONE, 8000);
events.ScheduleEvent(EVENT_ANZU_HEALTH1, 2000);
events.ScheduleEvent(EVENT_ANZU_HEALTH2, 2001);
}
void SummonBroods()
{
Talk(SAY_SUMMON);
me->CastSpell(me, SPELL_BANISH_SELF, true);
for (uint8 i = 0; i < 5; ++i)
me->SummonCreature(23132 /*NPC_BROOD_OF_ANZU*/, me->GetPositionX() + 20 * cos((float)i), me->GetPositionY() + 20 * std::sin((float)i), me->GetPositionZ() + 25.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
}
void UpdateAI(uint32 diff) override
{
if (talkTimer)
{
talkTimer = 1;
me->ReplaceAllUnitFlags(UNIT_FLAG_NON_ATTACKABLE);
me->AddAura(SPELL_SHADOWFORM, me);
}
EventMap events;
SummonList summons;
uint32 talkTimer;
void Reset() override
{
summons.DespawnAll();
if (InstanceScript* instance = me->GetInstanceScript())
if (instance->GetData(TYPE_ANZU_ENCOUNTER) != DONE)
instance->SetData(TYPE_ANZU_ENCOUNTER, NOT_STARTED);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->AI()->AttackStart(me->GetVictim());
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
summons.RemoveNotExisting();
if (summons.empty())
me->RemoveAurasDueToSpell(SPELL_BANISH_SELF);
}
void JustEngagedWith(Unit* /*who*/) override
{
events.Reset();
events.ScheduleEvent(EVENT_SPELL_SCREECH, 14000);
events.ScheduleEvent(EVENT_SPELL_BOMB, 5000);
events.ScheduleEvent(EVENT_SPELL_CYCLONE, 8000);
events.ScheduleEvent(EVENT_ANZU_HEALTH1, 2000);
events.ScheduleEvent(EVENT_ANZU_HEALTH2, 2001);
if (InstanceScript* instance = me->GetInstanceScript())
instance->SetData(TYPE_ANZU_ENCOUNTER, IN_PROGRESS);
}
void JustDied(Unit* /*killer*/) override
{
if (InstanceScript* instance = me->GetInstanceScript())
instance->SetData(TYPE_ANZU_ENCOUNTER, DONE);
}
void SummonBroods()
{
Talk(SAY_SUMMON);
me->CastSpell(me, SPELL_BANISH_SELF, true);
for (uint8 i = 0; i < 5; ++i)
me->SummonCreature(23132 /*NPC_BROOD_OF_ANZU*/, me->GetPositionX() + 20 * cos((float)i), me->GetPositionY() + 20 * std::sin((float)i), me->GetPositionZ() + 25.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
}
void UpdateAI(uint32 diff) override
{
if (talkTimer)
talkTimer += diff;
if (talkTimer >= 1000 && talkTimer < 10000)
{
talkTimer += diff;
if (talkTimer >= 1000 && talkTimer < 10000)
{
Talk(SAY_ANZU_INTRO1);
talkTimer = 10000;
}
else if (talkTimer >= 16000)
{
me->ReplaceAllUnitFlags(UNIT_FLAG_NONE);
me->RemoveAurasDueToSpell(SPELL_SHADOWFORM);
Talk(SAY_ANZU_INTRO2);
talkTimer = 0;
}
Talk(SAY_ANZU_INTRO1);
talkTimer = 10000;
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_STUNNED))
return;
switch (events.ExecuteEvent())
else if (talkTimer >= 16000)
{
case EVENT_SPELL_SCREECH:
me->CastSpell(me, SPELL_PARALYZING_SCREECH, false);
events.RepeatEvent(23000);
events.DelayEvents(3000);
break;
case EVENT_SPELL_BOMB:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_SPELL_BOMB, false);
events.RepeatEvent(urand(16000, 24500));
events.DelayEvents(3000);
break;
case EVENT_SPELL_CYCLONE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 45.0f, true))
me->CastSpell(target, SPELL_CYCLONE, false);
events.RepeatEvent(urand(22000, 27000));
events.DelayEvents(3000);
break;
case EVENT_ANZU_HEALTH1:
if (me->HealthBelowPct(66))
{
SummonBroods();
events.DelayEvents(10000);
return;
}
events.RepeatEvent(1000);
break;
case EVENT_ANZU_HEALTH2:
if (me->HealthBelowPct(33))
{
SummonBroods();
events.DelayEvents(10000);
return;
}
events.RepeatEvent(1000);
break;
me->ReplaceAllUnitFlags(UNIT_FLAG_NONE);
me->RemoveAurasDueToSpell(SPELL_SHADOWFORM);
Talk(SAY_ANZU_INTRO2);
talkTimer = 0;
}
DoMeleeAttackIfReady();
}
};
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_STUNNED))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_SCREECH:
me->CastSpell(me, SPELL_PARALYZING_SCREECH, false);
events.RepeatEvent(23000);
events.DelayEvents(3000);
break;
case EVENT_SPELL_BOMB:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_SPELL_BOMB, false);
events.RepeatEvent(urand(16000, 24500));
events.DelayEvents(3000);
break;
case EVENT_SPELL_CYCLONE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 45.0f, true))
me->CastSpell(target, SPELL_CYCLONE, false);
events.RepeatEvent(urand(22000, 27000));
events.DelayEvents(3000);
break;
case EVENT_ANZU_HEALTH1:
if (me->HealthBelowPct(66))
{
SummonBroods();
events.DelayEvents(10000);
return;
}
events.RepeatEvent(1000);
break;
case EVENT_ANZU_HEALTH2:
if (me->HealthBelowPct(33))
{
SummonBroods();
events.DelayEvents(10000);
return;
}
events.RepeatEvent(1000);
break;
}
DoMeleeAttackIfReady();
}
};
void AddSC_boss_talon_king_ikiss()
{
new boss_talon_king_ikiss();
new boss_anzu();
RegisterSethekkHallsCreatureAI(boss_talon_king_ikiss);
RegisterSpellScript(spell_talon_king_ikiss_blink);
RegisterSethekkHallsCreatureAI(boss_anzu);
}

View File

@@ -19,6 +19,17 @@
#include "ScriptMgr.h"
#include "sethekk_halls.h"
DoorData const doorData[] =
{
{ GO_IKISS_DOOR, DATA_IKISS, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
ObjectData const gameObjectData[] =
{
{ GO_THE_TALON_KINGS_COFFER, DATA_GO_TALON_KING_COFFER }
};
class instance_sethekk_halls : public InstanceMapScript
{
public:
@@ -31,91 +42,20 @@ public:
struct instance_sethekk_halls_InstanceMapScript : public InstanceScript
{
instance_sethekk_halls_InstanceMapScript(Map* map) : InstanceScript(map) {}
uint32 AnzuEncounter;
ObjectGuid m_uiIkissDoorGUID;
ObjectGuid _talonKingsCofferGUID;
void Initialize() override
instance_sethekk_halls_InstanceMapScript(Map* map) : InstanceScript(map)
{
AnzuEncounter = NOT_STARTED;
SetHeaders(DataHeaders);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
LoadObjectData(nullptr, gameObjectData);
}
void OnCreatureCreate(Creature* creature) override
{
if (creature->GetEntry() == NPC_ANZU || creature->GetEntry() == NPC_VOICE_OF_THE_RAVEN_GOD)
if (AnzuEncounter >= IN_PROGRESS)
if (GetBossState(DATA_ANZU) == DONE)
creature->DespawnOrUnsummon(1);
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_IKISS_DOOR:
m_uiIkissDoorGUID = go->GetGUID();
break;
case GO_THE_TALON_KINGS_COFFER:
_talonKingsCofferGUID = go->GetGUID();
break;
}
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case DATA_IKISSDOOREVENT:
if (data == DONE)
{
DoUseDoorOrButton(m_uiIkissDoorGUID, DAY * IN_MILLISECONDS);
if (GameObject* coffer = instance->GetGameObject(_talonKingsCofferGUID))
coffer->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_INTERACT_COND);
}
break;
case TYPE_ANZU_ENCOUNTER:
AnzuEncounter = data;
SaveToDB();
break;
}
}
std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
saveStream << "S H " << AnzuEncounter;
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
}
void Load(const char* strIn) override
{
if (!strIn)
{
OUT_LOAD_INST_DATA_FAIL;
return;
}
OUT_LOAD_INST_DATA(strIn);
char dataHead1, dataHead2;
std::istringstream loadStream(strIn);
loadStream >> dataHead1 >> dataHead2;
if (dataHead1 == 'S' && dataHead2 == 'H')
{
loadStream >> AnzuEncounter;
if (AnzuEncounter == IN_PROGRESS)
AnzuEncounter = NOT_STARTED;
}
OUT_LOAD_INST_DATA_COMPLETE;
}
};
};

View File

@@ -20,14 +20,30 @@
#include "CreatureAIImpl.h"
#define DataHeaders "SH"
uint32 constexpr EncounterCount = 3;
#define SethekkHallsScriptName "instance_sethekk_halls"
enum Encounters
{
DATA_DARKWEAVER_SYTH,
DATA_ANZU,
DATA_IKISS,
};
enum eTypes
{
DATA_IKISSDOOREVENT = 1,
TYPE_ANZU_ENCOUNTER = 2,
};
enum InstanceData
{
DATA_GO_TALON_KING_COFFER
};
enum eIds
{
NPC_VOICE_OF_THE_RAVEN_GOD = 21851,
@@ -43,4 +59,6 @@ inline AI* GetSethekkHallsAI(T* obj)
return GetInstanceAI<AI>(obj, SethekkHallsScriptName);
}
#define RegisterSethekkHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSethekkHallsAI)
#endif