mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-16 10:30:27 +00:00
fix(Scripts/RuinsOfAhnQiraj): Rework Ayamiss (#12738)
* fix(Scripts/RuinsOfAhnQiraj): Rework Ayamiss - Use serverside spells to handle the Hive'Zara Swarmers - Adjust pathing and timers - Rewrite its script to TaskScheduler Co-Authored-By: Gultask <100873791+Gultask@users.noreply.github.com> * fix swarmers not being summoned if the boss is casting & movement * Update landing path for swarmers * fix: Update the looping script * correct trash ability * fix ayamiss landing Co-authored-by: Gultask <100873791+Gultask@users.noreply.github.com>
This commit is contained in:
@@ -18,7 +18,9 @@
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "ruins_of_ahnqiraj.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
@@ -28,22 +30,31 @@ enum Spells
|
||||
SPELL_FRENZY = 8269,
|
||||
SPELL_LASH = 25852,
|
||||
SPELL_FEED = 25721,
|
||||
SPELL_THRASH = 3391,
|
||||
|
||||
// Server-side spells
|
||||
SPELL_SUMMON_LARVA_A = 26538,
|
||||
SPELL_SUMMON_LARVA_B = 26539,
|
||||
SPELL_LARVA_AGGRO_EFFECT = 25724, // Unknown purpose
|
||||
SPELL_LARVA_FEAR_EFFECT = 25726, // Unknown purpose
|
||||
SPELL_SUMMON_LARVA_A = 26538,
|
||||
SPELL_SUMMON_LARVA_B = 26539,
|
||||
SPELL_LARVA_AGGRO_EFFECT = 25724, // Unknown purpose
|
||||
SPELL_LARVA_FEAR_EFFECT = 25726, // Unknown purpose
|
||||
SPELL_SUMMON_HIVEZARA_SWARMER = 25708,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_1 = 25709,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_2 = 25825,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_3 = 25826,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_4 = 25827,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_5 = 25828,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_TRIGGER = 25830,
|
||||
SPELL_HIVEZARA_SWARMER_START_LOOP = 25711,
|
||||
SPELL_HIVEZARA_SWARMER_LOOP_1 = 25833,
|
||||
SPELL_HIVEZARA_SWARMER_LOOP_2 = 25834,
|
||||
SPELL_HIVEZARA_SWARMER_LOOP_3 = 25835,
|
||||
SPELL_HIVEZARA_SWARMER_SWARM = 25844
|
||||
};
|
||||
|
||||
enum Events
|
||||
enum Misc
|
||||
{
|
||||
EVENT_STINGER_SPRAY = 1,
|
||||
EVENT_POISON_STINGER = 2,
|
||||
EVENT_SUMMON_SWARMER = 3,
|
||||
EVENT_SWARMER_ATTACK = 4,
|
||||
EVENT_PARALYZE = 5,
|
||||
EVENT_LASH = 6
|
||||
MAX_SWARMER_COUNT = 28,
|
||||
ACTION_SWARMER_SWARM = 1,
|
||||
};
|
||||
|
||||
enum Emotes
|
||||
@@ -66,8 +77,6 @@ enum Points
|
||||
|
||||
const Position AyamissAirPos = { -9689.292f, 1547.912f, 48.02729f, 0.0f };
|
||||
const Position AltarPos = { -9717.18f, 1517.72f, 27.4677f, 0.0f };
|
||||
/// @todo These below are probably incorrect, taken from SD2
|
||||
const Position SwarmerPos = { -9647.352f, 1578.062f, 55.32f, 0.0f };
|
||||
|
||||
struct boss_ayamiss : public BossAI
|
||||
{
|
||||
@@ -79,6 +88,7 @@ struct boss_ayamiss : public BossAI
|
||||
_phase = PHASE_AIR;
|
||||
_enraged = false;
|
||||
SetCombatMovement(false);
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* who) override
|
||||
@@ -86,12 +96,14 @@ struct boss_ayamiss : public BossAI
|
||||
switch (who->GetEntry())
|
||||
{
|
||||
case NPC_HIVEZARA_SWARMER:
|
||||
who->CastSpell(who, SPELL_HIVEZARA_SWARMER_TELEPORT_TRIGGER, true);
|
||||
_swarmers.push_back(who->GetGUID());
|
||||
break;
|
||||
case NPC_HIVEZARA_LARVA:
|
||||
who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos);
|
||||
break;
|
||||
}
|
||||
|
||||
summons.Summon(who);
|
||||
}
|
||||
|
||||
@@ -104,6 +116,7 @@ struct boss_ayamiss : public BossAI
|
||||
else if (type == WAYPOINT_MOTION_TYPE && id == POINT_GROUND)
|
||||
{
|
||||
SetCombatMovement(true);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
if (me->GetVictim())
|
||||
@@ -115,6 +128,55 @@ struct boss_ayamiss : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleTasks()
|
||||
{
|
||||
_scheduler.Schedule(20s, 30s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_STINGER_SPRAY);
|
||||
context.Repeat(15s, 20s);
|
||||
}).Schedule(5s, [this](TaskContext context) {
|
||||
DoCastVictim(SPELL_POISON_STINGER);
|
||||
context.SetGroup(PHASE_AIR);
|
||||
context.Repeat(2s, 3s);
|
||||
}).Schedule(5s, [this](TaskContext context) {
|
||||
DoCastAOE(SPELL_SUMMON_HIVEZARA_SWARMER, true);
|
||||
|
||||
if (_swarmers.size() >= MAX_SWARMER_COUNT)
|
||||
{
|
||||
DoCastAOE(SPELL_HIVEZARA_SWARMER_SWARM, true);
|
||||
}
|
||||
|
||||
context.Repeat(RAND(2400ms, 3600ms));
|
||||
}).Schedule(15s, [this](TaskContext context) {
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
|
||||
{
|
||||
DoCast(target, SPELL_PARALYZE, true);
|
||||
instance->SetGuidData(DATA_PARALYZED, target->GetGUID());
|
||||
DoCastAOE(RAND(SPELL_SUMMON_LARVA_A, SPELL_SUMMON_LARVA_B), true);
|
||||
}
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_SWARMER_SWARM)
|
||||
{
|
||||
for (ObjectGuid const& guid : _swarmers)
|
||||
{
|
||||
if (Creature* swarmer = me->GetMap()->GetCreature(guid))
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
|
||||
{
|
||||
swarmer->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_swarmers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
me->ClearUnitState(UNIT_STATE_ROOT);
|
||||
@@ -125,14 +187,10 @@ struct boss_ayamiss : public BossAI
|
||||
void EnterCombat(Unit* attacker) override
|
||||
{
|
||||
BossAI::EnterCombat(attacker);
|
||||
events.ScheduleEvent(EVENT_STINGER_SPRAY, 20s, 30s);
|
||||
events.ScheduleEvent(EVENT_POISON_STINGER, 5s);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5s);
|
||||
events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60s);
|
||||
events.ScheduleEvent(EVENT_PARALYZE, 15s);
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos);
|
||||
ScheduleTasks();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
@@ -144,9 +202,19 @@ struct boss_ayamiss : public BossAI
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
|
||||
events.ScheduleEvent(EVENT_LASH, 5s, 8s);
|
||||
events.CancelEvent(EVENT_POISON_STINGER);
|
||||
DoResetThreat();
|
||||
|
||||
_scheduler.Schedule(5s, 8s, [this](TaskContext context) {
|
||||
DoCastVictim(SPELL_LASH);
|
||||
context.Repeat(8s, 15s);
|
||||
}).Schedule(16s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_THRASH);
|
||||
context.Repeat();
|
||||
});
|
||||
|
||||
_scheduler.DelayAll(5s);
|
||||
_scheduler.CancelGroup(PHASE_AIR);
|
||||
}
|
||||
|
||||
if (!_enraged && me->HealthBelowPctDamaged(20, damage))
|
||||
@@ -162,66 +230,14 @@ struct boss_ayamiss : public BossAI
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_STINGER_SPRAY:
|
||||
DoCastSelf(SPELL_STINGER_SPRAY);
|
||||
events.ScheduleEvent(EVENT_STINGER_SPRAY, 15s, 20s);
|
||||
break;
|
||||
case EVENT_POISON_STINGER:
|
||||
DoCastVictim(SPELL_POISON_STINGER);
|
||||
events.ScheduleEvent(EVENT_POISON_STINGER, 2s, 3s);
|
||||
break;
|
||||
case EVENT_PARALYZE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
|
||||
{
|
||||
DoCast(target, SPELL_PARALYZE, true);
|
||||
instance->SetGuidData(DATA_PARALYZED, target->GetGUID());
|
||||
DoCastAOE(RAND(SPELL_SUMMON_LARVA_A, SPELL_SUMMON_LARVA_B), true);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_PARALYZE, 15s);
|
||||
break;
|
||||
case EVENT_SWARMER_ATTACK:
|
||||
for (ObjectGuid const& guid : _swarmers)
|
||||
{
|
||||
if (Creature* swarmer = me->GetMap()->GetCreature(guid))
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
|
||||
{
|
||||
swarmer->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
_swarmers.clear();
|
||||
events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60s);
|
||||
break;
|
||||
case EVENT_SUMMON_SWARMER:
|
||||
{
|
||||
Position const offset = { 0.0f, 0.0f, 20.0f, 0.0f };
|
||||
Position spawnpos = me->GetRandomPoint(SwarmerPos, 80.0f);
|
||||
spawnpos.RelocateOffset(offset);
|
||||
if (Creature* wasp = me->SummonCreature(NPC_HIVEZARA_SWARMER, spawnpos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
|
||||
{
|
||||
wasp->GetMotionMaster()->MoveRandom(10.0f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5s);
|
||||
break;
|
||||
}
|
||||
case EVENT_LASH:
|
||||
DoCastVictim(SPELL_LASH);
|
||||
events.ScheduleEvent(EVENT_LASH, 8s, 15s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DoMeleeAttackIfReady();
|
||||
_scheduler.Update(diff,
|
||||
std::bind(&BossAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
private:
|
||||
GuidList _swarmers;
|
||||
uint8 _phase;
|
||||
bool _enraged;
|
||||
TaskScheduler _scheduler;
|
||||
Position homePos;
|
||||
};
|
||||
|
||||
@@ -234,14 +250,11 @@ struct npc_hive_zara_larva : public ScriptedAI
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE)
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_PARALYZE)
|
||||
{
|
||||
if (id == POINT_PARALYZE)
|
||||
if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED)))
|
||||
{
|
||||
if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED)))
|
||||
{
|
||||
DoCast(target, SPELL_FEED);
|
||||
}
|
||||
DoCast(target, SPELL_FEED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,7 +268,6 @@ struct npc_hive_zara_larva : public ScriptedAI
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS)
|
||||
return;
|
||||
@@ -282,8 +294,151 @@ private:
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
struct npc_hive_zara_swarmer : public ScriptedAI
|
||||
{
|
||||
npc_hive_zara_swarmer(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void PathEndReached(uint32 /*pathId*/) override
|
||||
{
|
||||
// Delay is required because we are calling the movement generator from inside the pathing hook.
|
||||
// If we issue another call here, it will be flushed before it is executed.
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
DoCastSelf(SPELL_HIVEZARA_SWARMER_START_LOOP);
|
||||
}, 1s);
|
||||
}
|
||||
};
|
||||
|
||||
struct WaspTeleportData
|
||||
{
|
||||
uint32 spellId;
|
||||
uint32 pathId;
|
||||
};
|
||||
|
||||
class spell_ayamiss_swarmer_teleport_trigger : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ayamiss_swarmer_teleport_trigger);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo
|
||||
( {
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_1, SPELL_HIVEZARA_SWARMER_TELEPORT_2,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_3, SPELL_HIVEZARA_SWARMER_TELEPORT_4,
|
||||
SPELL_HIVEZARA_SWARMER_TELEPORT_5
|
||||
});
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
WaspTeleportData telData[5] =
|
||||
{
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_1, NPC_HIVEZARA_SWARMER * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_2, (NPC_HIVEZARA_SWARMER + 1) * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_3, (NPC_HIVEZARA_SWARMER + 2) * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_4, (NPC_HIVEZARA_SWARMER + 3) * 10 },
|
||||
{ SPELL_HIVEZARA_SWARMER_TELEPORT_5, (NPC_HIVEZARA_SWARMER + 4) * 10 }
|
||||
};
|
||||
|
||||
WaspTeleportData data = Acore::Containers::SelectRandomContainerElement(telData);
|
||||
caster->CastSpell((Unit*)nullptr, data.spellId, true);
|
||||
|
||||
uint32 pathId = data.pathId;
|
||||
caster->m_Events.AddEventAtOffset([caster, pathId]()
|
||||
{
|
||||
caster->GetMotionMaster()->MovePath(pathId, false);
|
||||
}, 1s);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_teleport_trigger::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_ayamiss_swarmer_swarm : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ayamiss_swarmer_swarm);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetEntry() == NPC_AYAMISS;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->ToCreature()->AI()->DoAction(ACTION_SWARMER_SWARM);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_swarm::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_ayamiss_swarmer_start_loop : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_ayamiss_swarmer_start_loop);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_HIVEZARA_SWARMER_LOOP_1, SPELL_HIVEZARA_SWARMER_LOOP_2, SPELL_HIVEZARA_SWARMER_LOOP_3 });
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetEntry() == NPC_HIVEZARA_SWARMER;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
uint32 loopSpells[3] = { SPELL_HIVEZARA_SWARMER_LOOP_1, SPELL_HIVEZARA_SWARMER_LOOP_2, SPELL_HIVEZARA_SWARMER_LOOP_3 };
|
||||
GetCaster()->CastSpell((Unit*)nullptr, Acore::Containers::SelectRandomContainerElement(loopSpells));
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_ayamiss_swarmer_start_loop::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_gen_ayamiss_swarmer_loop: public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_ayamiss_swarmer_loop);
|
||||
|
||||
public:
|
||||
spell_gen_ayamiss_swarmer_loop(uint32 pathId) : SpellScript(), _pathId(pathId) { }
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetEntry() == NPC_HIVEZARA_SWARMER;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->ToCreature()->GetMotionMaster()->Clear();
|
||||
GetCaster()->ToCreature()->GetMotionMaster()->MovePath(_pathId, false);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gen_ayamiss_swarmer_loop::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _pathId;
|
||||
};
|
||||
|
||||
void AddSC_boss_ayamiss()
|
||||
{
|
||||
RegisterRuinsOfAhnQirajCreatureAI(boss_ayamiss);
|
||||
RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_larva);
|
||||
RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_swarmer);
|
||||
RegisterSpellScript(spell_ayamiss_swarmer_teleport_trigger);
|
||||
RegisterSpellScript(spell_ayamiss_swarmer_swarm);
|
||||
RegisterSpellScript(spell_ayamiss_swarmer_start_loop);
|
||||
RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_1", (NPC_HIVEZARA_SWARMER + 5) * 10);
|
||||
RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_2", (NPC_HIVEZARA_SWARMER + 6) * 10);
|
||||
RegisterSpellScriptWithArgs(spell_gen_ayamiss_swarmer_loop, "spell_gen_ayamiss_swarmer_loop_3", (NPC_HIVEZARA_SWARMER + 7) * 10);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user