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
@@ -0,0 +1,4 @@
--
DELETE FROM `spell_script_names` WHERE `spell_id` = 38194;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(38194, 'spell_talon_king_ikiss_blink');
+21
View File
@@ -264,6 +264,27 @@ SpellCastResult UnitAI::DoCastRandomTarget(uint32 spellId, uint32 threatTablePos
return SPELL_FAILED_BAD_TARGETS; return SPELL_FAILED_BAD_TARGETS;
} }
/**
* @brief Cast spell on the max threat target, which may not always be the current victim.
*
* @param uint32 spellId Spell ID to cast.
* @param uint32 Threat table position.
* @param float dist Distance from caster to target.
* @param bool playerOnly Select players only, excludes pets and other npcs.
* @param bool triggered Triggered cast (full triggered mask).
*
* @return SpellCastResult
*/
SpellCastResult UnitAI::DoCastMaxThreat(uint32 spellId, uint32 threatTablePosition, float dist, bool playerOnly, bool triggered)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, threatTablePosition, dist, playerOnly))
{
return DoCast(target, spellId, triggered);
}
return SPELL_FAILED_BAD_TARGETS;
}
#define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;} #define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;}
void UnitAI::FillAISpellInfo() void UnitAI::FillAISpellInfo()
+3
View File
@@ -372,6 +372,9 @@ public:
SpellCastResult DoCastAOE(uint32 spellId, bool triggered = false); SpellCastResult DoCastAOE(uint32 spellId, bool triggered = false);
SpellCastResult DoCastRandomTarget(uint32 spellId, uint32 threatTablePosition = 0, float dist = 0.0f, bool playerOnly = true, bool triggered = false); SpellCastResult DoCastRandomTarget(uint32 spellId, uint32 threatTablePosition = 0, float dist = 0.0f, bool playerOnly = true, bool triggered = false);
// Cast spell on the top threat target, which may not be the current victim.
SpellCastResult DoCastMaxThreat(uint32 spellId, uint32 threatTablePosition = 0, float dist = 0.0f, bool playerOnly = true, bool triggered = false);
float DoGetSpellMaxRange(uint32 spellId, bool positive = false); float DoGetSpellMaxRange(uint32 spellId, bool positive = false);
void DoMeleeAttackIfReady(); void DoMeleeAttackIfReady();
@@ -17,6 +17,7 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "SpellScript.h"
#include "sethekk_halls.h" #include "sethekk_halls.h"
enum TailonkingIkiss enum TailonkingIkiss
@@ -26,55 +27,40 @@ enum TailonkingIkiss
SAY_SLAY = 2, SAY_SLAY = 2,
SAY_DEATH = 3, SAY_DEATH = 3,
EMOTE_ARCANE_EXP = 4, EMOTE_ARCANE_EXP = 4,
};
enum Spells
{
SPELL_BLINK = 38194, SPELL_BLINK = 38194,
SPELL_BLINK_TELEPORT = 38203, SPELL_BLINK_TELEPORT = 38203,
SPELL_MANA_SHIELD = 38151, SPELL_MANA_SHIELD = 38151,
SPELL_ARCANE_BUBBLE = 9438, SPELL_ARCANE_BUBBLE = 9438,
SPELL_SLOW = 35032, SPELL_SLOW = 35032,
SPELL_POLYMORPH_N = 38245, // Difficulty data SPELL_POLYMORPH = 38245,
SPELL_POLYMORPH_H = 43309, SPELL_ARCANE_VOLLEY = 35059,
SPELL_ARCANE_VOLLEY_N = 35059, // Difficulty data SPELL_ARCANE_EXPLOSION = 38197,
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
}; };
class boss_talon_king_ikiss : public CreatureScript struct boss_talon_king_ikiss : public BossAI
{ {
public: boss_talon_king_ikiss(Creature* creature) : BossAI(creature, DATA_IKISS), _spoken(false), _manaShield(false)
boss_talon_king_ikiss() : CreatureScript("boss_talon_king_ikiss") { }
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetSethekkHallsAI<boss_talon_king_ikissAI>(creature); scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
} }
struct boss_talon_king_ikissAI : public ScriptedAI
{
boss_talon_king_ikissAI(Creature* creature) : ScriptedAI(creature)
{
}
EventMap events;
bool _spoken;
void Reset() override void Reset() override
{ {
_Reset();
_spoken = false; _spoken = false;
_manaShield = false;
} }
void MoveInLineOfSight(Unit* who) override void MoveInLineOfSight(Unit* who) override
{ {
if (!_spoken && who->GetTypeId() == TYPEID_PLAYER) if (!_spoken && who->IsPlayer())
{ {
Talk(SAY_INTRO); Talk(SAY_INTRO);
_spoken = true; _spoken = true;
@@ -85,22 +71,59 @@ public:
void JustEngagedWith(Unit* /*who*/) override void JustEngagedWith(Unit* /*who*/) override
{ {
_JustEngagedWith();
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_BLINK, 35000); scheduler.Schedule(35s, [this](TaskContext context)
events.ScheduleEvent(EVENT_SPELL_ARCANE_VOLLEY, 5000); {
events.ScheduleEvent(EVENT_SPELL_POLYMORPH, 8000); me->InterruptNonMeleeSpells(false);
events.ScheduleEvent(EVENT_HEALTH_CHECK, 2000); 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()) if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_SLOW, urand(15000, 25000)); {
scheduler.Schedule(15s, 25s, [this](TaskContext context)
{
DoCastAOE(SPELL_SLOW);
context.Repeat(15s, 30s);
});
}
} }
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
_JustDied();
Talk(SAY_DEATH); Talk(SAY_DEATH);
if (InstanceScript* instance = me->GetInstanceScript()) if (GameObject* coffer = instance->GetGameObject(DATA_GO_TALON_KING_COFFER))
instance->SetData(DATA_IKISSDOOREVENT, DONE); {
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 void KilledUnit(Unit* /*victim*/) override
@@ -109,60 +132,41 @@ public:
Talk(SAY_SLAY); Talk(SAY_SLAY);
} }
void UpdateAI(uint32 diff) override private:
{ bool _spoken;
if (!UpdateVictim()) bool _manaShield;
return; };
events.Update(diff); // 38194 - Blink
if (me->HasUnitState(UNIT_STATE_CASTING)) class spell_talon_king_ikiss_blink : public SpellScript
return; {
PrepareSpellScript(spell_talon_king_ikiss_blink);
switch (events.ExecuteEvent()) bool Validate(SpellInfo const* /*spellInfo*/) override
{ {
case EVENT_SPELL_ARCANE_VOLLEY: return sSpellMgr->GetSpellInfo(SPELL_BLINK);
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 FilterTargets(std::list<WorldObject*>& targets)
{
uint8 maxSize = 1;
if (targets.size() > maxSize)
{
Acore::Containers::RandomResize(targets, maxSize);
}
}
void HandleDummyHitTarget(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
GetHitUnit()->CastSpell(GetCaster(), SPELL_BLINK_TELEPORT, true);
}
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 enum Anzu
@@ -184,43 +188,17 @@ enum Anzu
EVENT_ANZU_HEALTH2 = 5 EVENT_ANZU_HEALTH2 = 5
}; };
class boss_anzu : public CreatureScript struct boss_anzu : public BossAI
{ {
public: boss_anzu(Creature* creature) : BossAI(creature, DATA_ANZU)
boss_anzu() : CreatureScript("boss_anzu") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetSethekkHallsAI<boss_anzuAI>(creature);
}
struct boss_anzuAI : public ScriptedAI
{
boss_anzuAI(Creature* creature) : ScriptedAI(creature), summons(me)
{ {
talkTimer = 1; talkTimer = 1;
me->ReplaceAllUnitFlags(UNIT_FLAG_NON_ATTACKABLE); me->ReplaceAllUnitFlags(UNIT_FLAG_NON_ATTACKABLE);
me->AddAura(SPELL_SHADOWFORM, me); me->AddAura(SPELL_SHADOWFORM, me);
} }
EventMap events;
SummonList summons;
uint32 talkTimer; 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 void SummonedCreatureDies(Creature* summon, Unit*) override
{ {
summons.Despawn(summon); summons.Despawn(summon);
@@ -231,21 +209,13 @@ public:
void JustEngagedWith(Unit* /*who*/) override void JustEngagedWith(Unit* /*who*/) override
{ {
_JustEngagedWith();
events.Reset(); events.Reset();
events.ScheduleEvent(EVENT_SPELL_SCREECH, 14000); events.ScheduleEvent(EVENT_SPELL_SCREECH, 14000);
events.ScheduleEvent(EVENT_SPELL_BOMB, 5000); events.ScheduleEvent(EVENT_SPELL_BOMB, 5000);
events.ScheduleEvent(EVENT_SPELL_CYCLONE, 8000); events.ScheduleEvent(EVENT_SPELL_CYCLONE, 8000);
events.ScheduleEvent(EVENT_ANZU_HEALTH1, 2000); events.ScheduleEvent(EVENT_ANZU_HEALTH1, 2000);
events.ScheduleEvent(EVENT_ANZU_HEALTH2, 2001); 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() void SummonBroods()
@@ -323,11 +293,11 @@ public:
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
};
}; };
void AddSC_boss_talon_king_ikiss() void AddSC_boss_talon_king_ikiss()
{ {
new boss_talon_king_ikiss(); RegisterSethekkHallsCreatureAI(boss_talon_king_ikiss);
new boss_anzu(); RegisterSpellScript(spell_talon_king_ikiss_blink);
RegisterSethekkHallsCreatureAI(boss_anzu);
} }
@@ -19,6 +19,17 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "sethekk_halls.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 class instance_sethekk_halls : public InstanceMapScript
{ {
public: public:
@@ -31,91 +42,20 @@ public:
struct instance_sethekk_halls_InstanceMapScript : public InstanceScript struct instance_sethekk_halls_InstanceMapScript : public InstanceScript
{ {
instance_sethekk_halls_InstanceMapScript(Map* map) : InstanceScript(map) {} instance_sethekk_halls_InstanceMapScript(Map* map) : InstanceScript(map)
uint32 AnzuEncounter;
ObjectGuid m_uiIkissDoorGUID;
ObjectGuid _talonKingsCofferGUID;
void Initialize() override
{ {
AnzuEncounter = NOT_STARTED; SetHeaders(DataHeaders);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
LoadObjectData(nullptr, gameObjectData);
} }
void OnCreatureCreate(Creature* creature) override void OnCreatureCreate(Creature* creature) override
{ {
if (creature->GetEntry() == NPC_ANZU || creature->GetEntry() == NPC_VOICE_OF_THE_RAVEN_GOD) 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); 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;
}
}; };
}; };
@@ -20,14 +20,30 @@
#include "CreatureAIImpl.h" #include "CreatureAIImpl.h"
#define DataHeaders "SH"
uint32 constexpr EncounterCount = 3;
#define SethekkHallsScriptName "instance_sethekk_halls" #define SethekkHallsScriptName "instance_sethekk_halls"
enum Encounters
{
DATA_DARKWEAVER_SYTH,
DATA_ANZU,
DATA_IKISS,
};
enum eTypes enum eTypes
{ {
DATA_IKISSDOOREVENT = 1, DATA_IKISSDOOREVENT = 1,
TYPE_ANZU_ENCOUNTER = 2, TYPE_ANZU_ENCOUNTER = 2,
}; };
enum InstanceData
{
DATA_GO_TALON_KING_COFFER
};
enum eIds enum eIds
{ {
NPC_VOICE_OF_THE_RAVEN_GOD = 21851, NPC_VOICE_OF_THE_RAVEN_GOD = 21851,
@@ -43,4 +59,6 @@ inline AI* GetSethekkHallsAI(T* obj)
return GetInstanceAI<AI>(obj, SethekkHallsScriptName); return GetInstanceAI<AI>(obj, SethekkHallsScriptName);
} }
#define RegisterSethekkHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSethekkHallsAI)
#endif #endif