mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
fix(Scripts/HyjalSummit): Rewrite Battle for Mount Hyjal (#18512)
* arrays * summon_groups * part 2 lesgooo * holy frick it works??? * drafted * forgot to add co-author Co-Authored-By: Saltgurka <22568446+saltgurka@users.noreply.github.com> * thrall & tyrande * Update hyjal.cpp * trash * winterchill & anetheron * kazrogal & azgalor * Update rev_1708737709108426300.sql * entrance rp and scourge base * it worked thank you nyeriah and ayamiss the hunter from AQ20 cause I remembered that it had a similar mechanic and i went to check how to deal with it. did you know ayamiss was my turning point in my emulation "career"? it was a very interesting fight and i spent many hours researching it, leading to my discovery into how the swarmers work, if i did it nowadays i'd have found out immediately but it was a journey nonetheless Co-Authored-By: Andrew <47818697+Nyeriah@users.noreply.github.com> * Update rev_1708737709108426300.sql * no gem farming! * infernals * leftovers * doors * archimonde * Update rev_1708737709108426300.sql * jaina didnt reset gossip flag its over * crashfix Co-Authored-By: Andrew <47818697+Nyeriah@users.noreply.github.com> * Update instance_hyjal.cpp * no more dberrors * fix archimonde model and size scale was set to 0.4, also fixed the speed and attack time, as well as adding model info * Update rev_1708737709108426300.sql * Update rev_1708737709108426300.sql * more stuff * Update data/sql/updates/pending_db_world/rev_1708737709108426300.sql * fix: warning * fix: warning * buildfix don't need to assign anything, as long as it doesn't return null we're good * buildfix infernal has no DoAction behaviour so it's fine * Update data/sql/updates/pending_db_world/rev_1708737709108426300.sql * Update data/sql/updates/pending_db_world/rev_1708737709108426300.sql * yay Co-Authored-By: Dan <83884799+elthehablo@users.noreply.github.com> * a * looks nicer, less updates overall * crashfix? messy code gomenasai 🙇 * hide undesirables >:( * Update instance_hyjal.cpp Co-Authored-By: Anton Popovichenko <walkline.ua@gmail.com> --------- Co-authored-by: Gultask <sagemochi@hotmail.com> Co-authored-by: Saltgurka <22568446+saltgurka@users.noreply.github.com> Co-authored-by: Andrew <47818697+Nyeriah@users.noreply.github.com> Co-authored-by: Gultask <100873791+Gultask@users.noreply.github.com> Co-authored-by: Dan <83884799+elthehablo@users.noreply.github.com> Co-authored-by: Anton Popovichenko <walkline.ua@gmail.com>
This commit is contained in:
2282
data/sql/updates/pending_db_world/rev_1708737709108426300.sql
Normal file
2282
data/sql/updates/pending_db_world/rev_1708737709108426300.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,16 +18,16 @@
|
||||
#include "CreatureScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "hyjal.h"
|
||||
#include "hyjal_trash.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CARRION_SWARM = 31306,
|
||||
SPELL_SLEEP = 31298,
|
||||
SPELL_VAMPIRIC_AURA = 38196,
|
||||
SPELL_INFERNO = 31299,
|
||||
SPELL_IMMOLATION = 31303,
|
||||
SPELL_INFERNO_EFFECT = 31302,
|
||||
SPELL_CARRION_SWARM = 31306,
|
||||
SPELL_SLEEP = 31298,
|
||||
SPELL_INFERNO = 31299,
|
||||
SPELL_VAMPIRIC_AURA = 31317,
|
||||
SPELL_ENRAGE = 26662,
|
||||
SPELL_INFERNAL_STUN = 31302,
|
||||
SPELL_INFERNAL_IMMOLATION = 31304
|
||||
};
|
||||
|
||||
enum Texts
|
||||
@@ -37,232 +37,108 @@ enum Texts
|
||||
SAY_SWARM = 2,
|
||||
SAY_SLEEP = 3,
|
||||
SAY_INFERNO = 4,
|
||||
SAY_ONAGGRO = 5,
|
||||
SAY_ONSPAWN = 5,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
PATH_ANETHERON = 178080,
|
||||
POINT_COMBAT_START = 7
|
||||
};
|
||||
class boss_anetheron : public CreatureScript
|
||||
struct boss_anetheron : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_anetheron() : CreatureScript("boss_anetheron") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_anetheron(Creature* creature) : BossAI(creature, DATA_ANETHERON)
|
||||
{
|
||||
return GetHyjalAI<boss_anetheronAI>(creature);
|
||||
_recentlySpoken = false;
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_anetheronAI : public hyjal_trashAI
|
||||
void JustEngagedWith(Unit * who) override
|
||||
{
|
||||
boss_anetheronAI(Creature* creature) : hyjal_trashAI(creature)
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
scheduler.Schedule(20s, 28s, [this](TaskContext context)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
go = false;
|
||||
}
|
||||
|
||||
uint32 SwarmTimer;
|
||||
uint32 SleepTimer;
|
||||
uint32 AuraTimer;
|
||||
uint32 InfernoTimer;
|
||||
bool go;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
damageTaken = 0;
|
||||
SwarmTimer = 45000;
|
||||
SleepTimer = 60000;
|
||||
AuraTimer = 5000;
|
||||
InfernoTimer = 45000;
|
||||
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_ANETHERONEVENT, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_ANETHERONEVENT, IN_PROGRESS);
|
||||
|
||||
Talk(SAY_ONAGGRO);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_ONSLAY);
|
||||
}
|
||||
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId == POINT_COMBAT_START)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_JAINAPROUDMOORE));
|
||||
if (target && target->IsAlive())
|
||||
me->AddThreat(target, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
hyjal_trashAI::JustDied(killer);
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_ANETHERONEVENT, DONE);
|
||||
Talk(SAY_ONDEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (IsEvent)
|
||||
{
|
||||
//Must update npc_escortAI
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
if (!go)
|
||||
{
|
||||
go = true;
|
||||
me->GetMotionMaster()->MovePath(PATH_ANETHERON, false);
|
||||
}
|
||||
}
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SwarmTimer <= diff)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
|
||||
{
|
||||
DoCast(target, SPELL_CARRION_SWARM);
|
||||
}
|
||||
|
||||
SwarmTimer = urand(45000, 60000);
|
||||
if (DoCastRandomTarget(SPELL_CARRION_SWARM, 0, 60.f))
|
||||
Talk(SAY_SWARM);
|
||||
}
|
||||
else SwarmTimer -= diff;
|
||||
|
||||
if (SleepTimer <= diff)
|
||||
{
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
|
||||
target->CastSpell(target, SPELL_SLEEP, true);
|
||||
}
|
||||
SleepTimer = 60000;
|
||||
context.Repeat(10s, 15s);
|
||||
}).Schedule(25s, 32s, [this](TaskContext context)
|
||||
{
|
||||
if (DoCastRandomTarget(SPELL_SLEEP))
|
||||
Talk(SAY_SLEEP);
|
||||
}
|
||||
else SleepTimer -= diff;
|
||||
if (AuraTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_VAMPIRIC_AURA, true);
|
||||
AuraTimer = urand(10000, 20000);
|
||||
}
|
||||
else AuraTimer -= diff;
|
||||
if (InfernoTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), SPELL_INFERNO);
|
||||
InfernoTimer = 45000;
|
||||
|
||||
context.Repeat(35s, 48s);
|
||||
}).Schedule(30s, 48s, [this](TaskContext context)
|
||||
{
|
||||
if (DoCastRandomTarget(SPELL_INFERNO))
|
||||
Talk(SAY_INFERNO);
|
||||
}
|
||||
else InfernoTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class npc_towering_infernal : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_towering_infernal() : CreatureScript("npc_towering_infernal") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHyjalAI<npc_towering_infernalAI>(creature);
|
||||
context.Repeat(50s, 55s);
|
||||
}).Schedule(10min, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
context.Repeat(5min);
|
||||
});
|
||||
}
|
||||
|
||||
struct npc_towering_infernalAI : public ScriptedAI
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
npc_towering_infernalAI(Creature* creature) : ScriptedAI(creature)
|
||||
if (summon)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
AnetheronGUID = instance->GetGuidData(DATA_ANETHERON);
|
||||
summon->AI()->DoCast(SPELL_INFERNAL_STUN);
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
BossAI::JustSummoned(summon);
|
||||
}
|
||||
|
||||
uint32 ImmolationTimer;
|
||||
uint32 CheckTimer;
|
||||
ObjectGuid AnetheronGUID;
|
||||
InstanceScript* instance;
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
Talk(SAY_ONSPAWN, 1200ms);
|
||||
|
||||
void Reset() override
|
||||
if (action == DATA_ANETHERON)
|
||||
me->GetMotionMaster()->MovePath(urand(ALLIANCE_BASE_CHARGE_1, ALLIANCE_BASE_CHARGE_3), false);
|
||||
}
|
||||
|
||||
void PathEndReached(uint32 pathId) override
|
||||
{
|
||||
switch (pathId)
|
||||
{
|
||||
DoCast(me, SPELL_INFERNO_EFFECT);
|
||||
ImmolationTimer = 5000;
|
||||
CheckTimer = 5000;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
if (me->IsWithinDist(who, 50) && !me->IsInCombat() && me->IsValidAttackTarget(who))
|
||||
{
|
||||
AttackStart(who);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (CheckTimer <= diff)
|
||||
{
|
||||
if (AnetheronGUID)
|
||||
case ALLIANCE_BASE_CHARGE_1:
|
||||
case ALLIANCE_BASE_CHARGE_2:
|
||||
case ALLIANCE_BASE_CHARGE_3:
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
Creature* boss = ObjectAccessor::GetCreature(*me, AnetheronGUID);
|
||||
if (!boss || boss->isDead())
|
||||
{
|
||||
me->setDeathState(DeathState::JustDied);
|
||||
me->RemoveCorpse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
CheckTimer = 5000;
|
||||
}
|
||||
else CheckTimer -= diff;
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImmolationTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_IMMOLATION);
|
||||
ImmolationTimer = 5000;
|
||||
}
|
||||
else ImmolationTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
me->GetMotionMaster()->MovePath(urand(ALLIANCE_BASE_PATROL_1, ALLIANCE_BASE_PATROL_3), true);
|
||||
}, 1s);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (!_recentlySpoken && victim->IsPlayer())
|
||||
{
|
||||
Talk(SAY_ONSLAY);
|
||||
_recentlySpoken = true;
|
||||
|
||||
scheduler.Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
_recentlySpoken = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit * killer) override
|
||||
{
|
||||
Talk(SAY_ONDEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
|
||||
};
|
||||
|
||||
void AddSC_boss_anetheron()
|
||||
{
|
||||
new boss_anetheron();
|
||||
new npc_towering_infernal();
|
||||
RegisterHyjalAI(boss_anetheron);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,6 @@
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "hyjal.h"
|
||||
/* ScriptData
|
||||
SDName: Boss_Archimonde
|
||||
SD%Complete: 85
|
||||
SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented.
|
||||
SDCategory: Caverns of Time, Mount Hyjal
|
||||
EndScriptData */
|
||||
|
||||
enum Texts
|
||||
{
|
||||
@@ -40,7 +34,7 @@ enum Texts
|
||||
SAY_SOUL_CHARGE = 7,
|
||||
};
|
||||
|
||||
enum Spells
|
||||
enum ArchiSpells
|
||||
{
|
||||
SPELL_DENOUEMENT_WISP = 32124,
|
||||
SPELL_ANCIENT_SPARK = 39349,
|
||||
@@ -290,7 +284,7 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
instance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED);
|
||||
instance->SetData(DATA_ARCHIMONDE, NOT_STARTED);
|
||||
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
DoomfireSpiritGUID.Clear();
|
||||
@@ -354,12 +348,14 @@ public:
|
||||
Talk(SAY_AGGRO);
|
||||
DoZoneInCombat();
|
||||
|
||||
instance->SetData(DATA_ARCHIMONDEEVENT, IN_PROGRESS);
|
||||
instance->SetData(DATA_ARCHIMONDE, IN_PROGRESS);
|
||||
events.ScheduleEvent(EVENT_SPELL_AIR_BURST, urand(25000, 35000));
|
||||
events.ScheduleEvent(EVENT_SPELL_DOOMFIRE, urand(10000, 20000));
|
||||
events.ScheduleEvent(EVENT_SPELL_FEAR, 42000);
|
||||
events.ScheduleEvent(EVENT_SPELL_GRIP_OF_THE_LEGION, 2000);
|
||||
events.ScheduleEvent(EVENT_SPELL_FINGER_OF_DEATH, 1000);
|
||||
|
||||
instance->SetData(DATA_SPAWN_WAVES, 1);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
@@ -399,7 +395,7 @@ public:
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_ARCHIMONDEEVENT, DONE);
|
||||
instance->SetData(DATA_ARCHIMONDE, DONE);
|
||||
instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, me->GetEntry(), 1, me);
|
||||
|
||||
// Reset scheduled events
|
||||
@@ -418,6 +414,12 @@ public:
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
instance->SetData(DATA_RESET_NIGHT_ELF, 1);
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
bool CanUseFingerOfDeath()
|
||||
{
|
||||
// Cast finger of death below 10% health
|
||||
@@ -553,13 +555,13 @@ public:
|
||||
if (!me->IsInCombat())
|
||||
{
|
||||
// Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished.
|
||||
if ((instance->GetData(DATA_AZGALOREVENT) < DONE) && (me->IsVisible() || (me->GetFaction() != FACTION_FRIENDLY)))
|
||||
if ((instance->GetBossState(DATA_AZGALOR) != DONE) && (me->IsVisible() || (me->GetFaction() != FACTION_FRIENDLY)))
|
||||
{
|
||||
me->SetVisible(false);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
}
|
||||
|
||||
if ((instance->GetData(DATA_AZGALOREVENT) >= DONE) && (!me->IsVisible() || (me->GetFaction() == FACTION_FRIENDLY)))
|
||||
if ((instance->GetBossState(DATA_AZGALOR) == DONE) && (!me->IsVisible() || (me->GetFaction() == FACTION_FRIENDLY)))
|
||||
{
|
||||
me->SetFaction(FACTION_DRAGONKIN);
|
||||
me->SetVisible(true);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "CreatureScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "hyjal.h"
|
||||
#include "hyjal_trash.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
@@ -26,11 +25,7 @@ enum Spells
|
||||
SPELL_DOOM = 31347,
|
||||
SPELL_HOWL_OF_AZGALOR = 31344,
|
||||
SPELL_CLEAVE = 31345,
|
||||
SPELL_BERSERK = 26662,
|
||||
|
||||
SPELL_THRASH = 12787,
|
||||
SPELL_CRIPPLE = 31406,
|
||||
SPELL_WARSTOMP = 31408,
|
||||
SPELL_BERSERK = 26662
|
||||
};
|
||||
|
||||
enum Texts
|
||||
@@ -38,249 +33,88 @@ enum Texts
|
||||
SAY_ONDEATH = 0,
|
||||
SAY_ONSLAY = 1,
|
||||
SAY_DOOM = 2, // Not used?
|
||||
SAY_ONAGGRO = 3,
|
||||
SAY_ONSPAWN = 3,
|
||||
|
||||
SAY_ARCHIMONDE_INTRO = 8
|
||||
};
|
||||
|
||||
class boss_azgalor : public CreatureScript
|
||||
struct boss_azgalor : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_azgalor() : CreatureScript("boss_azgalor") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_azgalor(Creature* creature) : BossAI(creature, DATA_AZGALOR)
|
||||
{
|
||||
return GetHyjalAI<boss_azgalorAI>(creature);
|
||||
_recentlySpoken = false;
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_azgalorAI : public hyjal_trashAI
|
||||
void JustEngagedWith(Unit * who) override
|
||||
{
|
||||
boss_azgalorAI(Creature* creature) : hyjal_trashAI(creature)
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
scheduler.Schedule(10s, 16s, [this](TaskContext context)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
go = false;
|
||||
}
|
||||
|
||||
uint32 RainTimer;
|
||||
uint32 DoomTimer;
|
||||
uint32 HowlTimer;
|
||||
uint32 CleaveTimer;
|
||||
uint32 EnrageTimer;
|
||||
bool enraged;
|
||||
|
||||
bool go;
|
||||
|
||||
void Reset() override
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
context.Repeat(8s, 16s);
|
||||
}).Schedule(25s, [this](TaskContext context)
|
||||
{
|
||||
damageTaken = 0;
|
||||
RainTimer = 20000;
|
||||
DoomTimer = 50000;
|
||||
HowlTimer = 30000;
|
||||
CleaveTimer = 10000;
|
||||
EnrageTimer = 600000;
|
||||
enraged = false;
|
||||
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_AZGALOREVENT, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
DoCastRandomTarget(SPELL_RAIN_OF_FIRE, 0, 40.f);
|
||||
context.Repeat(15s);
|
||||
}).Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_AZGALOREVENT, IN_PROGRESS);
|
||||
DoCastAOE(SPELL_HOWL_OF_AZGALOR);
|
||||
context.Repeat(18s, 20s);
|
||||
}).Schedule(45s, 55s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_DOOM, 0, 100.f);
|
||||
Talk(SAY_DOOM);
|
||||
context.Repeat();
|
||||
}).Schedule(10min, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK);
|
||||
context.Repeat(5min);
|
||||
});
|
||||
}
|
||||
|
||||
Talk(SAY_ONAGGRO);
|
||||
}
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
Talk(SAY_ONSPAWN, 1200ms);
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
if (action == DATA_AZGALOR)
|
||||
me->GetMotionMaster()->MovePath(HORDE_BOSS_PATH, false);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit * victim) override
|
||||
{
|
||||
if (!_recentlySpoken && victim->IsPlayer())
|
||||
{
|
||||
Talk(SAY_ONSLAY);
|
||||
_recentlySpoken = true;
|
||||
|
||||
scheduler.Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
_recentlySpoken = false;
|
||||
});
|
||||
}
|
||||
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId == 7 && instance)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_THRALL));
|
||||
if (target && target->IsAlive())
|
||||
me->AddThreat(target, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
hyjal_trashAI::JustDied(killer);
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_AZGALOREVENT, DONE);
|
||||
Talk(SAY_ONDEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (IsEvent)
|
||||
{
|
||||
//Must update npc_escortAI
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
if (!go)
|
||||
{
|
||||
go = true;
|
||||
AddWaypoint(0, 5492.91f, -2404.61f, 1462.63f);
|
||||
AddWaypoint(1, 5531.76f, -2460.87f, 1469.55f);
|
||||
AddWaypoint(2, 5554.58f, -2514.66f, 1476.12f);
|
||||
AddWaypoint(3, 5554.16f, -2567.23f, 1479.90f);
|
||||
AddWaypoint(4, 5540.67f, -2625.99f, 1480.89f);
|
||||
AddWaypoint(5, 5508.16f, -2659.2f, 1480.15f);
|
||||
AddWaypoint(6, 5489.62f, -2704.05f, 1482.18f);
|
||||
AddWaypoint(7, 5457.04f, -2726.26f, 1485.10f);
|
||||
Start(false, true);
|
||||
SetDespawnAtEnd(false);
|
||||
}
|
||||
}
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (RainTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 30, true), SPELL_RAIN_OF_FIRE);
|
||||
RainTimer = 20000 + rand() % 15000;
|
||||
}
|
||||
else RainTimer -= diff;
|
||||
|
||||
if (DoomTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 1, 100, true), SPELL_DOOM);//never on tank
|
||||
DoomTimer = 45000 + rand() % 5000;
|
||||
}
|
||||
else DoomTimer -= diff;
|
||||
|
||||
if (HowlTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_HOWL_OF_AZGALOR);
|
||||
HowlTimer = 30000;
|
||||
}
|
||||
else HowlTimer -= diff;
|
||||
|
||||
if (CleaveTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
CleaveTimer = 10000 + rand() % 5000;
|
||||
}
|
||||
else CleaveTimer -= diff;
|
||||
|
||||
if (EnrageTimer < diff && !enraged)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
DoCast(me, SPELL_BERSERK, true);
|
||||
enraged = true;
|
||||
EnrageTimer = 600000;
|
||||
}
|
||||
else EnrageTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class npc_lesser_doomguard : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_lesser_doomguard() : CreatureScript("npc_lesser_doomguard") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHyjalAI<npc_lesser_doomguardAI>(creature);
|
||||
}
|
||||
|
||||
struct npc_lesser_doomguardAI : public hyjal_trashAI
|
||||
void JustDied(Unit * killer) override
|
||||
{
|
||||
npc_lesser_doomguardAI(Creature* creature) : hyjal_trashAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
AzgalorGUID = instance->GetGuidData(DATA_AZGALOR);
|
||||
}
|
||||
Talk(SAY_ONDEATH);
|
||||
// If Archimonde has not yet been initialized, this won't trigger
|
||||
if (Creature* archi = instance->GetCreature(DATA_ARCHIMONDE))
|
||||
archi->AI()->Talk(SAY_ARCHIMONDE_INTRO, 25000ms);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
uint32 CrippleTimer;
|
||||
uint32 WarstompTimer;
|
||||
uint32 CheckTimer;
|
||||
ObjectGuid AzgalorGUID;
|
||||
InstanceScript* instance;
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
CrippleTimer = 50000;
|
||||
WarstompTimer = 10000;
|
||||
DoCast(me, SPELL_THRASH);
|
||||
CheckTimer = 5000;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void WaypointReached(uint32 /*waypointId*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
if (me->IsWithinDist(who, 50) && !me->IsInCombat() && me->IsValidAttackTarget(who))
|
||||
AttackStart(who);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (CheckTimer <= diff)
|
||||
{
|
||||
if (AzgalorGUID)
|
||||
{
|
||||
Creature* boss = ObjectAccessor::GetCreature(*me, AzgalorGUID);
|
||||
if (!boss || boss->isDead())
|
||||
{
|
||||
me->setDeathState(DeathState::JustDied);
|
||||
me->RemoveCorpse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
CheckTimer = 5000;
|
||||
}
|
||||
else CheckTimer -= diff;
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (WarstompTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_WARSTOMP);
|
||||
WarstompTimer = 10000 + rand() % 5000;
|
||||
}
|
||||
else WarstompTimer -= diff;
|
||||
|
||||
if (CrippleTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), SPELL_CRIPPLE);
|
||||
CrippleTimer = 25000 + rand() % 5000;
|
||||
}
|
||||
else CrippleTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
void AddSC_boss_azgalor()
|
||||
{
|
||||
new boss_azgalor();
|
||||
new npc_lesser_doomguard();
|
||||
RegisterHyjalAI(boss_azgalor);
|
||||
}
|
||||
|
||||
@@ -21,21 +21,21 @@
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "hyjal.h"
|
||||
#include "hyjal_trash.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CLEAVE = 31436,
|
||||
SPELL_WARSTOMP = 31480,
|
||||
SPELL_MARK = 31447,
|
||||
SPELL_MARK_DAMAGE = 31463
|
||||
SPELL_MALEVOLENT_CLEAVE = 31436,
|
||||
SPELL_WAR_STOMP = 31480,
|
||||
SPELL_CRIPPLE = 31477,
|
||||
SPELL_MARK = 31447,
|
||||
SPELL_MARK_DAMAGE = 31463
|
||||
};
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_ONSLAY = 0,
|
||||
SAY_MARK = 1,
|
||||
SAY_ONAGGRO = 2,
|
||||
SAY_ONSPAWN = 2,
|
||||
};
|
||||
|
||||
enum Sounds
|
||||
@@ -43,124 +43,88 @@ enum Sounds
|
||||
SOUND_ONDEATH = 11018,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
PATH_KAZROGAL = 178880,
|
||||
POINT_COMBAT_START = 7
|
||||
};
|
||||
|
||||
class boss_kazrogal : public CreatureScript
|
||||
struct boss_kazrogal : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_kazrogal() : CreatureScript("boss_kazrogal") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_kazrogal(Creature* creature) : BossAI(creature, DATA_KAZROGAL)
|
||||
{
|
||||
return GetHyjalAI<boss_kazrogalAI>(creature);
|
||||
_recentlySpoken = false;
|
||||
_markCounter = 0;
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_kazrogalAI : public hyjal_trashAI
|
||||
void JustEngagedWith(Unit * who) override
|
||||
{
|
||||
boss_kazrogalAI(Creature* creature) : hyjal_trashAI(creature)
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
scheduler.Schedule(6s, 21s, [this](TaskContext context)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
go = false;
|
||||
}
|
||||
|
||||
uint32 CleaveTimer;
|
||||
uint32 WarStompTimer;
|
||||
uint32 MarkTimer;
|
||||
uint32 MarkTimerBase;
|
||||
bool go;
|
||||
|
||||
void Reset() override
|
||||
DoCastVictim(SPELL_MALEVOLENT_CLEAVE);
|
||||
context.Repeat();
|
||||
}).Schedule(12s, 18s, [this](TaskContext context)
|
||||
{
|
||||
damageTaken = 0;
|
||||
CleaveTimer = 5000;
|
||||
WarStompTimer = 15000;
|
||||
MarkTimer = 45000;
|
||||
MarkTimerBase = 45000;
|
||||
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_KAZROGALEVENT, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
if (SelectTarget(SelectTargetMethod::Random, 0, 12.f))
|
||||
{
|
||||
DoCastAOE(SPELL_WAR_STOMP);
|
||||
context.Repeat(15s, 30s);
|
||||
}
|
||||
else
|
||||
context.Repeat(1200ms);
|
||||
}).Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_KAZROGALEVENT, IN_PROGRESS);
|
||||
Talk(SAY_ONAGGRO);
|
||||
}
|
||||
DoCastRandomTarget(SPELL_CRIPPLE, 0, 20.f);
|
||||
context.Repeat(12s, 20s);
|
||||
}).Schedule(45s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK);
|
||||
Talk(SAY_MARK);
|
||||
context.Repeat(GetMarkRepeatTimer());
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
Milliseconds GetMarkRepeatTimer()
|
||||
{
|
||||
Milliseconds timer = 45000ms - (5000ms * _markCounter);
|
||||
if (timer <= 10000ms)
|
||||
return 10000ms;
|
||||
else
|
||||
return timer;
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
Talk(SAY_ONSPAWN, 1200ms);
|
||||
|
||||
if (action == DATA_KAZROGAL)
|
||||
me->GetMotionMaster()->MovePath(HORDE_BOSS_PATH, false);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit * victim) override
|
||||
{
|
||||
if (!_recentlySpoken && victim->IsPlayer())
|
||||
{
|
||||
Talk(SAY_ONSLAY);
|
||||
}
|
||||
_recentlySpoken = true;
|
||||
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId == POINT_COMBAT_START && instance)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_THRALL));
|
||||
if (target && target->IsAlive())
|
||||
me->AddThreat(target, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
hyjal_trashAI::JustDied(killer);
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_KAZROGALEVENT, DONE);
|
||||
DoPlaySoundToSet(me, SOUND_ONDEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (IsEvent)
|
||||
{
|
||||
//Must update npc_escortAI
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
if (!go)
|
||||
scheduler.Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
go = true;
|
||||
me->GetMotionMaster()->MovePath(PATH_KAZROGAL, false);
|
||||
}
|
||||
}
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (CleaveTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_CLEAVE);
|
||||
CleaveTimer = 6000 + rand() % 15000;
|
||||
}
|
||||
else CleaveTimer -= diff;
|
||||
|
||||
if (WarStompTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_WARSTOMP);
|
||||
WarStompTimer = 60000;
|
||||
}
|
||||
else WarStompTimer -= diff;
|
||||
|
||||
if (MarkTimer <= diff)
|
||||
{
|
||||
DoCastAOE(SPELL_MARK);
|
||||
|
||||
MarkTimerBase -= 5000;
|
||||
if (MarkTimerBase < 5500)
|
||||
MarkTimerBase = 5500;
|
||||
MarkTimer = MarkTimerBase;
|
||||
Talk(SAY_MARK);
|
||||
}
|
||||
else MarkTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
_recentlySpoken = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void JustDied(Unit * killer) override
|
||||
{
|
||||
me->PlayDirectSound(SOUND_ONDEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
uint8 _markCounter;
|
||||
};
|
||||
|
||||
class spell_mark_of_kazrogal : public SpellScriptLoader
|
||||
@@ -223,7 +187,7 @@ public:
|
||||
|
||||
void AddSC_boss_kazrogal()
|
||||
{
|
||||
new boss_kazrogal();
|
||||
RegisterHyjalAI(boss_kazrogal);
|
||||
new spell_mark_of_kazrogal();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
#include "CreatureScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "hyjal.h"
|
||||
#include "hyjal_trash.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FROST_ARMOR = 31256,
|
||||
SPELL_DEATH_AND_DECAY = 31258,
|
||||
SPELL_FROST_NOVA = 31250,
|
||||
SPELL_ICEBOLT = 31249
|
||||
SPELL_ICEBOLT = 31249,
|
||||
SPELL_ENRAGE = 26662
|
||||
};
|
||||
|
||||
enum Texts
|
||||
@@ -34,7 +34,7 @@ enum Texts
|
||||
SAY_ONSLAY = 1,
|
||||
SAY_DECAY = 2,
|
||||
SAY_NOVA = 3,
|
||||
SAY_ONAGGRO = 4
|
||||
SAY_ONSPAWN = 4
|
||||
};
|
||||
|
||||
enum Misc
|
||||
@@ -43,122 +43,101 @@ enum Misc
|
||||
POINT_COMBAT_START = 7
|
||||
};
|
||||
|
||||
class boss_rage_winterchill : public CreatureScript
|
||||
struct boss_rage_winterchill : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_rage_winterchill() : CreatureScript("boss_rage_winterchill") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_rage_winterchill(Creature* creature) : BossAI(creature, DATA_WINTERCHILL)
|
||||
{
|
||||
return GetHyjalAI<boss_rage_winterchillAI>(creature);
|
||||
_recentlySpoken = false;
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_rage_winterchillAI : public hyjal_trashAI
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
boss_rage_winterchillAI(Creature* creature) : hyjal_trashAI(creature)
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
scheduler.Schedule(18s, 24s, [this](TaskContext context)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
go = false;
|
||||
}
|
||||
|
||||
uint32 FrostArmorTimer;
|
||||
uint32 DecayTimer;
|
||||
uint32 NovaTimer;
|
||||
uint32 IceboltTimer;
|
||||
bool go;
|
||||
|
||||
void Reset() override
|
||||
DoCastSelf(SPELL_FROST_ARMOR);
|
||||
context.Repeat(30s, 45s);
|
||||
}).Schedule(5s, 9s, [this](TaskContext context)
|
||||
{
|
||||
damageTaken = 0;
|
||||
FrostArmorTimer = 37000;
|
||||
DecayTimer = 45000;
|
||||
NovaTimer = 15000;
|
||||
IceboltTimer = 10000;
|
||||
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_RAGEWINTERCHILLEVENT, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
DoCastRandomTarget(SPELL_ICEBOLT);
|
||||
context.Repeat(9s, 15s);
|
||||
}).Schedule(12s, 17s, [this](TaskContext context)
|
||||
{
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_RAGEWINTERCHILLEVENT, IN_PROGRESS);
|
||||
Talk(SAY_ONAGGRO);
|
||||
}
|
||||
if (SelectTarget(SelectTargetMethod::Random, 0, 20.f))
|
||||
{
|
||||
DoCastAOE(SPELL_FROST_NOVA);
|
||||
Talk(SAY_NOVA);
|
||||
context.Repeat(25s, 30s);
|
||||
}
|
||||
else
|
||||
context.Repeat(1200ms);
|
||||
}).Schedule(21s, 28s, [this](TaskContext context)
|
||||
{
|
||||
if (DoCastRandomTarget(SPELL_DEATH_AND_DECAY, 0, 40.f))
|
||||
Talk(SAY_DECAY);
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
context.Repeat(45s);
|
||||
}).Schedule(10min, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
context.Repeat(5min);
|
||||
});
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
Talk(SAY_ONSPAWN, 1200ms);
|
||||
|
||||
if (action == DATA_WINTERCHILL)
|
||||
me->GetMotionMaster()->MovePath(urand(ALLIANCE_BASE_CHARGE_1, ALLIANCE_BASE_CHARGE_3), false);
|
||||
}
|
||||
|
||||
void PathEndReached(uint32 pathId) override
|
||||
{
|
||||
switch (pathId)
|
||||
{
|
||||
case ALLIANCE_BASE_CHARGE_1:
|
||||
case ALLIANCE_BASE_CHARGE_2:
|
||||
case ALLIANCE_BASE_CHARGE_3:
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(urand(ALLIANCE_BASE_PATROL_1, ALLIANCE_BASE_PATROL_3), true);
|
||||
}, 1s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (!_recentlySpoken && victim->IsPlayer())
|
||||
{
|
||||
Talk(SAY_ONSLAY);
|
||||
}
|
||||
_recentlySpoken = true;
|
||||
|
||||
void WaypointReached(uint32 waypointId) override
|
||||
{
|
||||
if (waypointId == POINT_COMBAT_START && instance)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_JAINAPROUDMOORE));
|
||||
if (target && target->IsAlive())
|
||||
me->AddThreat(target, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
hyjal_trashAI::JustDied(killer);
|
||||
if (IsEvent)
|
||||
instance->SetData(DATA_RAGEWINTERCHILLEVENT, DONE);
|
||||
Talk(SAY_ONDEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (IsEvent)
|
||||
{
|
||||
//Must update npc_escortAI
|
||||
npc_escortAI::UpdateAI(diff);
|
||||
if (!go)
|
||||
scheduler.Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
go = true;
|
||||
me->GetMotionMaster()->MovePath(PATH_RAGE_WINTERCHILL, false);
|
||||
}
|
||||
}
|
||||
|
||||
//Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (FrostArmorTimer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_FROST_ARMOR);
|
||||
FrostArmorTimer = 40000 + rand() % 20000;
|
||||
}
|
||||
else FrostArmorTimer -= diff;
|
||||
if (DecayTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_DEATH_AND_DECAY);
|
||||
DecayTimer = 60000 + rand() % 20000;
|
||||
Talk(SAY_DECAY);
|
||||
}
|
||||
else DecayTimer -= diff;
|
||||
if (NovaTimer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FROST_NOVA);
|
||||
NovaTimer = 30000 + rand() % 15000;
|
||||
Talk(SAY_NOVA);
|
||||
}
|
||||
else NovaTimer -= diff;
|
||||
if (IceboltTimer <= diff)
|
||||
{
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 40, true), SPELL_ICEBOLT);
|
||||
IceboltTimer = 11000 + rand() % 20000;
|
||||
}
|
||||
else IceboltTimer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
_recentlySpoken = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_ONDEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
};
|
||||
|
||||
void AddSC_boss_rage_winterchill()
|
||||
{
|
||||
new boss_rage_winterchill();
|
||||
RegisterHyjalAI(boss_rage_winterchill);
|
||||
}
|
||||
|
||||
@@ -15,244 +15,656 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Hyjal
|
||||
SD%Complete: 80
|
||||
SDComment: gossip text id's unknown
|
||||
SDCategory: Caverns of Time, Mount Hyjal
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_jaina_proudmoore
|
||||
npc_thrall
|
||||
npc_tyrande_whisperwind
|
||||
EndContentData */
|
||||
|
||||
#include "CreatureScript.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "hyjalAI.h"
|
||||
#include "hyjal.h"
|
||||
|
||||
#define GOSSIP_ITEM_BEGIN_ALLY "My companions and I are with you, Lady Proudmoore."
|
||||
#define GOSSIP_ITEM_ANETHERON "We are ready for whatever Archimonde might send our way, Lady Proudmoore."
|
||||
enum Spells
|
||||
{
|
||||
// Jaina
|
||||
SPELL_MASS_TELEPORT = 16807,
|
||||
SPELL_SIMPLE_TELEPORT = 12980,
|
||||
SPELL_SALVATION = 31745,
|
||||
SPELL_BRILLIANCE_AURA = 31260,
|
||||
SPELL_BLIZZARD = 31266,
|
||||
SPELL_PYROBLAST = 31263,
|
||||
SPELL_SUMMON_ELEMENTALS = 31264,
|
||||
|
||||
#define GOSSIP_ITEM_BEGIN_HORDE "I am with you, Thrall."
|
||||
#define GOSSIP_ITEM_AZGALOR "We have nothing to fear."
|
||||
// Thrall
|
||||
SPELL_CHAIN_LIGHTNING = 31330,
|
||||
SPELL_FERAL_SPIRIT = 31331,
|
||||
|
||||
#define GOSSIP_ITEM_RETREAT "We can't keep this up. Let's retreat!"
|
||||
// Tyrande
|
||||
SPELL_STARFALL = 20687,
|
||||
SPELL_TRUESHOT_AURA = 31519,
|
||||
SPELL_SUMMON_TEARS_OF_THE_GODDESS = 39118,
|
||||
|
||||
#define GOSSIP_ITEM_TYRANDE "Aid us in defending Nordrassil"
|
||||
#define ITEM_TEAR_OF_GODDESS 24494
|
||||
// Ghoul
|
||||
SPELL_FRENZY = 31540,
|
||||
SPELL_CANNIBALIZE = 31537,
|
||||
|
||||
#define GOSSIP_ITEM_GM1 "[GM] Toggle Debug Timers"
|
||||
// Crypt Fiend
|
||||
SPELL_CRYPT_SCARABS = 31592,
|
||||
|
||||
class npc_jaina_proudmoore : public CreatureScript
|
||||
// Abomination
|
||||
SPELL_KNOCKDOWN = 31610,
|
||||
|
||||
// Necromancer (Ranged)
|
||||
SPELL_RAISE_DEAD_1 = 31617,
|
||||
SPELL_RAISE_DEAD_2 = 31624,
|
||||
SPELL_RAISE_DEAD_3 = 31625,
|
||||
SPELL_SHADOW_BOLT = 31627,
|
||||
|
||||
// Banshee (Ranged)
|
||||
SPELL_BANSHEE_CURSE = 31651,
|
||||
SPELL_ANTI_MAGIC_SHELL = 31662,
|
||||
SPELL_BANSHEE_WAIL = 38183,
|
||||
|
||||
// Gargoyle (Ranged)
|
||||
SPELL_GARGOYLE_STRIKE = 31664,
|
||||
|
||||
// Frost Wyrm (Ranged)
|
||||
SPELL_FROST_BREATH = 31688,
|
||||
|
||||
// Fel Stalker
|
||||
SPELL_MANA_BURN = 31729
|
||||
};
|
||||
|
||||
enum Talk
|
||||
{
|
||||
SAY_ATTACKED = 0,
|
||||
SAY_BEGIN = 1,
|
||||
SAY_INCOMING = 2,
|
||||
SAY_RALLY = 3,
|
||||
SAY_FAILURE = 4,
|
||||
SAY_SUCCESS = 5,
|
||||
SAY_DEATH = 6,
|
||||
SAY_TELEPORT = 7
|
||||
};
|
||||
|
||||
class npc_hyjal_jaina : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_jaina_proudmoore() : CreatureScript("npc_jaina_proudmoore") { }
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
hyjalAI* ai = CAST_AI(hyjalAI, creature->AI());
|
||||
switch (action)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF + 1:
|
||||
ai->StartEvent(player);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 2:
|
||||
ai->FirstBossDead = true;
|
||||
ai->WaveCount = 9;
|
||||
ai->StartEvent(player);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 3:
|
||||
ai->Retreat();
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF:
|
||||
ai->Debug = !ai->Debug;
|
||||
//LOG_DEBUG("scripts", "HyjalAI - Debug mode has been toggled");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
hyjalAI* ai = CAST_AI(hyjalAI, creature->AI());
|
||||
if (ai->EventBegun)
|
||||
return false;
|
||||
|
||||
uint32 RageEncounter = ai->GetInstanceData(DATA_RAGEWINTERCHILLEVENT);
|
||||
uint32 AnetheronEncounter = ai->GetInstanceData(DATA_ANETHERONEVENT);
|
||||
if (RageEncounter == NOT_STARTED)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN_ALLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
else if (RageEncounter == DONE && AnetheronEncounter == NOT_STARTED)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_ANETHERON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
else if (RageEncounter == DONE && AnetheronEncounter == DONE)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
|
||||
|
||||
if (player->IsGameMaster())
|
||||
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_ITEM_GM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
|
||||
SendGossipMenuFor(player, 907, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
npc_hyjal_jaina() : CreatureScript("npc_hyjal_jaina") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
if (!creature->GetInstanceScript())
|
||||
return nullptr;
|
||||
return new hyjalJainaAI(creature);
|
||||
}
|
||||
struct hyjalJainaAI : public ScriptedAI
|
||||
{
|
||||
hyjalJainaAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
hyjalAI* ai = new hyjalAI(creature);
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
if (!hyjal->GetData(DATA_WAVE_STATUS))
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
}
|
||||
|
||||
ai->Reset();
|
||||
ai->EnterEvadeMode();
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_ATTACKED);
|
||||
|
||||
ai->Spells[0].SpellId = SPELL_BLIZZARD;
|
||||
ai->Spells[0].Cooldown = urand(15000, 35000);
|
||||
ai->Spells[0].TargetType = TARGETTYPE_RANDOM;
|
||||
scheduler.Schedule(15s, 35s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_BLIZZARD);
|
||||
context.Repeat();
|
||||
}).Schedule(2s, 9s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_PYROBLAST);
|
||||
context.Repeat();
|
||||
}).Schedule(15s, 45s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_ELEMENTALS);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
ai->Spells[1].SpellId = SPELL_PYROBLAST;
|
||||
ai->Spells[1].Cooldown = urand(5500, 9500);
|
||||
ai->Spells[1].TargetType = TARGETTYPE_RANDOM;
|
||||
void IsSummonedBy(WorldObject* /*summoner*/) override
|
||||
{
|
||||
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
DoCastSelf(SPELL_SIMPLE_TELEPORT, true);
|
||||
|
||||
ai->Spells[2].SpellId = SPELL_SUMMON_ELEMENTALS;
|
||||
ai->Spells[2].Cooldown = urand(15000, 45000);
|
||||
ai->Spells[2].TargetType = TARGETTYPE_SELF;
|
||||
// Should wait 2400ms
|
||||
me->SetFacingTo(1.082104f);
|
||||
DoCastSelf(SPELL_MASS_TELEPORT);
|
||||
Talk(SAY_TELEPORT);
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
hyjal->SetData(DATA_HORDE_RETREAT, 0);
|
||||
}
|
||||
|
||||
return ai;
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
hyjal->SetData(DATA_RESET_ALLIANCE, 0);
|
||||
}
|
||||
|
||||
void PathEndReached(uint32 /*pathId*/) override
|
||||
{
|
||||
DoCastSelf(SPELL_MASS_TELEPORT);
|
||||
Talk(SAY_TELEPORT);
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
hyjal->SetData(DATA_ALLIANCE_RETREAT, 0);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
bool OnGossipSelect(Player* /*player*/ , Creature* creature, uint32 /*sender*/, uint32 /*action*/) override
|
||||
{
|
||||
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
if (InstanceScript* hyjal = creature->GetInstanceScript())
|
||||
{
|
||||
if (hyjal->GetBossState(DATA_WINTERCHILL) != DONE || hyjal->GetBossState(DATA_ANETHERON) != DONE)
|
||||
{
|
||||
hyjal->SetData(DATA_RESET_WAVES, 0);
|
||||
hyjal->SetData(DATA_SPAWN_WAVES, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
creature->AI()->Talk(SAY_SUCCESS);
|
||||
creature->GetMotionMaster()->MovePath(JAINA_RETREAT_PATH, false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class npc_thrall : public CreatureScript
|
||||
class npc_hyjal_thrall : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_thrall() : CreatureScript("npc_thrall") { }
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
hyjalAI* ai = CAST_AI(hyjalAI, creature->AI());
|
||||
ai->DeSpawnVeins();//despawn the alliance veins
|
||||
switch (action)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF + 1:
|
||||
ai->StartEvent(player);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 2:
|
||||
ai->FirstBossDead = true;
|
||||
ai->WaveCount = 9;
|
||||
ai->StartEvent(player);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 3:
|
||||
ai->Retreat();
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF:
|
||||
ai->Debug = !ai->Debug;
|
||||
//LOG_DEBUG("scripts", "HyjalAI - Debug mode has been toggled");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
hyjalAI* ai = CAST_AI(hyjalAI, creature->AI());
|
||||
if (ai->EventBegun)
|
||||
return false;
|
||||
|
||||
uint32 AnetheronEvent = ai->GetInstanceData(DATA_ANETHERONEVENT);
|
||||
// Only let them start the Horde phases if Anetheron is dead.
|
||||
if (AnetheronEvent == DONE && ai->GetInstanceData(DATA_ALLIANCE_RETREAT))
|
||||
{
|
||||
uint32 KazrogalEvent = ai->GetInstanceData(DATA_KAZROGALEVENT);
|
||||
uint32 AzgalorEvent = ai->GetInstanceData(DATA_AZGALOREVENT);
|
||||
if (KazrogalEvent == NOT_STARTED)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN_HORDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
else if (KazrogalEvent == DONE && AzgalorEvent == NOT_STARTED)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_AZGALOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
else if (AzgalorEvent == DONE)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
|
||||
}
|
||||
|
||||
if (player->IsGameMaster())
|
||||
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_ITEM_GM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
|
||||
SendGossipMenuFor(player, 907, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
npc_hyjal_thrall() : CreatureScript("npc_hyjal_thrall") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
if (!creature->GetInstanceScript())
|
||||
return nullptr;
|
||||
return new hyjalThrallAI(creature);
|
||||
}
|
||||
struct hyjalThrallAI : public ScriptedAI
|
||||
{
|
||||
hyjalThrallAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
hyjalAI* ai = new hyjalAI(creature);
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
if (!hyjal->GetData(DATA_WAVE_STATUS))
|
||||
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
}
|
||||
|
||||
ai->Reset();
|
||||
ai->EnterEvadeMode();
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_ATTACKED);
|
||||
|
||||
ai->Spells[0].SpellId = SPELL_CHAIN_LIGHTNING;
|
||||
ai->Spells[0].Cooldown = urand(3000, 8000);
|
||||
ai->Spells[0].TargetType = TARGETTYPE_VICTIM;
|
||||
scheduler.Schedule(13s, 19s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_CHAIN_LIGHTNING);
|
||||
context.Repeat();
|
||||
}).Schedule(15s, 45s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_FERAL_SPIRIT);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
ai->Spells[1].SpellId = SPELL_SUMMON_DIRE_WOLF;
|
||||
ai->Spells[1].Cooldown = urand(6000, 41000);
|
||||
ai->Spells[1].TargetType = TARGETTYPE_RANDOM;
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
hyjal->SetData(DATA_RESET_HORDE, 0);
|
||||
}
|
||||
|
||||
return ai;
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
bool OnGossipSelect(Player* /*player*/, Creature* creature, uint32 /*sender*/, uint32 /*action*/) override
|
||||
{
|
||||
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
if (InstanceScript* hyjal = creature->GetInstanceScript())
|
||||
{
|
||||
if (hyjal->GetBossState(DATA_KAZROGAL) != DONE || hyjal->GetBossState(DATA_AZGALOR) != DONE)
|
||||
{
|
||||
hyjal->SetData(DATA_RESET_WAVES, 0);
|
||||
hyjal->SetData(DATA_SPAWN_WAVES, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
creature->AI()->Talk(SAY_SUCCESS);
|
||||
creature->SummonCreatureGroup(0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class npc_tyrande_whisperwind : public CreatureScript
|
||||
class npc_hyjal_tyrande : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_tyrande_whisperwind() : CreatureScript("npc_tyrande_whisperwind") { }
|
||||
npc_hyjal_tyrande() : CreatureScript("npc_hyjal_tyrande") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
if (!creature->GetInstanceScript())
|
||||
return nullptr;
|
||||
|
||||
hyjalAI* ai = new hyjalAI(creature);
|
||||
ai->Reset();
|
||||
ai->EnterEvadeMode();
|
||||
return ai;
|
||||
return new hyjalTyrandeAI(creature);
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
||||
struct hyjalTyrandeAI : public ScriptedAI
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
if (action == GOSSIP_ACTION_INFO_DEF)
|
||||
hyjalTyrandeAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_TEAR_OF_GODDESS, 1);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
if (Item* item = player->StoreNewItem(dest, ITEM_TEAR_OF_GODDESS, true))
|
||||
player->SendNewItem(item, 1, true, false, true);
|
||||
|
||||
SendGossipMenuFor(player, 907, creature->GetGUID());
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_ATTACKED);
|
||||
|
||||
scheduler.Schedule(60s, 70s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_STARFALL);
|
||||
context.Repeat();
|
||||
}).Schedule(4s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_TRUESHOT_AURA);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
if (InstanceScript* hyjal = me->GetInstanceScript())
|
||||
hyjal->SetData(DATA_RESET_NIGHT_ELF, 0);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/) override
|
||||
{
|
||||
hyjalAI* ai = CAST_AI(hyjalAI, creature->AI());
|
||||
uint32 AzgalorEvent = ai->GetInstanceData(DATA_AZGALOREVENT);
|
||||
|
||||
// Only let them get item if Azgalor is dead.
|
||||
if (AzgalorEvent == DONE && !player->HasItemCount(ITEM_TEAR_OF_GODDESS))
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_TYRANDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
SendGossipMenuFor(player, 907, creature->GetGUID());
|
||||
CloseGossipMenuFor(player);
|
||||
creature->AI()->DoCast(player, SPELL_SUMMON_TEARS_OF_THE_GODDESS, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct npc_hyjal_ground_trash : public ScriptedAI
|
||||
{
|
||||
npc_hyjal_ground_trash(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
switch (me->GetEntry())
|
||||
{
|
||||
case NPC_NECRO:
|
||||
case NPC_BANSH:
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
me->GetMotionMaster()->MoveChase(who, 30.0f);
|
||||
break;
|
||||
default:
|
||||
ScriptedAI::AttackStart(who);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
switch (me->GetEntry())
|
||||
{
|
||||
case NPC_GHOUL:
|
||||
{
|
||||
scheduler.Schedule(3s, 7s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_FRENZY);
|
||||
context.Repeat(15s, 30s);
|
||||
}).Schedule(1200ms, [this](TaskContext context)
|
||||
{
|
||||
if (me->GetHealthPct() <= 7)
|
||||
DoCastSelf(SPELL_CANNIBALIZE);
|
||||
else
|
||||
context.Repeat();
|
||||
});
|
||||
break;
|
||||
}
|
||||
case NPC_CRYPT:
|
||||
{
|
||||
scheduler.Schedule(0s, 2400ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_CRYPT_SCARABS);
|
||||
context.Repeat(2400ms, 8s);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case NPC_ABOMI:
|
||||
{
|
||||
scheduler.Schedule(13s, 17s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCKDOWN);
|
||||
context.Repeat(16s, 25s);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case NPC_NECRO:
|
||||
{
|
||||
scheduler.Schedule(0s, 2400ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
context.Repeat(2400ms, 4800ms);
|
||||
}).Schedule(5s, 10s, [this](TaskContext context)
|
||||
{
|
||||
// TODO: Should target corpse, and skeletons should spawn at the target
|
||||
switch (urand(1, 3))
|
||||
{
|
||||
case 1:
|
||||
DoCastSelf(SPELL_RAISE_DEAD_1);
|
||||
break;
|
||||
case 2:
|
||||
DoCastSelf(SPELL_RAISE_DEAD_2);
|
||||
break;
|
||||
case 3:
|
||||
DoCastSelf(SPELL_RAISE_DEAD_3);
|
||||
break;
|
||||
}
|
||||
context.Repeat(10s, 20s);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case NPC_BANSH:
|
||||
{
|
||||
scheduler.Schedule(10s, 15s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
DoCast(target, SPELL_BANSHEE_CURSE);
|
||||
context.Repeat(18s, 24s);
|
||||
}).Schedule(5s, 15s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_ANTI_MAGIC_SHELL);
|
||||
context.Repeat(18s, 24s);
|
||||
}).Schedule(0s, 1s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_BANSHEE_WAIL);
|
||||
context.Repeat(1800ms, 2200ms);
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
case NPC_STALK:
|
||||
{
|
||||
scheduler.Schedule(3s, 6s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(POWER_MANA), 30.f, true)))
|
||||
DoCast(target, SPELL_MANA_BURN);
|
||||
context.Repeat(6s, 9s);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
me->setActive(true);
|
||||
switch (action)
|
||||
{
|
||||
case DATA_WINTERCHILL:
|
||||
case DATA_ANETHERON:
|
||||
case DATA_ALLIANCE_RETREAT:
|
||||
me->GetMotionMaster()->MovePath(urand(ALLIANCE_BASE_CHARGE_1, ALLIANCE_BASE_CHARGE_3), false);
|
||||
break;
|
||||
case DATA_KAZROGAL:
|
||||
case DATA_AZGALOR:
|
||||
case DATA_HORDE_RETREAT:
|
||||
me->GetMotionMaster()->MovePath(urand(HORDE_BASE_CHARGE_1, HORDE_BASE_CHARGE_3), false);
|
||||
break;
|
||||
case DATA_ARCHIMONDE:
|
||||
me->GetMotionMaster()->MovePath(urand(NIGHT_ELF_BASE_CHARGE_1, NIGHT_ELF_BASE_CHARGE_3), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
switch (pathId)
|
||||
{
|
||||
case ALLIANCE_BASE_CHARGE_1:
|
||||
case ALLIANCE_BASE_CHARGE_2:
|
||||
case ALLIANCE_BASE_CHARGE_3:
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(urand(ALLIANCE_BASE_PATROL_1, ALLIANCE_BASE_PATROL_3), true);
|
||||
}, 1s);
|
||||
break;
|
||||
case HORDE_BASE_CHARGE_1:
|
||||
case HORDE_BASE_CHARGE_2:
|
||||
case HORDE_BASE_CHARGE_3:
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(urand(HORDE_BASE_PATROL_1, HORDE_BASE_PATROL_3), true);
|
||||
}, 1s);
|
||||
break;
|
||||
case NIGHT_ELF_BASE_CHARGE_1:
|
||||
case NIGHT_ELF_BASE_CHARGE_2:
|
||||
case NIGHT_ELF_BASE_CHARGE_3:
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->GetMotionMaster()->MoveRandom(5.f);
|
||||
}, 1s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct npc_hyjal_gargoyle : public ScriptedAI
|
||||
{
|
||||
npc_hyjal_gargoyle(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
me->GetMotionMaster()->MoveChase(who, 25.0f);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
scheduler.Schedule(0s, 2s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_GARGOYLE_STRIKE);
|
||||
context.Repeat(2s, 3s);
|
||||
});
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
me->setActive(true);
|
||||
switch (action)
|
||||
{
|
||||
case DATA_ALLIANCE_RETREAT:
|
||||
// TODO: Set up to attack NPC_BUILD
|
||||
break;
|
||||
case DATA_KAZROGAL:
|
||||
case DATA_AZGALOR:
|
||||
case DATA_HORDE_RETREAT:
|
||||
if (me->GetPositionX() < 5500.f)
|
||||
me->GetMotionMaster()->MovePath(urand(GARGOYLE_PATH_FORTRESS_1, GARGOYLE_PATH_FORTRESS_3), false);
|
||||
else
|
||||
me->GetMotionMaster()->MovePath(urand(GARGOYLE_PATH_TROLL_CAMP_1, GARGOYLE_PATH_TROLL_CAMP_3), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PathEndReached(uint32 /* pathId */) override
|
||||
{
|
||||
// TODO: Do they do something special after finishing the path?
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->GetMotionMaster()->MoveRandom(30.f);
|
||||
}, 1s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct npc_hyjal_frost_wyrm : public ScriptedAI
|
||||
{
|
||||
npc_hyjal_frost_wyrm(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
me->GetMotionMaster()->MoveChase(who, 25.0f);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
scheduler.Schedule(0s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_GARGOYLE_STRIKE);
|
||||
context.Repeat(3500ms, 4s);
|
||||
});
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
me->setActive(true);
|
||||
switch (action)
|
||||
{
|
||||
case DATA_KAZROGAL:
|
||||
case DATA_AZGALOR:
|
||||
case DATA_HORDE_RETREAT:
|
||||
if (me->GetPositionX() < 5500.f)
|
||||
me->GetMotionMaster()->MovePath(FROST_WYRM_FORTRESS, false);
|
||||
else
|
||||
me->GetMotionMaster()->MovePath(FROST_WYRM_TROLL_CAMP, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PathEndReached(uint32 pathId) override
|
||||
{
|
||||
if (pathId == FROST_WYRM_FORTRESS)
|
||||
{
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(FROST_WYRM_FORTRESS_PATROL, true);
|
||||
}, 1s);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void AddSC_hyjal()
|
||||
{
|
||||
new npc_jaina_proudmoore();
|
||||
new npc_thrall();
|
||||
new npc_tyrande_whisperwind();
|
||||
new npc_hyjal_jaina();
|
||||
new npc_hyjal_thrall();
|
||||
new npc_hyjal_tyrande();
|
||||
RegisterHyjalAI(npc_hyjal_ground_trash);
|
||||
RegisterHyjalAI(npc_hyjal_gargoyle);
|
||||
RegisterHyjalAI(npc_hyjal_frost_wyrm);
|
||||
}
|
||||
|
||||
@@ -34,68 +34,148 @@ enum HyjalBosses
|
||||
|
||||
enum DataTypes
|
||||
{
|
||||
DATA_ANETHERON = 1,
|
||||
DATA_ANETHERONEVENT = 2,
|
||||
DATA_ARCHIMONDE = 3,
|
||||
DATA_ARCHIMONDEEVENT = 4,
|
||||
DATA_AZGALOR = 5,
|
||||
DATA_AZGALOREVENT = 6,
|
||||
DATA_JAINAPROUDMOORE = 7,
|
||||
DATA_KAZROGAL = 8,
|
||||
DATA_KAZROGALEVENT = 9,
|
||||
DATA_RAGEWINTERCHILL = 10,
|
||||
DATA_RAGEWINTERCHILLEVENT = 11,
|
||||
DATA_THRALL = 12,
|
||||
DATA_TYRANDEWHISPERWIND = 13,
|
||||
DATA_TRASH = 14,
|
||||
DATA_RESET_TRASH_COUNT = 15,
|
||||
DATA_ALLIANCE_RETREAT = 16,
|
||||
DATA_HORDE_RETREAT = 17,
|
||||
DATA_RAIDDAMAGE = 18,
|
||||
DATA_RESET_RAIDDAMAGE = 19,
|
||||
TYPE_RETREAT = 20
|
||||
DATA_WINTERCHILL = 1,
|
||||
DATA_ANETHERON = 2,
|
||||
DATA_KAZROGAL = 3,
|
||||
DATA_AZGALOR = 4,
|
||||
DATA_ARCHIMONDE = 5,
|
||||
|
||||
DATA_ALLIANCE_RETREAT = 11,
|
||||
DATA_HORDE_RETREAT = 12,
|
||||
|
||||
DATA_JAINA = 13,
|
||||
DATA_THRALL = 14,
|
||||
DATA_TYRANDE = 15,
|
||||
|
||||
DATA_SPAWN_WAVES = 20,
|
||||
DATA_SPAWN_INFERNALS = 21,
|
||||
DATA_RESET_ALLIANCE = 22,
|
||||
DATA_RESET_HORDE = 23,
|
||||
DATA_RESET_NIGHT_ELF = 24,
|
||||
DATA_RESET_WAVES = 25,
|
||||
DATA_WAVE_STATUS = 26,
|
||||
DATA_BOSS_WAVE = 27
|
||||
};
|
||||
|
||||
enum WorldStateIds
|
||||
enum HyjalWorldStateIds
|
||||
{
|
||||
WORLD_STATE_WAVES = 2842,
|
||||
WORLD_STATE_ENEMY = 2453,
|
||||
WORLD_STATE_ENEMYCOUNT = 2454
|
||||
};
|
||||
|
||||
enum CreaturesIds
|
||||
enum HyjalCreaturesIds
|
||||
{
|
||||
// Trash Mobs summoned in waves
|
||||
NECROMANCER = 17899,
|
||||
ABOMINATION = 17898,
|
||||
GHOUL = 17895,
|
||||
BANSHEE = 17905,
|
||||
CRYPT_FIEND = 17897,
|
||||
GARGOYLE = 17906,
|
||||
FROST_WYRM = 17907,
|
||||
GIANT_INFERNAL = 17908,
|
||||
FEL_STALKER = 17916,
|
||||
NPC_GHOUL = 17895,
|
||||
NPC_CRYPT = 17897,
|
||||
NPC_ABOMI = 17898,
|
||||
NPC_NECRO = 17899,
|
||||
NPC_BANSH = 17905,
|
||||
NPC_GARGO = 17906,
|
||||
NPC_FROST = 17907,
|
||||
NPC_INFER = 17908,
|
||||
NPC_STALK = 17916,
|
||||
NPC_BUILD = 18304, // Serverside creature? Not found in CreateObject packets, but seen as targets
|
||||
|
||||
JAINA = 17772,
|
||||
THRALL = 17852,
|
||||
TYRANDE = 17948,
|
||||
// Alliance Base
|
||||
NPC_JAINA = 17772,
|
||||
NPC_ALLIANCE_PEASANT = 17931,
|
||||
NPC_ALLIANCE_KNIGHT = 17920,
|
||||
NPC_ALLIANCE_FOOTMAN = 17919,
|
||||
NPC_ALLIANCE_RIFLEMAN = 17921,
|
||||
NPC_ALLIANCE_PRIEST = 17928,
|
||||
NPC_ALLIANCE_SORCERESS = 17922,
|
||||
|
||||
// Bosses summoned after every 8 waves
|
||||
RAGE_WINTERCHILL = 17767,
|
||||
ANETHERON = 17808,
|
||||
KAZROGAL = 17888,
|
||||
AZGALOR = 17842,
|
||||
ARCHIMONDE = 17968,
|
||||
// Horde Base
|
||||
NPC_THRALL = 17852,
|
||||
NPC_HORDE_HEADHUNTER = 17934,
|
||||
NPC_HORDE_SHAMAN = 17936,
|
||||
NPC_HORDE_GRUNT = 17932,
|
||||
NPC_HORDE_HEALING_WARD = 18036,
|
||||
NPC_TAUREN_WARRIOR = 17933,
|
||||
NPC_HORDE_WITCH_DOCTOR = 17935,
|
||||
NPC_HORDE_PEON = 17937,
|
||||
NPC_INFERNAL_RELAY = 18242,
|
||||
NPC_INFERNAL_TARGET = 21075,
|
||||
|
||||
// Night Elf Base
|
||||
NPC_TYRANDE = 17948,
|
||||
NPC_DRUID_OF_THE_TALON = 3794,
|
||||
NPC_DRUID_OF_THE_CLAW = 3795,
|
||||
NPC_NELF_ANCIENT_PROT = 18487,
|
||||
NPC_NELF_ANCIENT_OF_LORE = 18486,
|
||||
NPC_NELF_ANCIENT_OF_WAR = 18485,
|
||||
NPC_NELF_ARCHER = 17943,
|
||||
NPC_NELF_HUNTRESS = 17945,
|
||||
NPC_DRYAD = 17944,
|
||||
|
||||
// Bosses
|
||||
NPC_WINTERCHILL = 17767,
|
||||
NPC_ANETHERON = 17808,
|
||||
NPC_KAZROGAL = 17888,
|
||||
NPC_AZGALOR = 17842,
|
||||
NPC_ARCHIMONDE = 17968,
|
||||
NPC_WORLD_TRIGGER_TINY = 21987
|
||||
};
|
||||
|
||||
enum GameobjectIds
|
||||
enum HyjalGameobjectIds
|
||||
{
|
||||
GO_HORDE_ENCAMPMENT_PORTAL = 182060,
|
||||
GO_NIGHT_ELF_VILLAGE_PORTAL = 182061,
|
||||
GO_ANCIENT_GEM = 185557,
|
||||
GO_ANCIENT_VEIN = 185557,
|
||||
GO_ROARING_FLAME = 182592
|
||||
GO_FLAME = 182260
|
||||
};
|
||||
|
||||
enum HyjalMisc
|
||||
{
|
||||
MAX_WAVES_STANDARD = 9,
|
||||
MAX_WAVES_RETREAT = 3,
|
||||
MAX_WAVES_NIGHT_ELF = 1,
|
||||
START_WAVE_WINTERCHILL = 0,
|
||||
START_WAVE_ANETHERON = 9,
|
||||
START_WAVE_KAZROGAL = 18,
|
||||
START_WAVE_AZGALOR = 27,
|
||||
START_WAVE_ALLIANCE_RETREAT = 36,
|
||||
START_WAVE_HORDE_RETREAT = 39,
|
||||
START_WAVE_NIGHT_ELF = 42,
|
||||
|
||||
CONTEXT_GROUP_WAVES = 1
|
||||
};
|
||||
|
||||
enum HyjalPaths
|
||||
{
|
||||
ALLIANCE_BASE_CHARGE_1 = 177721,
|
||||
ALLIANCE_BASE_CHARGE_2 = 177722,
|
||||
ALLIANCE_BASE_CHARGE_3 = 177723,
|
||||
ALLIANCE_BASE_PATROL_1 = 177724,
|
||||
ALLIANCE_BASE_PATROL_2 = 177725,
|
||||
ALLIANCE_BASE_PATROL_3 = 177726,
|
||||
JAINA_RETREAT_PATH = 177727,
|
||||
|
||||
HORDE_BASE_CHARGE_1 = 178521,
|
||||
HORDE_BASE_CHARGE_2 = 178522,
|
||||
HORDE_BASE_CHARGE_3 = 178523,
|
||||
HORDE_BASE_PATROL_1 = 178524,
|
||||
HORDE_BASE_PATROL_2 = 178525,
|
||||
HORDE_BASE_PATROL_3 = 178526,
|
||||
|
||||
NIGHT_ELF_BASE_CHARGE_1 = 179481,
|
||||
NIGHT_ELF_BASE_CHARGE_2 = 179482,
|
||||
NIGHT_ELF_BASE_CHARGE_3 = 179483,
|
||||
|
||||
GARGOYLE_PATH_TROLL_CAMP_1 = 179061,
|
||||
GARGOYLE_PATH_TROLL_CAMP_2 = 179062,
|
||||
GARGOYLE_PATH_TROLL_CAMP_3 = 179063,
|
||||
GARGOYLE_PATH_FORTRESS_1 = 179064,
|
||||
GARGOYLE_PATH_FORTRESS_2 = 179065,
|
||||
GARGOYLE_PATH_FORTRESS_3 = 179066,
|
||||
|
||||
FROST_WYRM_TROLL_CAMP = 179071,
|
||||
FROST_WYRM_FORTRESS = 179072,
|
||||
FROST_WYRM_FORTRESS_PATROL = 179073,
|
||||
|
||||
HORDE_BOSS_PATH = 178527
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
@@ -104,4 +184,6 @@ inline AI* GetHyjalAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, HyjalScriptName);
|
||||
}
|
||||
|
||||
#define RegisterHyjalAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetHyjalAI)
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SC_HYJALAI_H
|
||||
#define SC_HYJALAI_H
|
||||
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "hyjal.h"
|
||||
|
||||
#define HYJAL_AI_MAX_SPELLS 3
|
||||
|
||||
enum SpellIds
|
||||
{
|
||||
SPELL_TELEPORT_VISUAL = 41232,
|
||||
SPELL_MASS_TELEPORT = 16807,
|
||||
|
||||
//Spells for Jaina
|
||||
SPELL_BRILLIANCE_AURA = 31260, // The database must handle this spell via creature_addon(it should, but is removed in evade..)
|
||||
SPELL_BLIZZARD = 31266,
|
||||
SPELL_PYROBLAST = 31263,
|
||||
SPELL_SUMMON_ELEMENTALS = 31264,
|
||||
|
||||
//Thrall spells
|
||||
SPELL_CHAIN_LIGHTNING = 31330,
|
||||
SPELL_SUMMON_DIRE_WOLF = 31331
|
||||
};
|
||||
|
||||
struct Wave
|
||||
{
|
||||
uint32 Mob[18]; // Stores Creature Entries to be summoned in Waves
|
||||
uint32 WaveTimer; // The timer before the next wave is summoned
|
||||
bool IsBoss; // Simply used to inform the wave summoner that the next wave contains a boss to halt all waves after that
|
||||
};
|
||||
|
||||
const Wave AllianceWaves[] = // Waves that will be summoned in the Alliance Base
|
||||
{
|
||||
// Rage Winterchill Wave 1-8
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, 0, 0, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, 0, 0, 0, 0}, 180000, false},
|
||||
// All 8 Waves are summoned, summon Rage Winterchill, next few waves are for Anetheron
|
||||
{{RAGE_WINTERCHILL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true},
|
||||
// Anetheron Wave 1-8
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, 0, 0, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0}, 120000, false},
|
||||
{{CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, BANSHEE, BANSHEE, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, GHOUL, GHOUL, 0, 0, 0, 0}, 120000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 0, 0}, 180000, false},
|
||||
// All 8 Waves are summoned, summon Anatheron
|
||||
{{ANETHERON, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true}
|
||||
};
|
||||
|
||||
const Wave HordeWaves[] = // Waves that are summoned in the Horde base
|
||||
{
|
||||
// Kaz'Rogal Wave 1-8
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, NECROMANCER, NECROMANCER, 0, 0, 0, 0}, 180000, false},
|
||||
{{CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, NECROMANCER, NECROMANCER, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0}, 180000, false},
|
||||
{{GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, FROST_WYRM, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, FROST_WYRM, 0, 0, 0, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0}, 240000, false},
|
||||
// All 8 Waves are summoned, summon Kaz'Rogal, next few waves are for Azgalor
|
||||
{{KAZROGAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true},
|
||||
// Azgalor Wave 1-8
|
||||
{{ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, FROST_WYRM, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, GARGOYLE, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GHOUL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, 0, 0, 0, 0}, 180000, false},
|
||||
{{GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, 0, 0, 0, 0}, 180000, false},
|
||||
{{FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, FEL_STALKER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, 0, 0, 0, 0}, 180000, false},
|
||||
{{NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, NECROMANCER, BANSHEE, BANSHEE, BANSHEE, BANSHEE, BANSHEE, BANSHEE, 0, 0, 0, 0, 0, 0}, 180000, false},
|
||||
{{GHOUL, GHOUL, CRYPT_FIEND, CRYPT_FIEND, FEL_STALKER, FEL_STALKER, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, GIANT_INFERNAL, 0, 0, 0, 0}, 180000, false},
|
||||
{{CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, CRYPT_FIEND, FEL_STALKER, FEL_STALKER, ABOMINATION, ABOMINATION, ABOMINATION, ABOMINATION, BANSHEE, BANSHEE, BANSHEE, BANSHEE, NECROMANCER, NECROMANCER, 0, 0}, 240000, false},
|
||||
// All 8 Waves are summoned, summon Azgalor
|
||||
{{AZGALOR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, true}
|
||||
};
|
||||
|
||||
enum TargetType // Used in the spell cast system for the AI
|
||||
{
|
||||
TARGETTYPE_SELF = 0,
|
||||
TARGETTYPE_RANDOM = 1,
|
||||
TARGETTYPE_VICTIM = 2,
|
||||
};
|
||||
|
||||
enum YellId
|
||||
{
|
||||
ATTACKED = 0, // Used when attacked and set in combat
|
||||
BEGIN = 1, // Used when the event is begun
|
||||
INCOMING = 2, // Used to warn the raid that another wave phase is coming
|
||||
RALLY = 3, // Used to rally the raid and warn that the next wave has been summoned
|
||||
FAILURE = 4, // Used when raid has failed (unsure where to place)
|
||||
SUCCESS = 5, // Used when the raid has sucessfully defeated a wave phase
|
||||
DEATH = 6, // Used on death
|
||||
};
|
||||
|
||||
struct hyjalAI : public npc_escortAI
|
||||
{
|
||||
hyjalAI(Creature* creature);
|
||||
|
||||
void Reset() override; // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override; // Send creature back to spawn location and evade.
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override; // Used to reset cooldowns for our spells and to inform the raid that we're under attack
|
||||
|
||||
void UpdateAI(uint32 diff) override; // Called to summon waves, check for boss deaths and to cast our spells.
|
||||
|
||||
void JustDied(Unit* /*killer*/) override; // Called on death, informs the raid that they have failed.
|
||||
|
||||
void SetFaction(uint32 _faction) // Set the faction to either Alliance or Horde in Hyjal
|
||||
{
|
||||
Faction = _faction;
|
||||
}
|
||||
|
||||
void Retreat(); // "Teleport" (teleport visual + set invisible) all friendly creatures away from the base.
|
||||
|
||||
void SpawnVeins();
|
||||
void DeSpawnVeins();
|
||||
void JustSummoned(Creature* summoned) override;
|
||||
void SummonedCreatureDespawn(Creature* summoned) override;
|
||||
void HideNearPos(float x, float y);
|
||||
void RespawnNearPos(float x, float y);
|
||||
void WaypointReached(uint32 waypointId) override;
|
||||
void DoOverrun(uint32 faction, const uint32 diff);
|
||||
void MoveInLineOfSight(Unit* who) override;
|
||||
|
||||
void SummonCreature(uint32 entry, float Base[4][3]); // Summons a creature for that wave in that base
|
||||
|
||||
// Summons the next wave, calls SummonCreature
|
||||
void SummonNextWave(const Wave wave[18], uint32 Count, float Base[4][3]);
|
||||
|
||||
void StartEvent(Player* player); // Begins the event by gossip click
|
||||
|
||||
uint32 GetInstanceData(uint32 Event); // Gets instance data for this instance, used to check if raid has gotten past a certain point and can access the next phase
|
||||
|
||||
public:
|
||||
InstanceScript* instance;
|
||||
|
||||
ObjectGuid PlayerGUID;
|
||||
ObjectGuid BossGUID[2];
|
||||
ObjectGuid VeinGUID[14];
|
||||
|
||||
uint32 NextWaveTimer;
|
||||
uint32 WaveCount;
|
||||
uint32 CheckTimer;
|
||||
uint32 Faction;
|
||||
uint32 EnemyCount;
|
||||
uint32 RetreatTimer;
|
||||
|
||||
bool EventBegun;
|
||||
bool FirstBossDead;
|
||||
bool SecondBossDead;
|
||||
bool Summon;
|
||||
bool bRetreat;
|
||||
bool Debug;
|
||||
bool VeinsSpawned[2];
|
||||
uint8 InfernalCount;
|
||||
SummonList Summons;
|
||||
bool Overrun;
|
||||
bool Teleported;
|
||||
bool WaitForTeleport;
|
||||
uint32 TeleportTimer;
|
||||
uint32 OverrunCounter;
|
||||
uint32 OverrunCounter2;
|
||||
uint32 InfernalPoint;
|
||||
uint32 RespawnTimer;
|
||||
bool DoRespawn;
|
||||
bool DoHide;
|
||||
bool IsDummy;
|
||||
uint32 MassTeleportTimer;
|
||||
bool DoMassTeleport;
|
||||
ObjectGuid DummyGuid;
|
||||
|
||||
struct Spell
|
||||
{
|
||||
uint32 SpellId;
|
||||
uint32 Cooldown;
|
||||
uint32 TargetType;
|
||||
} Spells[HYJAL_AI_MAX_SPELLS];
|
||||
|
||||
private:
|
||||
uint32 SpellTimer[3];
|
||||
//GuidList CreatureList;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SC_HYJAL_TRASH_AI_H
|
||||
#define SC_HYJAL_TRASH_AI_H
|
||||
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "hyjal.h"
|
||||
|
||||
#define MINRAIDDAMAGE 700000//minimal damage before trash can drop loot and reputation, resets if faction leader dies
|
||||
|
||||
struct hyjal_trashAI : public npc_escortAI
|
||||
{
|
||||
hyjal_trashAI(Creature* creature);
|
||||
|
||||
void UpdateAI(uint32 diff) override;
|
||||
|
||||
void JustDied(Unit* /*killer*/) override;
|
||||
|
||||
void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType, SpellSchoolMask) override;
|
||||
|
||||
public:
|
||||
InstanceScript* instance;
|
||||
bool IsEvent;
|
||||
uint32 Delay;
|
||||
uint32 LastOverronPos;
|
||||
bool IsOverrun;
|
||||
bool SetupOverrun;
|
||||
uint32 OverrunType;
|
||||
uint8 faction;
|
||||
bool useFlyPath;
|
||||
uint32 damageTaken;
|
||||
float DummyTarget[3];
|
||||
|
||||
//private:
|
||||
};
|
||||
#endif
|
||||
@@ -15,19 +15,12 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Instance_Mount_Hyjal
|
||||
SD%Complete: 100
|
||||
SDComment: Instance Data Scripts and functions to acquire mobs and set encounter status for use in various Hyjal Scripts
|
||||
SDCategory: Caverns of Time, Mount Hyjal
|
||||
EndScriptData */
|
||||
|
||||
#include "Chat.h"
|
||||
#include "InstanceMapScript.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Opcodes.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "hyjal_trash.h"
|
||||
#include "hyjal.h"
|
||||
|
||||
/* Battle of Mount Hyjal encounters:
|
||||
0 - Rage Winterchill event
|
||||
@@ -37,7 +30,49 @@ EndScriptData */
|
||||
4 - Archimonde event
|
||||
*/
|
||||
|
||||
#define YELL_EFFORTS "All of your efforts have been in vain, for the draining of the World Tree has already begun. Soon the heart of your world will beat no more."
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_HORDE_ENCAMPMENT_PORTAL, DATA_ANETHERON, DOOR_TYPE_PASSAGE },
|
||||
{ GO_NIGHT_ELF_VILLAGE_PORTAL, DATA_AZGALOR, DOOR_TYPE_PASSAGE },
|
||||
{ 0, 0, DOOR_TYPE_PASSAGE }
|
||||
};
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_WINTERCHILL, DATA_WINTERCHILL },
|
||||
{ NPC_ANETHERON, DATA_ANETHERON },
|
||||
{ NPC_KAZROGAL, DATA_KAZROGAL },
|
||||
{ NPC_AZGALOR, DATA_AZGALOR },
|
||||
{ NPC_ARCHIMONDE, DATA_ARCHIMONDE },
|
||||
{ NPC_THRALL, DATA_THRALL },
|
||||
{ NPC_JAINA, DATA_JAINA },
|
||||
{ NPC_TYRANDE, DATA_TYRANDE },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
ObjectData const objectData[] =
|
||||
{
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
Milliseconds hyjalWaveTimers[4][MAX_WAVES_STANDARD]
|
||||
{
|
||||
{ 130000ms, 130000ms, 130000ms, 130000ms, 130000ms, 130000ms, 130000ms, 190000ms, 0ms }, // Winterchill
|
||||
{ 130000ms, 130000ms, 130000ms, 130000ms, 130000ms, 130000ms, 130000ms, 190000ms, 0ms }, // Anetheron
|
||||
{ 130000ms, 155000ms, 130000ms, 155000ms, 130000ms, 130000ms, 155000ms, 225000ms, 0ms }, // Kaz'rogal
|
||||
{ 130000ms, 190000ms, 190000ms, 190000ms, 130000ms, 155000ms, 190000ms, 225000ms, 0ms } // Azgalor
|
||||
};
|
||||
|
||||
Milliseconds hyjalRetreatTimers[2][MAX_WAVES_RETREAT]
|
||||
{
|
||||
{ 10000ms, 6000ms , 0ms }, // Alliance
|
||||
{ 10000ms, 40000ms, 0ms } // Horde
|
||||
};
|
||||
|
||||
Milliseconds hyjalNightElfWaveTimers[1][MAX_WAVES_NIGHT_ELF]
|
||||
{
|
||||
{ 0ms }
|
||||
};
|
||||
|
||||
class instance_hyjal : public InstanceMapScript
|
||||
{
|
||||
@@ -51,206 +86,383 @@ public:
|
||||
|
||||
struct instance_mount_hyjal_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_mount_hyjal_InstanceMapScript(Map* map) : InstanceScript(map) { }
|
||||
instance_mount_hyjal_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, objectData);
|
||||
}
|
||||
|
||||
void Initialize() override
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
|
||||
|
||||
m_uiAncientGemGUID.clear();
|
||||
|
||||
RaidDamage = 0;
|
||||
Trash = 0;
|
||||
hordeRetreat = 0;
|
||||
allianceRetreat = 0;
|
||||
|
||||
ArchiYell = false;
|
||||
}
|
||||
|
||||
bool IsEncounterInProgress() const override
|
||||
{
|
||||
for (uint8 i = 0; i < EncounterCount; ++i)
|
||||
if (m_auiEncounter[i] == IN_PROGRESS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
_bossWave = 0;
|
||||
_retreat = 0;
|
||||
trash = 0;
|
||||
_currentWave = 0;
|
||||
_encounterNPCs.clear();
|
||||
_baseAlliance.clear();
|
||||
_baseHorde.clear();
|
||||
_infernalTargets.clear();
|
||||
_baseNightElf.clear();
|
||||
_roaringFlameAlliance.clear();
|
||||
_roaringFlameHorde.clear();
|
||||
_ancientGemAlliance.clear();
|
||||
_ancientGemHorde.clear();
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_HORDE_ENCAMPMENT_PORTAL:
|
||||
HordeGate = go->GetGUID();
|
||||
if (allianceRetreat)
|
||||
HandleGameObject(ObjectGuid::Empty, true, go);
|
||||
else
|
||||
HandleGameObject(ObjectGuid::Empty, false, go);
|
||||
break;
|
||||
case GO_NIGHT_ELF_VILLAGE_PORTAL:
|
||||
ElfGate = go->GetGUID();
|
||||
if (hordeRetreat)
|
||||
HandleGameObject(ObjectGuid::Empty, true, go);
|
||||
else
|
||||
HandleGameObject(ObjectGuid::Empty, false, go);
|
||||
break;
|
||||
case GO_ANCIENT_GEM:
|
||||
m_uiAncientGemGUID.push_back(go->GetGUID());
|
||||
if (go->GetPositionY() > -2500.f)
|
||||
_ancientGemAlliance.insert(go->GetGUID());
|
||||
else
|
||||
_ancientGemHorde.insert(go->GetGUID());
|
||||
go->DespawnOrUnsummon();
|
||||
break;
|
||||
case GO_FLAME:
|
||||
if (go->GetPositionX() < 5360.f)
|
||||
_roaringFlameAlliance.insert(go->GetGUID());
|
||||
else
|
||||
_roaringFlameHorde.insert(go->GetGUID());
|
||||
go->DespawnOrUnsummon();
|
||||
break;
|
||||
}
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case RAGE_WINTERCHILL:
|
||||
RageWinterchill = creature->GetGUID();
|
||||
// Alliance base
|
||||
case NPC_ALLIANCE_PEASANT:
|
||||
case NPC_ALLIANCE_KNIGHT:
|
||||
case NPC_ALLIANCE_FOOTMAN:
|
||||
case NPC_ALLIANCE_RIFLEMAN:
|
||||
case NPC_ALLIANCE_PRIEST:
|
||||
case NPC_ALLIANCE_SORCERESS:
|
||||
case NPC_JAINA:
|
||||
_baseAlliance.insert(creature->GetGUID());
|
||||
break;
|
||||
case ANETHERON:
|
||||
Anetheron = creature->GetGUID();
|
||||
// Horde base
|
||||
case NPC_HORDE_HEADHUNTER:
|
||||
case NPC_HORDE_SHAMAN:
|
||||
case NPC_HORDE_GRUNT:
|
||||
case NPC_HORDE_HEALING_WARD:
|
||||
case NPC_TAUREN_WARRIOR:
|
||||
case NPC_HORDE_WITCH_DOCTOR:
|
||||
case NPC_HORDE_PEON:
|
||||
case NPC_THRALL:
|
||||
_baseHorde.insert(creature->GetGUID());
|
||||
break;
|
||||
case KAZROGAL:
|
||||
Kazrogal = creature->GetGUID();
|
||||
// Elf base
|
||||
case NPC_DRUID_OF_THE_TALON:
|
||||
case NPC_DRUID_OF_THE_CLAW:
|
||||
case NPC_NELF_ANCIENT_PROT:
|
||||
case NPC_NELF_ANCIENT_OF_LORE:
|
||||
case NPC_NELF_ANCIENT_OF_WAR:
|
||||
case NPC_NELF_ARCHER:
|
||||
case NPC_NELF_HUNTRESS:
|
||||
case NPC_DRYAD:
|
||||
case NPC_TYRANDE:
|
||||
_baseNightElf.insert(creature->GetGUID());
|
||||
break;
|
||||
case AZGALOR:
|
||||
Azgalor = creature->GetGUID();
|
||||
|
||||
case NPC_INFERNAL_TARGET:
|
||||
_infernalTargets.push_back(creature->GetGUID());
|
||||
break;
|
||||
case ARCHIMONDE:
|
||||
Archimonde = creature->GetGUID();
|
||||
break;
|
||||
case JAINA:
|
||||
JainaProudmoore = creature->GetGUID();
|
||||
break;
|
||||
case THRALL:
|
||||
Thrall = creature->GetGUID();
|
||||
break;
|
||||
case TYRANDE:
|
||||
TyrandeWhisperwind = creature->GetGUID();
|
||||
|
||||
case NPC_WINTERCHILL:
|
||||
case NPC_ANETHERON:
|
||||
case NPC_KAZROGAL:
|
||||
case NPC_AZGALOR:
|
||||
case NPC_NECRO:
|
||||
case NPC_ABOMI:
|
||||
case NPC_GHOUL:
|
||||
case NPC_BANSH:
|
||||
case NPC_CRYPT:
|
||||
case NPC_STALK:
|
||||
case NPC_GARGO:
|
||||
case NPC_FROST:
|
||||
case NPC_INFER:
|
||||
if (_bossWave)
|
||||
creature->AI()->DoAction(_bossWave);
|
||||
else if (_retreat)
|
||||
creature->AI()->DoAction(_retreat);
|
||||
|
||||
if (creature->IsSummon() && _bossWave)
|
||||
{
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, ++trash); // Update the instance wave count on new trash spawn
|
||||
_encounterNPCs.insert(creature->GetGUID()); // Used for despawning on wipe
|
||||
}
|
||||
break;
|
||||
}
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 identifier) const override
|
||||
void OnUnitDeath(Unit* unit) override
|
||||
{
|
||||
switch (identifier)
|
||||
{
|
||||
case DATA_RAGEWINTERCHILL:
|
||||
return RageWinterchill;
|
||||
case DATA_ANETHERON:
|
||||
return Anetheron;
|
||||
case DATA_KAZROGAL:
|
||||
return Kazrogal;
|
||||
case DATA_AZGALOR:
|
||||
return Azgalor;
|
||||
case DATA_ARCHIMONDE:
|
||||
return Archimonde;
|
||||
case DATA_JAINAPROUDMOORE:
|
||||
return JainaProudmoore;
|
||||
case DATA_THRALL:
|
||||
return Thrall;
|
||||
case DATA_TYRANDEWHISPERWIND:
|
||||
return TyrandeWhisperwind;
|
||||
}
|
||||
InstanceScript::OnUnitDeath(unit);
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
if (Creature* creature = unit->ToCreature())
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_NECRO:
|
||||
case NPC_ABOMI:
|
||||
case NPC_GHOUL:
|
||||
case NPC_BANSH:
|
||||
case NPC_CRYPT:
|
||||
case NPC_GARGO:
|
||||
case NPC_FROST:
|
||||
case NPC_INFER:
|
||||
case NPC_STALK:
|
||||
if (unit->ToCreature()->IsSummon())
|
||||
{
|
||||
if (_bossWave)
|
||||
{
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, --trash); // Update the instance wave count on new trash death
|
||||
_encounterNPCs.erase(unit->ToCreature()->GetGUID()); // Used for despawning on wipe
|
||||
|
||||
if (trash == 0) // It can reach negatives if trash spawned after a retreat are killed, it shouldn't affect anything. Also happens on retail
|
||||
SetData(DATA_SPAWN_WAVES, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NPC_WINTERCHILL:
|
||||
case NPC_ANETHERON:
|
||||
case NPC_KAZROGAL:
|
||||
case NPC_AZGALOR:
|
||||
if (Creature* jaina = GetCreature(DATA_JAINA))
|
||||
jaina->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
if (Creature* thrall = GetCreature(DATA_THRALL))
|
||||
thrall->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
||||
SetData(DATA_RESET_WAVES, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_RAGEWINTERCHILLEVENT:
|
||||
m_auiEncounter[0] = data;
|
||||
break;
|
||||
case DATA_ANETHERONEVENT:
|
||||
m_auiEncounter[1] = data;
|
||||
break;
|
||||
case DATA_KAZROGALEVENT:
|
||||
m_auiEncounter[2] = data;
|
||||
break;
|
||||
case DATA_AZGALOREVENT:
|
||||
{
|
||||
m_auiEncounter[3] = data;
|
||||
if (data == DONE)
|
||||
{
|
||||
if (ArchiYell)
|
||||
break;
|
||||
|
||||
ArchiYell = true;
|
||||
|
||||
Creature* creature = instance->GetCreature(Azgalor);
|
||||
if (creature)
|
||||
{
|
||||
Creature* unit = creature->SummonCreature(NPC_WORLD_TRIGGER_TINY, creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
|
||||
|
||||
Map* map = creature->GetMap();
|
||||
if (map->IsDungeon() && unit)
|
||||
{
|
||||
unit->SetVisible(false);
|
||||
Map::PlayerList const& PlayerList = map->GetPlayers();
|
||||
if (PlayerList.IsEmpty())
|
||||
return;
|
||||
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
{
|
||||
if (Player* player = i->GetSource())
|
||||
{
|
||||
WorldPacket packet;
|
||||
ChatHandler::BuildChatPacket(packet, CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, unit, player, YELL_EFFORTS);
|
||||
player->SendDirectMessage(&packet);
|
||||
player->PlayDirectSound(10986, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DATA_ARCHIMONDEEVENT:
|
||||
m_auiEncounter[4] = data;
|
||||
break;
|
||||
case DATA_RESET_TRASH_COUNT:
|
||||
Trash = 0;
|
||||
break;
|
||||
case DATA_TRASH:
|
||||
if (data)
|
||||
Trash = data;
|
||||
else
|
||||
Trash--;
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, Trash);
|
||||
break;
|
||||
case TYPE_RETREAT:
|
||||
if (data == SPECIAL)
|
||||
{
|
||||
if (!m_uiAncientGemGUID.empty())
|
||||
{
|
||||
for (ObjectGuid const& guid : m_uiAncientGemGUID)
|
||||
{
|
||||
//don't know how long it expected
|
||||
DoRespawnGameObject(guid, DAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DATA_ALLIANCE_RETREAT:
|
||||
allianceRetreat = data;
|
||||
HandleGameObject(HordeGate, true);
|
||||
_bossWave = 0;
|
||||
_retreat = DATA_ALLIANCE_RETREAT;
|
||||
// Spawn Ancient Gems
|
||||
for (ObjectGuid const& guid : _ancientGemAlliance)
|
||||
instance->GetGameObject(guid)->Respawn();
|
||||
|
||||
// Move all alliance NPCs near Jaina (only happens in this base, not Horde's)
|
||||
if (Creature* jaina = GetCreature(DATA_JAINA))
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseAlliance)
|
||||
{
|
||||
if (instance->GetCreature(guid) && instance->GetCreature(guid)->IsAlive())
|
||||
{
|
||||
float x, y, z;
|
||||
jaina->GetNearPoint(instance->GetCreature(guid), x, y, z, 10.f, 0, jaina->GetAngle(instance->GetCreature(guid)));
|
||||
instance->GetCreature(guid)->SetWalk(true);
|
||||
instance->GetCreature(guid)->GetMotionMaster()->MovePoint(1, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Despawn all alliance NPCs
|
||||
_scheduler.Schedule(21000ms, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseAlliance)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
// Spawn Roaring Flame after a delay
|
||||
_scheduler.Schedule(30s, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _roaringFlameAlliance)
|
||||
instance->GetGameObject(guid)->Respawn();
|
||||
});
|
||||
});
|
||||
|
||||
// Spawn Overrun waves
|
||||
ScheduleWaves(1ms, START_WAVE_ALLIANCE_RETREAT, MAX_WAVES_RETREAT, hyjalRetreatTimers[0]);
|
||||
|
||||
SaveToDB();
|
||||
break;
|
||||
case DATA_HORDE_RETREAT:
|
||||
hordeRetreat = data;
|
||||
HandleGameObject(ElfGate, true);
|
||||
_bossWave = 0;
|
||||
_retreat = DATA_HORDE_RETREAT;
|
||||
for (ObjectGuid const& guid : _ancientGemHorde)
|
||||
instance->GetGameObject(guid)->Respawn();
|
||||
|
||||
if (Creature* jaina = GetCreature(DATA_JAINA))
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseHorde)
|
||||
{
|
||||
if (instance->GetCreature(guid) && instance->GetCreature(guid)->IsAlive())
|
||||
{
|
||||
float x, y, z;
|
||||
jaina->GetNearPoint(instance->GetCreature(guid), x, y, z, 10.f, 0, jaina->GetAngle(instance->GetCreature(guid)));
|
||||
instance->GetCreature(guid)->SetWalk(true);
|
||||
instance->GetCreature(guid)->GetMotionMaster()->MovePoint(1, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_scheduler.Schedule(21000ms, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseHorde)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
_scheduler.Schedule(30s, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _roaringFlameHorde)
|
||||
instance->GetGameObject(guid)->Respawn();
|
||||
});
|
||||
});
|
||||
|
||||
ScheduleWaves(1ms, START_WAVE_HORDE_RETREAT, MAX_WAVES_RETREAT, hyjalRetreatTimers[1]);
|
||||
|
||||
SaveToDB();
|
||||
break;
|
||||
case DATA_RAIDDAMAGE:
|
||||
RaidDamage += data;
|
||||
if (RaidDamage >= MINRAIDDAMAGE)
|
||||
RaidDamage = MINRAIDDAMAGE;
|
||||
case DATA_SPAWN_WAVES:
|
||||
_retreat = 0;
|
||||
if (GetBossState(DATA_WINTERCHILL) != DONE)
|
||||
{
|
||||
if (!_bossWave)
|
||||
for (ObjectGuid const& guid : _baseAlliance)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
_bossWave = DATA_WINTERCHILL;
|
||||
ScheduleWaves(1ms, START_WAVE_WINTERCHILL, MAX_WAVES_STANDARD, hyjalWaveTimers[DATA_WINTERCHILL - 1]);
|
||||
}
|
||||
else if (GetBossState(DATA_ANETHERON) != DONE)
|
||||
{
|
||||
if (!_bossWave)
|
||||
for (ObjectGuid const& guid : _baseAlliance)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
_bossWave = DATA_ANETHERON;
|
||||
ScheduleWaves(1ms, START_WAVE_ANETHERON, MAX_WAVES_STANDARD, hyjalWaveTimers[DATA_ANETHERON - 1]);
|
||||
}
|
||||
else if (GetBossState(DATA_KAZROGAL) != DONE)
|
||||
{
|
||||
if (!_bossWave)
|
||||
for (ObjectGuid const& guid : _baseHorde)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
_bossWave = DATA_KAZROGAL;
|
||||
ScheduleWaves(1ms, START_WAVE_KAZROGAL, MAX_WAVES_STANDARD, hyjalWaveTimers[DATA_KAZROGAL - 1]);
|
||||
}
|
||||
else if (GetBossState(DATA_AZGALOR) != DONE)
|
||||
{
|
||||
if (!_bossWave)
|
||||
for (ObjectGuid const& guid : _baseHorde)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
_bossWave = DATA_AZGALOR;
|
||||
ScheduleWaves(1ms, START_WAVE_AZGALOR, MAX_WAVES_STANDARD, hyjalWaveTimers[DATA_AZGALOR - 1]);
|
||||
}
|
||||
else if (GetBossState(DATA_ARCHIMONDE) != DONE)
|
||||
{
|
||||
_bossWave = DATA_ARCHIMONDE;
|
||||
ScheduleWaves(1ms, START_WAVE_NIGHT_ELF, MAX_WAVES_NIGHT_ELF, hyjalNightElfWaveTimers[0]);
|
||||
}
|
||||
break;
|
||||
case DATA_RESET_RAIDDAMAGE:
|
||||
RaidDamage = 0;
|
||||
case DATA_SPAWN_INFERNALS:
|
||||
{
|
||||
uint8 doubleInfernalCount = 2;
|
||||
// Uses SmartAI
|
||||
for (ObjectGuid const& guid : _infernalTargets)
|
||||
{
|
||||
if (Creature* target = instance->GetCreature(guid))
|
||||
{
|
||||
if (doubleInfernalCount > 0)
|
||||
{
|
||||
target->AI()->SetData(DATA_SPAWN_INFERNALS, 2); // Spawns 2 infernals, as there are only 6 spawns, some summon 2
|
||||
doubleInfernalCount--;
|
||||
}
|
||||
else
|
||||
target->AI()->SetData(DATA_SPAWN_INFERNALS, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DATA_RESET_ALLIANCE:
|
||||
for (ObjectGuid const& guid : _baseAlliance)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
for (ObjectGuid const& guid : _encounterNPCs)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
_scheduler.Schedule(300s, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseAlliance)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
});
|
||||
|
||||
SetData(DATA_RESET_WAVES, 0);
|
||||
break;
|
||||
case DATA_RESET_HORDE:
|
||||
for (ObjectGuid const& guid : _baseHorde)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
for (ObjectGuid const& guid : _encounterNPCs)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
_scheduler.Schedule(300s, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseHorde)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
});
|
||||
|
||||
SetData(DATA_RESET_WAVES, 0);
|
||||
break;
|
||||
case DATA_RESET_NIGHT_ELF:
|
||||
for (ObjectGuid const& guid : _baseNightElf)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
for (ObjectGuid const& guid : _encounterNPCs)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->DespawnOrUnsummon();
|
||||
|
||||
GetCreature(DATA_ARCHIMONDE)->DespawnOrUnsummon();
|
||||
|
||||
_scheduler.Schedule(300s, [this](TaskContext)
|
||||
{
|
||||
for (ObjectGuid const& guid : _baseNightElf)
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
creature->Respawn();
|
||||
|
||||
if (Creature* archi = GetCreature(DATA_ARCHIMONDE))
|
||||
archi->Respawn();
|
||||
});
|
||||
|
||||
SetData(DATA_RESET_WAVES, 0);
|
||||
break;
|
||||
case DATA_RESET_WAVES:
|
||||
_scheduler.CancelGroup(CONTEXT_GROUP_WAVES);
|
||||
_encounterNPCs.clear();
|
||||
_currentWave = 0;
|
||||
trash = 0;
|
||||
_bossWave = 0;
|
||||
_retreat = 0;
|
||||
DoUpdateWorldState(WORLD_STATE_WAVES, _currentWave);
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMY, trash);
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, trash);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -266,70 +478,75 @@ public:
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_RAGEWINTERCHILLEVENT:
|
||||
return m_auiEncounter[0];
|
||||
case DATA_ANETHERONEVENT:
|
||||
return m_auiEncounter[1];
|
||||
case DATA_KAZROGALEVENT:
|
||||
return m_auiEncounter[2];
|
||||
case DATA_AZGALOREVENT:
|
||||
return m_auiEncounter[3];
|
||||
case DATA_ARCHIMONDEEVENT:
|
||||
return m_auiEncounter[4];
|
||||
case DATA_TRASH:
|
||||
return Trash;
|
||||
case DATA_ALLIANCE_RETREAT:
|
||||
return allianceRetreat;
|
||||
case DATA_HORDE_RETREAT:
|
||||
return hordeRetreat;
|
||||
case DATA_RAIDDAMAGE:
|
||||
return RaidDamage;
|
||||
case DATA_WAVE_STATUS:
|
||||
return _currentWave;
|
||||
break;
|
||||
case DATA_BOSS_WAVE:
|
||||
return _bossWave;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ReadSaveDataMore(std::istringstream& data) override
|
||||
void ScheduleWaves(Milliseconds /* time */, uint8 startWaves, uint8 maxWaves, Milliseconds timerptr[])
|
||||
{
|
||||
data >> m_auiEncounter[0];
|
||||
data >> m_auiEncounter[1];
|
||||
data >> m_auiEncounter[2];
|
||||
data >> m_auiEncounter[3];
|
||||
data >> m_auiEncounter[4];
|
||||
data >> allianceRetreat;
|
||||
data >> hordeRetreat;
|
||||
data >> RaidDamage;
|
||||
// No overlapping!
|
||||
_scheduler.CancelGroup(CONTEXT_GROUP_WAVES);
|
||||
|
||||
_scheduler.Schedule(1ms, [this, startWaves, maxWaves, timerptr](TaskContext context)
|
||||
{
|
||||
// If all waves reached, cancel scheduling new ones
|
||||
if (_currentWave >= maxWaves)
|
||||
return;
|
||||
|
||||
trash = 0; // Overrun event trash can modify the counter, so we set it to 0 at the start of every wave. World Update is sent in the first spawn
|
||||
instance->SummonCreatureGroup(startWaves + _currentWave); // _currentWave should be 0 when this function is first called
|
||||
|
||||
// Check if it's time to summon Infernals
|
||||
if (GetBossState(DATA_KAZROGAL) == DONE && GetBossState(DATA_AZGALOR) != DONE)
|
||||
{
|
||||
switch (_currentWave + 1)
|
||||
{
|
||||
case 3:
|
||||
case 4:
|
||||
case 7:
|
||||
SetData(DATA_SPAWN_INFERNALS, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
context.Repeat(timerptr[_currentWave]);
|
||||
if (++_currentWave < maxWaves && _bossWave)
|
||||
{
|
||||
DoUpdateWorldState(WORLD_STATE_WAVES, _currentWave);
|
||||
DoUpdateWorldState(WORLD_STATE_ENEMY, 1);
|
||||
}
|
||||
|
||||
context.SetGroup(CONTEXT_GROUP_WAVES);
|
||||
});
|
||||
}
|
||||
|
||||
void WriteSaveDataMore(std::ostringstream& data) override
|
||||
void Update(uint32 diff) override
|
||||
{
|
||||
data << m_auiEncounter[0] << ' '
|
||||
<< m_auiEncounter[1] << ' '
|
||||
<< m_auiEncounter[2] << ' '
|
||||
<< m_auiEncounter[3] << ' '
|
||||
<< m_auiEncounter[4]<< ' '
|
||||
<< allianceRetreat << ' '
|
||||
<< hordeRetreat << ' '
|
||||
<< RaidDamage;
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32 m_auiEncounter[EncounterCount];
|
||||
GuidList m_uiAncientGemGUID;
|
||||
ObjectGuid RageWinterchill;
|
||||
ObjectGuid Anetheron;
|
||||
ObjectGuid Kazrogal;
|
||||
ObjectGuid Azgalor;
|
||||
ObjectGuid Archimonde;
|
||||
ObjectGuid JainaProudmoore;
|
||||
ObjectGuid Thrall;
|
||||
ObjectGuid TyrandeWhisperwind;
|
||||
ObjectGuid HordeGate;
|
||||
ObjectGuid ElfGate;
|
||||
uint32 Trash;
|
||||
uint32 hordeRetreat;
|
||||
uint32 allianceRetreat;
|
||||
uint32 RaidDamage;
|
||||
bool ArchiYell;
|
||||
int32 trash;
|
||||
uint8 _currentWave;
|
||||
uint8 _bossWave;
|
||||
uint8 _retreat;
|
||||
TaskScheduler _scheduler;
|
||||
GuidSet _encounterNPCs;
|
||||
GuidSet _baseAlliance;
|
||||
GuidSet _baseHorde;
|
||||
GuidVector _infernalTargets;
|
||||
GuidSet _baseNightElf;
|
||||
GuidSet _ancientGemAlliance;
|
||||
GuidSet _ancientGemHorde;
|
||||
GuidSet _roaringFlameAlliance;
|
||||
GuidSet _roaringFlameHorde;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ void AddSC_instance_blackfathom_deeps(); //Blackfathom Depths
|
||||
void AddSC_hyjal(); //CoT Battle for Mt. Hyjal
|
||||
void AddSC_boss_archimonde();
|
||||
void AddSC_instance_mount_hyjal();
|
||||
void AddSC_hyjal_trash();
|
||||
void AddSC_boss_rage_winterchill();
|
||||
void AddSC_boss_anetheron();
|
||||
void AddSC_boss_kazrogal();
|
||||
@@ -104,7 +103,6 @@ void AddKalimdorScripts()
|
||||
AddSC_hyjal(); //CoT Battle for Mt. Hyjal
|
||||
AddSC_boss_archimonde();
|
||||
AddSC_instance_mount_hyjal();
|
||||
AddSC_hyjal_trash();
|
||||
AddSC_boss_rage_winterchill();
|
||||
AddSC_boss_anetheron();
|
||||
AddSC_boss_kazrogal();
|
||||
|
||||
Reference in New Issue
Block a user