refactor(Scripts/VioletHold): Modernize Violet Hold dungeon scripts (#25187)

Co-authored-by: joschiwald <joschiwald@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andrew
2026-04-11 13:02:28 -03:00
committed by GitHub
parent 25b928b094
commit 272da9fbad
12 changed files with 1745 additions and 2222 deletions
+5 -4
View File
@@ -1810,12 +1810,13 @@ void Map::RemoveAllObjectsInRemoveList()
} }
} }
uint32 Map::GetPlayersCountExceptGMs() const uint32 Map::GetPlayersCountExceptGMs(bool aliveOnly /*= false*/) const
{ {
uint32 count = 0; uint32 count = 0;
for (MapRefMgr::const_iterator itr = m_mapRefMgr.begin(); itr != m_mapRefMgr.end(); ++itr) for (auto const& ref : m_mapRefMgr)
if (!itr->GetSource()->IsGameMaster()) if (Player* player = ref.GetSource())
++count; if (!player->IsGameMaster() && (!aliveOnly || (player->IsAlive() && !player->HasSpiritOfRedemptionAura())))
++count;
return count; return count;
} }
+2 -1
View File
@@ -318,7 +318,8 @@ public:
void markCell(uint32 pCellId) { marked_cells.set(pCellId); } void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
[[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); } [[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); }
[[nodiscard]] uint32 GetPlayersCountExceptGMs() const; // When aliveOnly is true, counts only players that are alive and not in Spirit of Redemption form.
[[nodiscard]] uint32 GetPlayersCountExceptGMs(bool aliveOnly = false) const;
void SendToPlayers(WorldPacket const* data) const; void SendToPlayers(WorldPacket const* data) const;
@@ -50,141 +50,95 @@ enum eEvents
EVENT_UNROOT, EVENT_UNROOT,
}; };
class boss_cyanigosa : public CreatureScript struct boss_cyanigosa : public BossAI
{ {
public: boss_cyanigosa(Creature* c) : BossAI(c, DATA_CYANIGOSA) { }
boss_cyanigosa() : CreatureScript("boss_cyanigosa") { }
CreatureAI* GetAI(Creature* pCreature) const override void JustEngagedWith(Unit* who) override
{ {
return GetVioletHoldAI<boss_cyanigosaAI>(pCreature); BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.RescheduleEvent(EVENT_SPELL_ARCANE_VACUUM, 30s);
events.RescheduleEvent(EVENT_SPELL_BLIZZARD, 5s, 10s);
events.RescheduleEvent(EVENT_SPELL_TAIL_SWEEP, 15s, 20s);
events.RescheduleEvent(EVENT_SPELL_UNCONTROLLABLE_ENERGY, 5s, 8s);
if (IsHeroic())
events.RescheduleEvent(EVENT_SPELL_MANA_DESTRUCTION, 20s);
} }
struct boss_cyanigosaAI : public ScriptedAI void SpellHitTarget(Unit* target, SpellInfo const* spell) override
{ {
boss_cyanigosaAI(Creature* c) : ScriptedAI(c) if (!target || !spell)
return;
if (spell->Id == SPELL_ARCANE_VACUUM)
target->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10.0f, target->GetOrientation());
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_ARCANE_VACUUM:
DoCastAOE(SPELL_ARCANE_VACUUM);
DoResetThreatList();
me->SetControlled(true, UNIT_STATE_ROOT);
me->setAttackTimer(BASE_ATTACK, 3000);
events.Repeat(30s);
events.ScheduleEvent(EVENT_UNROOT, 3s);
break;
case EVENT_UNROOT:
me->SetControlled(false, UNIT_STATE_ROOT);
break;
case EVENT_SPELL_BLIZZARD:
DoCastRandomTarget(SPELL_BLIZZARD, 0, 45.0f);
events.Repeat(15s);
break;
case EVENT_SPELL_MANA_DESTRUCTION:
DoCastRandomTarget(SPELL_MANA_DESTRUCTION, 0, 50.0f);
events.Repeat(20s);
break;
case EVENT_SPELL_TAIL_SWEEP:
DoCastVictim(SPELL_TAIL_SWEEP);
events.Repeat(15s, 20s);
break;
case EVENT_SPELL_UNCONTROLLABLE_ENERGY:
DoCastVictim(SPELL_UNCONTROLLABLE_ENERGY);
events.Repeat(20s, 25s);
break;
} }
}
InstanceScript* pInstance; void JustDied(Unit* killer) override
EventMap events; {
Talk(SAY_DEATH);
void Reset() override BossAI::JustDied(killer);
float h = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
if (h != INVALID_HEIGHT && me->GetPositionZ() - h > 3.0f)
{ {
events.Reset(); me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), h, me->GetOrientation(), true);
me->StopMovingOnCurrentPos();
me->DestroyForVisiblePlayers();
} }
}
void JustEngagedWith(Unit* /*who*/) override void KilledUnit(Unit* victim) override
{ {
DoZoneInCombat(); if (victim && victim->GetGUID() == me->GetGUID())
Talk(SAY_AGGRO); return;
events.Reset(); Talk(SAY_SLAY);
events.RescheduleEvent(EVENT_SPELL_ARCANE_VACUUM, 30s); }
events.RescheduleEvent(EVENT_SPELL_BLIZZARD, 5s, 10s);
events.RescheduleEvent(EVENT_SPELL_TAIL_SWEEP, 15s, 20s);
events.RescheduleEvent(EVENT_SPELL_UNCONTROLLABLE_ENERGY, 5s, 8s);
if (IsHeroic())
events.RescheduleEvent(EVENT_SPELL_MANA_DESTRUCTION, 20s);
}
void SpellHitTarget(Unit* target, SpellInfo const* spell) override void MoveInLineOfSight(Unit* /*who*/) override {}
{
if (!target || !spell)
return;
switch (spell->Id)
{
case SPELL_ARCANE_VACUUM:
target->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10.0f, target->GetOrientation());
break;
}
}
void UpdateAI(uint32 diff) override void EnterEvadeMode(EvadeReason why) override
{ {
if (!UpdateVictim()) me->SetControlled(false, UNIT_STATE_ROOT);
return; me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
_EnterEvadeMode(why);
events.Update(diff); }
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_ARCANE_VACUUM:
me->CastSpell((Unit*)nullptr, SPELL_ARCANE_VACUUM, false);
DoResetThreatList();
me->SetControlled(true, UNIT_STATE_ROOT);
me->setAttackTimer(BASE_ATTACK, 3000);
events.Repeat(30s);
events.ScheduleEvent(EVENT_UNROOT, 3s);
break;
case EVENT_UNROOT:
me->SetControlled(false, UNIT_STATE_ROOT);
break;
case EVENT_SPELL_BLIZZARD:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f, true))
me->CastSpell(target, SPELL_BLIZZARD, false);
events.Repeat(15s);
break;
case EVENT_SPELL_MANA_DESTRUCTION:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
me->CastSpell(target, SPELL_MANA_DESTRUCTION, false);
events.Repeat(20s);
break;
case EVENT_SPELL_TAIL_SWEEP:
me->CastSpell(me->GetVictim(), SPELL_TAIL_SWEEP, false);
events.Repeat(15s, 20s);
break;
case EVENT_SPELL_UNCONTROLLABLE_ENERGY:
me->CastSpell(me->GetVictim(), SPELL_UNCONTROLLABLE_ENERGY, false);
events.Repeat(20s, 25s);
break;
}
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (pInstance)
pInstance->SetData(DATA_BOSS_DIED, 0);
float h = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
if (h != INVALID_HEIGHT && me->GetPositionZ() - h > 3.0f)
{
me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), h, me->GetOrientation(), true); // move to ground
me->StopMovingOnCurrentPos();
me->DestroyForVisiblePlayers();
}
}
void KilledUnit(Unit* victim) override
{
if (victim && victim->GetGUID() == me->GetGUID())
return;
Talk(SAY_SLAY);
}
void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override
{
me->SetControlled(false, UNIT_STATE_ROOT);
ScriptedAI::EnterEvadeMode(why);
events.Reset();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
};
}; };
void AddSC_boss_cyanigosa() void AddSC_boss_cyanigosa()
{ {
new boss_cyanigosa(); RegisterVioletHoldCreatureAI(boss_cyanigosa);
} }
@@ -25,8 +25,6 @@ enum eSpells
SPELL_BREAK_BONDS = 59463, SPELL_BREAK_BONDS = 59463,
SPELL_CHAIN_HEAL = 54481, SPELL_CHAIN_HEAL = 54481,
SPELL_EARTH_SHIELD = 54479, SPELL_EARTH_SHIELD = 54479,
//SPELL_EARTH_SHIELD_TRIGGERED_N = 54480,
//SPELL_EARTH_SHIELD_TRIGGERED_H = 59472,
SPELL_EARTH_SHOCK = 54511, SPELL_EARTH_SHOCK = 54511,
SPELL_LIGHTNING_BOLT = 53044, SPELL_LIGHTNING_BOLT = 53044,
SPELL_STORMSTRIKE = 51876, SPELL_STORMSTRIKE = 51876,
@@ -53,164 +51,120 @@ enum eEvents
EVENT_SPELL_STORMSTRIKE, EVENT_SPELL_STORMSTRIKE,
}; };
class boss_erekem : public CreatureScript struct boss_erekem : public BossAI
{ {
public: boss_erekem(Creature* c) : BossAI(c, BOSS_EREKEM) { }
boss_erekem() : CreatureScript("boss_erekem") { }
CreatureAI* GetAI(Creature* pCreature) const override void JustEngagedWith(Unit* who) override
{ {
return GetVioletHoldAI<boss_erekemAI>(pCreature); BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_EARTH_SHIELD);
events.RescheduleEvent(EVENT_SPELL_BLOODLUST, 15s);
events.RescheduleEvent(EVENT_SPELL_BREAK_BONDS, 9s, 14s);
events.RescheduleEvent(EVENT_SPELL_CHAIN_HEAL, 0ms);
events.RescheduleEvent(EVENT_SPELL_EARTH_SHIELD, 20s);
events.RescheduleEvent(EVENT_SPELL_EARTH_SHOCK, 2s, 8s);
events.RescheduleEvent(EVENT_SPELL_LIGHTNING_BOLT, 5s, 10s);
if (IsHeroic())
events.RescheduleEvent(EVENT_SPELL_STORMSTRIKE, 3s);
if (Creature* c = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_1_GUID)))
if (!c->IsInCombat())
c->AI()->AttackStart(who);
if (Creature* c = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_2_GUID)))
if (!c->IsInCombat())
c->AI()->AttackStart(who);
} }
struct boss_erekemAI : public ScriptedAI void ExecuteEvent(uint32 eventId) override
{ {
boss_erekemAI(Creature* c) : ScriptedAI(c) switch (eventId)
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_BLOODLUST:
} DoCastAOE(SPELL_BLOODLUST);
events.Repeat(35s, 45s);
break;
case EVENT_SPELL_BREAK_BONDS:
DoCastAOE(SPELL_BREAK_BONDS);
events.Repeat(16s, 22s);
break;
case EVENT_SPELL_CHAIN_HEAL:
if (ObjectGuid targetGuid = GetChainHealTargetGuid())
{
if (Creature* target = instance->instance->GetCreature(targetGuid))
DoCast(target, SPELL_CHAIN_HEAL);
InstanceScript* pInstance; Creature* guard1 = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_1_GUID));
EventMap events; Creature* guard2 = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_2_GUID));
if ((guard1 && !guard1->IsAlive()) || (guard2 && !guard2->IsAlive()))
void Reset() override
{
events.Reset();
}
void JustEngagedWith(Unit* who) override
{
DoZoneInCombat();
Talk(SAY_AGGRO);
DoCast(me, SPELL_EARTH_SHIELD);
events.Reset();
events.RescheduleEvent(EVENT_SPELL_BLOODLUST, 15s);
events.RescheduleEvent(EVENT_SPELL_BREAK_BONDS, 9s, 14s);
events.RescheduleEvent(EVENT_SPELL_CHAIN_HEAL, 0ms);
events.RescheduleEvent(EVENT_SPELL_EARTH_SHIELD, 20s);
events.RescheduleEvent(EVENT_SPELL_EARTH_SHOCK, 2s, 8s);
events.RescheduleEvent(EVENT_SPELL_LIGHTNING_BOLT, 5s, 10s);
if (IsHeroic())
events.RescheduleEvent(EVENT_SPELL_STORMSTRIKE, 3s);
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_1_GUID)))
if (!c->IsInCombat())
c->AI()->AttackStart(who);
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_2_GUID)))
if (!c->IsInCombat())
c->AI()->AttackStart(who);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_BLOODLUST:
me->CastSpell((Unit*)nullptr, SPELL_BLOODLUST, false);
events.Repeat(35s, 45s);
break;
case EVENT_SPELL_BREAK_BONDS:
me->CastSpell((Unit*)nullptr, SPELL_BREAK_BONDS, false);
events.Repeat(16s, 22s);
break;
case EVENT_SPELL_CHAIN_HEAL:
if (ObjectGuid TargetGUID = GetChainHealTargetGUID())
if (pInstance)
{
if (Creature* target = pInstance->instance->GetCreature(TargetGUID))
me->CastSpell(target, SPELL_CHAIN_HEAL, false);
Creature* pGuard1 = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_1_GUID));
Creature* pGuard2 = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_2_GUID));
if ((pGuard1 && !pGuard1->IsAlive()) || (pGuard2 && !pGuard2->IsAlive()))
{
events.Repeat(3s, 6s);
break;
}
}
events.Repeat(8s, 11s);
break;
case EVENT_SPELL_EARTH_SHIELD:
me->CastSpell(me, SPELL_EARTH_SHIELD, false);
events.Repeat(20s);
break;
case EVENT_SPELL_EARTH_SHOCK:
me->CastSpell(me->GetVictim(), SPELL_EARTH_SHOCK, false);
events.Repeat(8s, 13s);
break;
case EVENT_SPELL_LIGHTNING_BOLT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 35.0f, true))
me->CastSpell(target, SPELL_LIGHTNING_BOLT, false);
events.Repeat(15s, 25s);
break;
case EVENT_SPELL_STORMSTRIKE:
{ {
Creature* pGuard1 = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_1_GUID)); events.Repeat(3s, 6s);
Creature* pGuard2 = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_2_GUID)); break;
if (pGuard1 && !pGuard1->IsAlive() && pGuard2 && !pGuard2->IsAlive()) // both dead
me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE, false);
events.Repeat(3s);
} }
break; }
} events.Repeat(8s, 11s);
break;
DoMeleeAttackIfReady(); case EVENT_SPELL_EARTH_SHIELD:
DoCastSelf(SPELL_EARTH_SHIELD);
events.Repeat(20s);
break;
case EVENT_SPELL_EARTH_SHOCK:
DoCastVictim(SPELL_EARTH_SHOCK);
events.Repeat(8s, 13s);
break;
case EVENT_SPELL_LIGHTNING_BOLT:
DoCastRandomTarget(SPELL_LIGHTNING_BOLT, 0, 35.0f);
events.Repeat(15s, 25s);
break;
case EVENT_SPELL_STORMSTRIKE:
{
Creature* guard1 = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_1_GUID));
Creature* guard2 = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_2_GUID));
if (guard1 && !guard1->IsAlive() && guard2 && !guard2->IsAlive())
DoCastVictim(SPELL_STORMSTRIKE);
events.Repeat(3s);
}
break;
} }
}
void JustDied(Unit* /*killer*/) override void JustDied(Unit* killer) override
{ {
Talk(SAY_DEATH); Talk(SAY_DEATH);
if (pInstance) BossAI::JustDied(killer);
pInstance->SetData(DATA_BOSS_DIED, 0); }
}
void KilledUnit(Unit* victim) override void KilledUnit(Unit* victim) override
{ {
if (victim && victim->GetGUID() == me->GetGUID()) if (victim && victim->GetGUID() == me->GetGUID())
return; return;
Talk(SAY_SLAY); Talk(SAY_SLAY);
} }
void MoveInLineOfSight(Unit* /*who*/) override {} void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override void EnterEvadeMode(EvadeReason why) override
{ {
ScriptedAI::EnterEvadeMode(why); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
events.Reset(); _EnterEvadeMode(why);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); }
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
ObjectGuid GetChainHealTargetGUID()
{
if (HealthBelowPct(85))
return me->GetGUID();
if (pInstance)
{
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_1_GUID)))
if (c->IsAlive() && !c->HealthAbovePct(75))
return c->GetGUID();
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUARD_2_GUID)))
if (c->IsAlive() && !c->HealthAbovePct(75))
return c->GetGUID();
}
ObjectGuid GetChainHealTargetGuid()
{
if (HealthBelowPct(85))
return me->GetGUID(); return me->GetGUID();
}
}; if (Creature* c = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_1_GUID)))
if (c->IsAlive() && !c->HealthAbovePct(75))
return c->GetGUID();
if (Creature* c = instance->instance->GetCreature(instance->GetGuidData(DATA_EREKEM_GUARD_2_GUID)))
if (c->IsAlive() && !c->HealthAbovePct(75))
return c->GetGUID();
return me->GetGUID();
}
}; };
enum GuardSpells enum GuardSpells
@@ -227,81 +181,69 @@ enum eGuardEvents
EVENT_SPELL_STRIKE EVENT_SPELL_STRIKE
}; };
class npc_erekem_guard : public CreatureScript struct npc_erekem_guard : public ScriptedAI
{ {
public: npc_erekem_guard(Creature* c) : ScriptedAI(c)
npc_erekem_guard() : CreatureScript("npc_erekem_guard") { }
CreatureAI* GetAI(Creature* pCreature) const override
{ {
return GetVioletHoldAI<npc_erekem_guardAI>(pCreature); _instance = c->GetInstanceScript();
} }
struct npc_erekem_guardAI : public ScriptedAI void Reset() override
{ {
npc_erekem_guardAI(Creature* c) : ScriptedAI(c) _events.Reset();
}
void JustEngagedWith(Unit* who) override
{
DoZoneInCombat();
_events.Reset();
_events.RescheduleEvent(EVENT_SPELL_GUSHING_WOUND, 1s, 3s);
_events.RescheduleEvent(EVENT_SPELL_HOWLING_SCREECH, 8s, 13s);
_events.RescheduleEvent(EVENT_SPELL_STRIKE, 4s, 8s);
if (Creature* c = _instance->GetCreature(BOSS_EREKEM))
if (!c->IsInCombat())
c->AI()->AttackStart(who);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (_events.ExecuteEvent())
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_GUSHING_WOUND:
DoCastVictim(SPELL_GUSHING_WOUND);
_events.Repeat(7s, 12s);
break;
case EVENT_SPELL_HOWLING_SCREECH:
DoCastVictim(SPELL_HOWLING_SCREECH);
_events.Repeat(8s, 13s);
break;
case EVENT_SPELL_STRIKE:
DoCastVictim(SPELL_STRIKE);
_events.Repeat(4s, 8s);
break;
} }
InstanceScript* pInstance; DoMeleeAttackIfReady();
EventMap events; }
void Reset() override void MoveInLineOfSight(Unit* /*who*/) override {}
{
events.Reset();
}
void JustEngagedWith(Unit* who) override private:
{ InstanceScript* _instance;
DoZoneInCombat(); EventMap _events;
events.Reset();
events.RescheduleEvent(EVENT_SPELL_GUSHING_WOUND, 1s, 3s);
events.RescheduleEvent(EVENT_SPELL_HOWLING_SCREECH, 8s, 13s);
events.RescheduleEvent(EVENT_SPELL_STRIKE, 4s, 8s);
if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_EREKEM_GUID)))
if (!c->IsInCombat())
c->AI()->AttackStart(who);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_GUSHING_WOUND:
me->CastSpell(me->GetVictim(), SPELL_GUSHING_WOUND, false);
events.Repeat(7s, 12s);
break;
case EVENT_SPELL_HOWLING_SCREECH:
me->CastSpell(me->GetVictim(), SPELL_HOWLING_SCREECH, false);
events.Repeat(8s, 13s);
break;
case EVENT_SPELL_STRIKE:
me->CastSpell(me->GetVictim(), SPELL_STRIKE, false);
events.Repeat(4s, 8s);
break;
}
DoMeleeAttackIfReady();
}
void MoveInLineOfSight(Unit* /*who*/) override {}
};
}; };
void AddSC_boss_erekem() void AddSC_boss_erekem()
{ {
new boss_erekem(); RegisterVioletHoldCreatureAI(boss_erekem);
new npc_erekem_guard(); RegisterVioletHoldCreatureAI(npc_erekem_guard);
} }
@@ -58,302 +58,278 @@ enum eSpells
SPELL_WATER_BLAST = 54237, SPELL_WATER_BLAST = 54237,
SPELL_WATER_BOLT_VOLLEY = 54241, SPELL_WATER_BOLT_VOLLEY = 54241,
SPELL_SPLASH = 59516, // casted by globule upon death SPELL_SPLASH = 59516,
SPELL_WATER_GLOBULE = 54268, // casted when hit by visual SPELL_WATER_GLOBULE = 54268,
SPELL_CREATE_GLOBULE_VISUAL = 54260, // tar 25 SPELL_CREATE_GLOBULE_VISUAL = 54260,
}; };
class boss_ichoron : public CreatureScript enum eEvents
{ {
public: EVENT_WATER_BOLT_VOLLEY = 1,
boss_ichoron() : CreatureScript("boss_ichoron") { } EVENT_DRAINED_CHECK,
};
CreatureAI* GetAI(Creature* pCreature) const override struct boss_ichoron : public BossAI
{
boss_ichoron(Creature* c) : BossAI(c, BOSS_ICHORON) { }
void Reset() override
{ {
return GetVioletHoldAI<boss_ichoronAI>(pCreature); BossAI::Reset();
_isExploded = false;
_isFrenzy = false;
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetDisplayId(me->GetNativeDisplayId());
} }
struct boss_ichoronAI : public ScriptedAI void DoAction(int32 param) override
{ {
boss_ichoronAI(Creature* c) : ScriptedAI(c), globules(me) if (!me->IsAlive())
return;
switch (param)
{ {
pInstance = c->GetInstanceScript(); case ACTION_WATER_ELEMENT_HIT:
instance->SetData(DATA_ACHIEV, 0);
me->ModifyHealth(int32(me->CountPctFromMaxHealth(1)));
if (_isExploded)
DoExplodeCompleted();
break;
case ACTION_WATER_ELEMENT_KILLED:
uint32 damage = me->CountPctFromMaxHealth(3);
damage = std::min(damage, me->GetHealth() - 1);
me->ModifyHealth(-int32(damage));
me->LowerPlayerDamageReq(damage);
break;
}
}
void DoExplodeCompleted()
{
_isExploded = false;
me->RemoveAura(SPELL_DRAINED);
if (!HealthBelowPct(25))
{
Talk(SAY_BUBBLE);
DoCastSelf(SPELL_PROTECTIVE_BUBBLE, true);
} }
InstanceScript* pInstance; me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
SummonList globules; me->SetDisplayId(me->GetNativeDisplayId());
bool bIsExploded; }
bool bIsFrenzy;
uint32 uiWaterBoltVolleyTimer;
uint32 uiDrainedTimer;
void Reset() override void IchoronDoCastToAllHostilePlayers(uint32 spellId, bool triggered)
{
Map::PlayerList const& playerList = me->GetMap()->GetPlayers();
if (playerList.IsEmpty())
return;
for (Map::PlayerList::const_iterator i = playerList.begin(); i != playerList.end(); ++i)
if (Player* plr = i->GetSource())
DoCast(plr, spellId, triggered);
}
void JustEngagedWith(Unit* who) override
{
_isExploded = false;
_isFrenzy = false;
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_PROTECTIVE_BUBBLE, true);
events.RescheduleEvent(EVENT_WATER_BOLT_VOLLEY, 7s, 12s);
instance->SetData(DATA_ACHIEV, 1);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (!_isFrenzy && !_isExploded && HealthBelowPct(25))
{ {
globules.DespawnAll(); Talk(SAY_ENRAGE);
bIsExploded = false; DoCastSelf(SPELL_FRENZY, true);
bIsFrenzy = false; _isFrenzy = true;
uiDrainedTimer = 15000;
uiWaterBoltVolleyTimer = urand(7000, 12000);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetDisplayId(me->GetNativeDisplayId());
} }
void DoAction(int32 param) override if (!_isFrenzy)
{ {
if (!me->IsAlive()) if (!_isExploded)
return;
switch (param)
{ {
case ACTION_WATER_ELEMENT_HIT: if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE))
if (pInstance)
pInstance->SetData(DATA_ACHIEV, 0);
me->ModifyHealth(int32(me->CountPctFromMaxHealth(1)));
if (bIsExploded)
DoExplodeCompleted();
break;
case ACTION_WATER_ELEMENT_KILLED:
uint32 damage = me->CountPctFromMaxHealth(3);
damage = std::min(damage, me->GetHealth() - 1);
me->ModifyHealth(-int32(damage));
me->LowerPlayerDamageReq(damage);
break;
}
}
void DoExplodeCompleted()
{
bIsExploded = false;
me->RemoveAura(SPELL_DRAINED);
if (!HealthBelowPct(25))
{
Talk(SAY_BUBBLE);
me->CastSpell(me, SPELL_PROTECTIVE_BUBBLE, true);
}
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetDisplayId(me->GetNativeDisplayId());
}
void IchoronDoCastToAllHostilePlayers(uint32 spellId, bool triggered)
{
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
if (PlayerList.IsEmpty())
return;
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
if (Player* plr = i->GetSource())
me->CastSpell(plr, spellId, triggered);
}
void JustEngagedWith(Unit* /*who*/) override
{
bIsExploded = false;
bIsFrenzy = false;
uiDrainedTimer = 15000;
uiWaterBoltVolleyTimer = urand(7000, 12000);
DoZoneInCombat();
Talk(SAY_AGGRO);
me->CastSpell(me, SPELL_PROTECTIVE_BUBBLE, true);
if (pInstance)
pInstance->SetData(DATA_ACHIEV, 1);
}
void UpdateAI(uint32 uiDiff) override
{
if (!UpdateVictim())
return;
if (!bIsFrenzy && !bIsExploded && HealthBelowPct(25))
{
Talk(SAY_ENRAGE);
me->CastSpell(me, SPELL_FRENZY, true);
bIsFrenzy = true;
}
if (!bIsFrenzy)
{
if (!bIsExploded)
{ {
if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE)) me->InterruptNonMeleeSpells(false);
Talk(SAY_SHATTER);
DoZoneInCombat();
IchoronDoCastToAllHostilePlayers(SPELL_WATER_BLAST, true);
DoCastSelf(SPELL_DRAINED, true);
_isExploded = true;
events.CancelEvent(EVENT_WATER_BOLT_VOLLEY);
events.RescheduleEvent(EVENT_DRAINED_CHECK, 15s);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetDisplayId(11686);
for (uint8 i = 0; i < MAX_SPAWN_LOC; ++i)
{ {
me->InterruptNonMeleeSpells(false); float angle = rand_norm() * 2 * M_PI;
Talk(SAY_SHATTER); Position p1(SpawnLoc[i]), p2(SpawnLoc[i]);
DoZoneInCombat(); p1.m_positionX += 2.5f * cos(angle);
IchoronDoCastToAllHostilePlayers(SPELL_WATER_BLAST, true); p1.m_positionY += 2.5f * std::sin(angle);
me->CastSpell(me, SPELL_DRAINED, true); p2.m_positionX -= 2.5f * cos(angle);
bIsExploded = true; p2.m_positionY -= 2.5f * std::sin(angle);
uiDrainedTimer = 15000; DoSummon(NPC_ICHOR_GLOBULE, p1, 60000, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); DoSummon(NPC_ICHOR_GLOBULE, p2, 60000, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN);
me->SetDisplayId(11686);
for (uint8 i = 0; i < MAX_SPAWN_LOC; ++i)
{
float angle = rand_norm() * 2 * M_PI;
Position p1(SpawnLoc[i]), p2(SpawnLoc[i]);
p1.m_positionX += 2.5f * cos(angle);
p1.m_positionY += 2.5f * std::sin(angle);
p2.m_positionX -= 2.5f * cos(angle);
p2.m_positionY -= 2.5f * std::sin(angle);
DoSummon(NPC_ICHOR_GLOBULE, p1, 60000, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN);
DoSummon(NPC_ICHOR_GLOBULE, p2, 60000, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN);
}
} }
} }
}
else
{
if (events.ExecuteEvent() == EVENT_DRAINED_CHECK)
DoExplodeCompleted();
else else
{ {
if (uiDrainedTimer <= uiDiff) bool isWaterElementsAlive = false;
DoExplodeCompleted(); if (!summons.empty())
else
{ {
uiDrainedTimer -= uiDiff; for (ObjectGuid const& guid : summons)
if (Creature* temp = ObjectAccessor::GetCreature(*me, guid))
bool bIsWaterElementsAlive = false; if (temp->IsAlive())
if (!globules.empty()) {
{ isWaterElementsAlive = true;
for (ObjectGuid const& guid : globules) break;
if (Creature* pTemp = ObjectAccessor::GetCreature(*me, guid)) }
if (pTemp->IsAlive())
{
bIsWaterElementsAlive = true;
break;
}
}
if (!bIsWaterElementsAlive)
DoExplodeCompleted();
} }
if (!isWaterElementsAlive)
DoExplodeCompleted();
} }
} }
if (!bIsExploded)
{
if (uiWaterBoltVolleyTimer <= uiDiff)
{
me->CastSpell((Unit*)nullptr, SPELL_WATER_BOLT_VOLLEY, false);
uiWaterBoltVolleyTimer = urand(10000, 15000);
}
else uiWaterBoltVolleyTimer -= uiDiff;
}
DoMeleeAttackIfReady();
} }
void JustSummoned(Creature* pSummoned) override if (!_isExploded)
{ {
if (pSummoned) if (events.ExecuteEvent() == EVENT_WATER_BOLT_VOLLEY)
{ {
pSummoned->SetSpeed(MOVE_RUN, 0.3f); DoCastAOE(SPELL_WATER_BOLT_VOLLEY);
pSummoned->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); events.Repeat(10s, 15s);
pSummoned->GetMotionMaster()->MoveFollow(me, 0, 0, MOTION_SLOT_ACTIVE, false, false);
me->CastSpell(pSummoned, SPELL_CREATE_GLOBULE_VISUAL, true); // triggered should ignore los
globules.Summon(pSummoned);
if (pInstance)
pInstance->SetGuidData(DATA_ADD_TRASH_MOB, pSummoned->GetGUID());
} }
} }
void SummonedCreatureDespawn(Creature* pSummoned) override DoMeleeAttackIfReady();
{
if (pSummoned)
{
globules.Despawn(pSummoned);
if (pInstance)
pInstance->SetGuidData(DATA_DELETE_TRASH_MOB, pSummoned->GetGUID());
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
bIsExploded = false;
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetDisplayId(me->GetNativeDisplayId());
globules.DespawnAll();
if (pInstance)
pInstance->SetData(DATA_BOSS_DIED, 0);
}
void KilledUnit(Unit* victim) override
{
if (victim && victim->GetGUID() == me->GetGUID())
return;
Talk(SAY_SLAY);
}
void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override
{
ScriptedAI::EnterEvadeMode(why);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
};
};
class npc_ichor_globule : public CreatureScript
{
public:
npc_ichor_globule() : CreatureScript("npc_ichor_globule") { }
CreatureAI* GetAI(Creature* pCreature) const override
{
return GetVioletHoldAI<npc_ichor_globuleAI>(pCreature);
} }
struct npc_ichor_globuleAI : public ScriptedAI void JustSummoned(Creature* summoned) override
{ {
npc_ichor_globuleAI(Creature* c) : ScriptedAI(c) if (summoned)
{ {
pInstance = c->GetInstanceScript(); summoned->SetSpeed(MOVE_RUN, 0.3f);
uiRangeCheck_Timer = 1000; summoned->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
summoned->GetMotionMaster()->MoveFollow(me, 0, 0, MOTION_SLOT_ACTIVE, false, false);
DoCast(summoned, SPELL_CREATE_GLOBULE_VISUAL, true);
BossAI::JustSummoned(summoned);
instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID());
} }
}
InstanceScript* pInstance; void SummonedCreatureDespawn(Creature* summoned) override
uint32 uiRangeCheck_Timer; {
if (summoned)
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{ {
if (spell->Id == SPELL_CREATE_GLOBULE_VISUAL) BossAI::SummonedCreatureDespawn(summoned);
me->CastSpell(me, SPELL_WATER_GLOBULE, true); instance->SetGuidData(DATA_DELETE_TRASH_MOB, summoned->GetGUID());
} }
}
void UpdateAI(uint32 uiDiff) override void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
_isExploded = false;
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetDisplayId(me->GetNativeDisplayId());
BossAI::JustDied(killer);
}
void KilledUnit(Unit* victim) override
{
if (victim && victim->GetGUID() == me->GetGUID())
return;
Talk(SAY_SLAY);
}
void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override
{
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
_EnterEvadeMode(why);
}
private:
bool _isExploded;
bool _isFrenzy;
};
enum eGlobuleEvents
{
EVENT_RANGE_CHECK = 1,
};
struct npc_ichor_globule : public ScriptedAI
{
npc_ichor_globule(Creature* c) : ScriptedAI(c)
{
_instance = c->GetInstanceScript();
}
void Reset() override
{
_events.RescheduleEvent(EVENT_RANGE_CHECK, 1s);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_CREATE_GLOBULE_VISUAL)
DoCastSelf(SPELL_WATER_GLOBULE, true);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (_events.ExecuteEvent() == EVENT_RANGE_CHECK)
{ {
if (uiRangeCheck_Timer < uiDiff) if (Creature* ichoron = _instance->GetCreature(BOSS_ICHORON))
{ if (me->IsWithinDist(ichoron, 2.0f, false))
if (pInstance) {
if (Creature* pIchoron = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_ICHORON_GUID))) if (ichoron->AI())
if (me->IsWithinDist(pIchoron, 2.0f, false)) ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT);
{ me->DespawnOrUnsummon();
if (pIchoron->AI()) return;
pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT); }
me->DespawnOrUnsummon(); _events.Repeat(1s);
}
uiRangeCheck_Timer = 1000;
}
else uiRangeCheck_Timer -= uiDiff;
} }
}
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
me->CastSpell(me, SPELL_SPLASH, true); DoCastSelf(SPELL_SPLASH, true);
if (pInstance) if (Creature* ichoron = _instance->GetCreature(BOSS_ICHORON))
if (Creature* pIchoron = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_ICHORON_GUID))) if (ichoron->AI())
if (pIchoron->AI()) ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED);
pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED); me->DespawnOrUnsummon(2500ms);
me->DespawnOrUnsummon(2500ms); }
}
void AttackStart(Unit* /*who*/) override {} void AttackStart(Unit* /*who*/) override {}
void MoveInLineOfSight(Unit* /*who*/) override {} void MoveInLineOfSight(Unit* /*who*/) override {}
};
private:
InstanceScript* _instance;
EventMap _events;
}; };
void AddSC_boss_ichoron() void AddSC_boss_ichoron()
{ {
new boss_ichoron(); RegisterVioletHoldCreatureAI(boss_ichoron);
new npc_ichor_globule(); RegisterVioletHoldCreatureAI(npc_ichor_globule);
} }
@@ -35,97 +35,53 @@ enum eEvents
EVENT_SPELL_CAUTERIZING_FLAMES, EVENT_SPELL_CAUTERIZING_FLAMES,
}; };
class boss_lavanthor : public CreatureScript struct boss_lavanthor : public BossAI
{ {
public: boss_lavanthor(Creature* c) : BossAI(c, BOSS_LAVANTHOR) { }
boss_lavanthor() : CreatureScript("boss_lavanthor") { }
CreatureAI* GetAI(Creature* pCreature) const override void JustEngagedWith(Unit* who) override
{ {
return GetVioletHoldAI<boss_lavanthorAI>(pCreature); BossAI::JustEngagedWith(who);
events.RescheduleEvent(EVENT_SPELL_FIREBOLT, 1s);
events.RescheduleEvent(EVENT_SPELL_FLAME_BREATH, 5s);
events.RescheduleEvent(EVENT_SPELL_LAVA_BURN, 10s);
if (IsHeroic())
events.RescheduleEvent(EVENT_SPELL_CAUTERIZING_FLAMES, 3s);
} }
struct boss_lavanthorAI : public ScriptedAI void ExecuteEvent(uint32 eventId) override
{ {
boss_lavanthorAI(Creature* c) : ScriptedAI(c) switch (eventId)
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_FIREBOLT:
DoCastVictim(SPELL_FIREBOLT);
events.Repeat(5s, 13s);
break;
case EVENT_SPELL_FLAME_BREATH:
DoCastVictim(SPELL_FLAME_BREATH);
events.Repeat(10s, 15s);
break;
case EVENT_SPELL_LAVA_BURN:
DoCastVictim(SPELL_LAVA_BURN);
events.Repeat(14s, 20s);
break;
case EVENT_SPELL_CAUTERIZING_FLAMES:
DoCastAOE(SPELL_CAUTERIZING_FLAMES);
events.Repeat(10s, 16s);
break;
} }
}
InstanceScript* pInstance; void MoveInLineOfSight(Unit* /*who*/) override {}
EventMap events;
void Reset() override void EnterEvadeMode(EvadeReason why) override
{ {
events.Reset(); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
} _EnterEvadeMode(why);
}
void JustEngagedWith(Unit* /*who*/) override
{
DoZoneInCombat();
events.Reset();
events.RescheduleEvent(EVENT_SPELL_FIREBOLT, 1s);
events.RescheduleEvent(EVENT_SPELL_FLAME_BREATH, 5s);
events.RescheduleEvent(EVENT_SPELL_LAVA_BURN, 10s);
if (IsHeroic())
events.RescheduleEvent(EVENT_SPELL_CAUTERIZING_FLAMES, 3s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_FIREBOLT:
me->CastSpell(me->GetVictim(), SPELL_FIREBOLT, false);
events.Repeat(5s, 13s);
break;
case EVENT_SPELL_FLAME_BREATH:
me->CastSpell(me->GetVictim(), SPELL_FLAME_BREATH, false);
events.Repeat(10s, 15s);
break;
case EVENT_SPELL_LAVA_BURN:
me->CastSpell(me->GetVictim(), SPELL_LAVA_BURN, false);
events.Repeat(14s, 20s);
break;
case EVENT_SPELL_CAUTERIZING_FLAMES:
me->CastSpell((Unit*)nullptr, SPELL_FLAME_BREATH, false);
events.Repeat(10s, 16s);
break;
}
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
if (pInstance)
pInstance->SetData(DATA_BOSS_DIED, 0);
}
void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override
{
ScriptedAI::EnterEvadeMode(why);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
};
}; };
void AddSC_boss_lavanthor() void AddSC_boss_lavanthor()
{ {
new boss_lavanthor(); RegisterVioletHoldCreatureAI(boss_lavanthor);
} }
@@ -25,12 +25,7 @@
enum eSpells enum eSpells
{ {
SPELL_RAY_OF_SUFFERING = 54442, SPELL_RAY_OF_SUFFERING = 54442,
//SPELL_RAY_OF_SUFFERING_TRIGGERED = 54417,
SPELL_RAY_OF_PAIN = 54438, SPELL_RAY_OF_PAIN = 54438,
//SPELL_RAY_OF_PAIN_TRIGGERED_N = 54416,
//SPELL_RAY_OF_PAIN_TRIGGERED_H = 59525,
SPELL_CORROSIVE_SALIVA = 54527, SPELL_CORROSIVE_SALIVA = 54527,
SPELL_OPTIC_LINK = 54396, SPELL_OPTIC_LINK = 54396,
}; };
@@ -41,90 +36,46 @@ enum eEvents
EVENT_SPELL_OPTIC_LINK, EVENT_SPELL_OPTIC_LINK,
}; };
class boss_moragg : public CreatureScript struct boss_moragg : public BossAI
{ {
public: boss_moragg(Creature* c) : BossAI(c, BOSS_MORAGG) { }
boss_moragg() : CreatureScript("boss_moragg") { }
CreatureAI* GetAI(Creature* pCreature) const override void JustEngagedWith(Unit* who) override
{ {
return GetVioletHoldAI<boss_moraggAI>(pCreature); BossAI::JustEngagedWith(who);
DoCastSelf(SPELL_RAY_OF_SUFFERING, true);
DoCastSelf(SPELL_RAY_OF_PAIN, true);
events.RescheduleEvent(EVENT_SPELL_CORROSIVE_SALIVA, 4s, 6s);
events.RescheduleEvent(EVENT_SPELL_OPTIC_LINK, 10s, 11s);
} }
struct boss_moraggAI : public ScriptedAI void ExecuteEvent(uint32 eventId) override
{ {
boss_moraggAI(Creature* c) : ScriptedAI(c) switch (eventId)
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_CORROSIVE_SALIVA:
DoCastVictim(SPELL_CORROSIVE_SALIVA);
events.Repeat(8s, 10s);
break;
case EVENT_SPELL_OPTIC_LINK:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 40.0f, true))
{
DoCast(target, SPELL_OPTIC_LINK);
events.Repeat(18s, 21s);
}
else
events.Repeat(5s);
break;
} }
}
InstanceScript* pInstance; void MoveInLineOfSight(Unit* /*who*/) override {}
EventMap events;
void Reset() override void EnterEvadeMode(EvadeReason why) override
{ {
events.Reset(); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
} _EnterEvadeMode(why);
}
void JustEngagedWith(Unit* /*who*/) override
{
DoZoneInCombat();
me->CastSpell(me, SPELL_RAY_OF_SUFFERING, true);
me->CastSpell(me, SPELL_RAY_OF_PAIN, true);
events.Reset();
events.RescheduleEvent(EVENT_SPELL_CORROSIVE_SALIVA, 4s, 6s);
events.RescheduleEvent(EVENT_SPELL_OPTIC_LINK, 10s, 11s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_CORROSIVE_SALIVA:
me->CastSpell(me->GetVictim(), SPELL_CORROSIVE_SALIVA, false);
events.Repeat(8s, 10s);
break;
case EVENT_SPELL_OPTIC_LINK:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, 40.0f, true))
{
me->CastSpell(target, SPELL_OPTIC_LINK, false);
events.Repeat(18s, 21s);
}
else
events.Repeat(5s);
break;
}
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
if (pInstance)
pInstance->SetData(DATA_BOSS_DIED, 0);
}
void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override
{
ScriptedAI::EnterEvadeMode(why);
events.Reset();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
};
}; };
class spell_optic_link_aura : public AuraScript class spell_optic_link_aura : public AuraScript
@@ -147,6 +98,6 @@ class spell_optic_link_aura : public AuraScript
void AddSC_boss_moragg() void AddSC_boss_moragg()
{ {
new boss_moragg(); RegisterVioletHoldCreatureAI(boss_moragg);
RegisterSpellScript(spell_optic_link_aura); RegisterSpellScript(spell_optic_link_aura);
} }
@@ -39,8 +39,6 @@ enum eSpells
SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138, SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138,
SPELL_ARCANE_POWER = 54160 SPELL_ARCANE_POWER = 54160
//SPELL_SUMMON_PLAYERS = 54164, // not used
//SPELL_POWER_BALL_VISUAL = 54141,
}; };
enum eEvents enum eEvents
@@ -51,159 +49,114 @@ enum eEvents
EVENT_CHECK_DISTANCE, EVENT_CHECK_DISTANCE,
}; };
class boss_xevozz : public CreatureScript struct boss_xevozz : public BossAI
{ {
public: boss_xevozz(Creature* c) : BossAI(c, BOSS_XEVOZZ) { }
boss_xevozz() : CreatureScript("boss_xevozz") { }
CreatureAI* GetAI(Creature* pCreature) const override void JustEngagedWith(Unit* who) override
{ {
return GetVioletHoldAI<boss_xevozzAI>(pCreature); Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.RescheduleEvent(EVENT_SPELL_ARCANE_BARRAGE_VOLLEY, 16s, 20s);
events.RescheduleEvent(EVENT_SUMMON_SPHERES, 10s);
} }
struct boss_xevozzAI : public ScriptedAI void ExecuteEvent(uint32 eventId) override
{ {
boss_xevozzAI(Creature* c) : ScriptedAI(c), spheres(me) switch (eventId)
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_ARCANE_BARRAGE_VOLLEY:
} DoCastAOE(SPELL_ARCANE_BARRAGE_VOLLEY);
events.Repeat(20s);
InstanceScript* pInstance; break;
EventMap events; case EVENT_SPELL_ARCANE_BUFFET:
SummonList spheres; DoCastVictim(SPELL_ARCANE_BUFFET);
break;
void Reset() override case EVENT_SUMMON_SPHERES:
{ {
events.Reset(); Talk(SAY_SUMMON_ENERGY);
spheres.DespawnAll(); summons.DespawnAll();
} uint32 entry1 = RAND(SPELL_SUMMON_ETHEREAL_SPHERE_1, SPELL_SUMMON_ETHEREAL_SPHERE_2, SPELL_SUMMON_ETHEREAL_SPHERE_3);
DoCastAOE(entry1, true);
void JustEngagedWith(Unit* /*who*/) override if (IsHeroic())
{
Talk(SAY_AGGRO);
DoZoneInCombat();
events.Reset();
events.RescheduleEvent(EVENT_SPELL_ARCANE_BARRAGE_VOLLEY, 16s, 20s);
events.RescheduleEvent(EVENT_SUMMON_SPHERES, 10s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_ARCANE_BARRAGE_VOLLEY:
me->CastSpell((Unit*)nullptr, SPELL_ARCANE_BARRAGE_VOLLEY, false);
events.Repeat(20s);
break;
case EVENT_SPELL_ARCANE_BUFFET:
me->CastSpell(me->GetVictim(), SPELL_ARCANE_BUFFET, false);
break;
case EVENT_SUMMON_SPHERES:
{ {
Talk(SAY_SUMMON_ENERGY); uint32 entry2;
spheres.DespawnAll(); do { entry2 = RAND(SPELL_SUMMON_ETHEREAL_SPHERE_1, SPELL_SUMMON_ETHEREAL_SPHERE_2, SPELL_SUMMON_ETHEREAL_SPHERE_3); }
uint32 entry1 = RAND(SPELL_SUMMON_ETHEREAL_SPHERE_1, SPELL_SUMMON_ETHEREAL_SPHERE_2, SPELL_SUMMON_ETHEREAL_SPHERE_3); while (entry1 == entry2);
me->CastSpell((Unit*)nullptr, entry1, true); DoCastAOE(entry2, true);
if (IsHeroic())
{
uint32 entry2;
do { entry2 = RAND(SPELL_SUMMON_ETHEREAL_SPHERE_1, SPELL_SUMMON_ETHEREAL_SPHERE_2, SPELL_SUMMON_ETHEREAL_SPHERE_3); }
while (entry1 == entry2);
me->CastSpell((Unit*)nullptr, entry2, true);
}
events.Repeat(45s);
events.RescheduleEvent(EVENT_SPELL_ARCANE_BUFFET, 5s);
events.RescheduleEvent(EVENT_CHECK_DISTANCE, 6s);
} }
break; events.Repeat(45s);
case EVENT_CHECK_DISTANCE: events.RescheduleEvent(EVENT_SPELL_ARCANE_BUFFET, 5s);
events.RescheduleEvent(EVENT_CHECK_DISTANCE, 6s);
}
break;
case EVENT_CHECK_DISTANCE:
{
bool found = false;
for (ObjectGuid const& guid : summons)
if (Creature* sphere = instance->instance->GetCreature(guid))
if (me->GetDistance(sphere) < 3.0f)
{
sphere->CastSpell(me, SPELL_ARCANE_POWER, false);
sphere->DespawnOrUnsummon(8s);
found = true;
}
if (found)
{ {
bool found = false; Talk(SAY_CHARGED);
if (pInstance) events.Repeat(9s);
for (ObjectGuid const& guid : spheres) events.RescheduleEvent(EVENT_SUMMON_SPHERES, 10s);
if (Creature* c = pInstance->instance->GetCreature(guid))
if (me->GetDistance(c) < 3.0f)
{
c->CastSpell(me, SPELL_ARCANE_POWER, false);
c->DespawnOrUnsummon(8s);
found = true;
}
if (found)
{
Talk(SAY_CHARGED);
events.Repeat(9s);
events.RescheduleEvent(EVENT_SUMMON_SPHERES, 10s);
}
else
events.Repeat(2s);
} }
break; else
} events.Repeat(2s);
}
DoMeleeAttackIfReady(); break;
} }
}
void JustSummoned(Creature* pSummoned) override void JustSummoned(Creature* summoned) override
{
if (summoned)
{ {
if (pSummoned) summoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f, MOTION_SLOT_ACTIVE, true, false);
{ BossAI::JustSummoned(summoned);
pSummoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f, MOTION_SLOT_ACTIVE, true, false); instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID());
spheres.Summon(pSummoned);
if (pInstance)
pInstance->SetGuidData(DATA_ADD_TRASH_MOB, pSummoned->GetGUID());
}
} }
}
void SummonedCreatureDespawn(Creature* pSummoned) override void SummonedCreatureDespawn(Creature* summoned) override
{
if (summoned)
{ {
if (pSummoned) BossAI::SummonedCreatureDespawn(summoned);
{ instance->SetGuidData(DATA_DELETE_TRASH_MOB, summoned->GetGUID());
spheres.Despawn(pSummoned);
if (pInstance)
pInstance->SetGuidData(DATA_DELETE_TRASH_MOB, pSummoned->GetGUID());
}
} }
}
void JustDied(Unit* /*killer*/) override void JustDied(Unit* killer) override
{ {
Talk(SAY_DEATH); Talk(SAY_DEATH);
spheres.DespawnAll(); BossAI::JustDied(killer);
if (pInstance) }
pInstance->SetData(DATA_BOSS_DIED, 0);
}
void KilledUnit(Unit* pVictim) override void KilledUnit(Unit* victim) override
{ {
if (pVictim && pVictim->GetGUID() == me->GetGUID()) if (victim && victim->GetGUID() == me->GetGUID())
return; return;
Talk(SAY_SLAY); Talk(SAY_SLAY);
} }
void MoveInLineOfSight(Unit* /*who*/) override {} void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override void EnterEvadeMode(EvadeReason why) override
{ {
ScriptedAI::EnterEvadeMode(why); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
events.Reset(); _EnterEvadeMode(why);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); }
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
};
}; };
void AddSC_boss_xevozz() void AddSC_boss_xevozz()
{ {
new boss_xevozz(); RegisterVioletHoldCreatureAI(boss_xevozz);
} }
@@ -36,12 +36,12 @@ enum eSpells
SPELL_VOID_SHIFT = 54361, SPELL_VOID_SHIFT = 54361,
SPELL_SUMMON_VOID_SENTRY = 54369, SPELL_SUMMON_VOID_SENTRY = 54369,
SPELL_SUMMON_VOID_SENTRY_BALL = 58650, SPELL_SUMMON_VOID_SENTRY_BALL = 58650,
//SPELL_ZURAMAT_ADD_2_N = 54342,
//SPELL_ZURAMAT_ADD_2_H = 59747,
}; };
#define NPC_VOID_SENTRY_BALL 29365 enum eCreatures
{
NPC_VOID_SENTRY_BALL = 29365,
};
enum eEvents enum eEvents
{ {
@@ -50,208 +50,154 @@ enum eEvents
EVENT_SPELL_SUMMON_VOID_SENTRY, EVENT_SPELL_SUMMON_VOID_SENTRY,
}; };
class boss_zuramat : public CreatureScript enum eVoidSentryEvents
{ {
public: EVENT_CHECK_SUMMONER = 1,
boss_zuramat() : CreatureScript("boss_zuramat") { }
CreatureAI* GetAI(Creature* pCreature) const override
{
return GetVioletHoldAI<boss_zuramatAI>(pCreature);
}
struct boss_zuramatAI : public ScriptedAI
{
boss_zuramatAI(Creature* c) : ScriptedAI(c), summons(me)
{
pInstance = c->GetInstanceScript();
}
InstanceScript* pInstance;
EventMap events;
SummonList summons;
void Reset() override
{
events.Reset();
summons.DespawnAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
DoZoneInCombat();
events.Reset();
events.RescheduleEvent(EVENT_SPELL_SHROUD_OF_DARKNESS, 5s, 7s);
events.RescheduleEvent(EVENT_SPELL_VOID_SHIFT, 23s, 25s);
events.RescheduleEvent(EVENT_SPELL_SUMMON_VOID_SENTRY, 10s);
if (pInstance)
pInstance->SetData(DATA_ACHIEV, 1);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case 0:
break;
case EVENT_SPELL_SHROUD_OF_DARKNESS:
me->CastSpell(me, SPELL_SHROUD_OF_DARKNESS, false);
Talk(SAY_SHIELD);
events.Repeat(20s);
break;
case EVENT_SPELL_VOID_SHIFT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
{
me->CastSpell(target, SPELL_VOID_SHIFT, false);
me->Whisper("Gaze... into the void.", LANG_UNIVERSAL, target->ToPlayer());
}
events.Repeat(18s, 22s);
break;
case EVENT_SPELL_SUMMON_VOID_SENTRY:
me->CastSpell((Unit*)nullptr, SPELL_SUMMON_VOID_SENTRY, false);
events.Repeat(12s);
break;
}
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
summons.DespawnAll();
Talk(SAY_DEATH);
if (pInstance)
pInstance->SetData(DATA_BOSS_DIED, 0);
}
void KilledUnit(Unit* victim) override
{
if (victim && victim->GetGUID() == me->GetGUID())
return;
Talk(SAY_SLAY);
}
void JustSummoned(Creature* pSummoned) override
{
if (pSummoned)
{
summons.Summon(pSummoned);
pSummoned->SetPhaseMask(16, true);
if (pInstance)
pInstance->SetGuidData(DATA_ADD_TRASH_MOB, pSummoned->GetGUID());
}
}
void SummonedCreatureDespawn(Creature* pSummoned) override
{
if (pSummoned)
{
summons.Despawn(pSummoned);
if (pSummoned->IsAIEnabled)
pSummoned->AI()->DoAction(-1337);
if (pInstance)
pInstance->SetGuidData(DATA_DELETE_TRASH_MOB, pSummoned->GetGUID());
}
}
void MoveInLineOfSight(Unit* /*who*/) override {}
void EnterEvadeMode(EvadeReason why) override
{
ScriptedAI::EnterEvadeMode(why);
events.Reset();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (pInstance)
pInstance->SetData(DATA_FAILED, 1);
}
};
}; };
class npc_vh_void_sentry : public CreatureScript struct boss_zuramat : public BossAI
{ {
public: boss_zuramat(Creature* c) : BossAI(c, BOSS_ZURAMAT) { }
npc_vh_void_sentry() : CreatureScript("npc_vh_void_sentry") { }
CreatureAI* GetAI(Creature* pCreature) const override void JustEngagedWith(Unit* who) override
{ {
return GetVioletHoldAI<npc_vh_void_sentryAI>(pCreature); Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.RescheduleEvent(EVENT_SPELL_SHROUD_OF_DARKNESS, 5s, 7s);
events.RescheduleEvent(EVENT_SPELL_VOID_SHIFT, 23s, 25s);
events.RescheduleEvent(EVENT_SPELL_SUMMON_VOID_SENTRY, 10s);
instance->SetData(DATA_ACHIEV, 1);
} }
struct npc_vh_void_sentryAI : public NullCreatureAI void ExecuteEvent(uint32 eventId) override
{ {
npc_vh_void_sentryAI(Creature* c) : NullCreatureAI(c) switch (eventId)
{ {
pInstance = c->GetInstanceScript(); case EVENT_SPELL_SHROUD_OF_DARKNESS:
SummonedGUID.Clear(); DoCastSelf(SPELL_SHROUD_OF_DARKNESS);
checkTimer = 5000; Talk(SAY_SHIELD);
//me->CastSpell(me, SPELL_SUMMON_VOID_SENTRY_BALL, true); events.Repeat(20s);
if (Creature* pSummoned = me->SummonCreature(NPC_VOID_SENTRY_BALL, *me, TEMPSUMMON_TIMED_DESPAWN, 300000)) break;
{ case EVENT_SPELL_VOID_SHIFT:
pSummoned->SetPhaseMask(1, true); if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
SummonedGUID = pSummoned->GetGUID(); {
pInstance->SetGuidData(DATA_ADD_TRASH_MOB, pSummoned->GetGUID()); DoCast(target, SPELL_VOID_SHIFT);
} me->Whisper("Gaze... into the void.", LANG_UNIVERSAL, target->ToPlayer());
}
events.Repeat(18s, 22s);
break;
case EVENT_SPELL_SUMMON_VOID_SENTRY:
DoCastAOE(SPELL_SUMMON_VOID_SENTRY);
events.Repeat(12s);
break;
} }
}
InstanceScript* pInstance; void JustDied(Unit* killer) override
ObjectGuid SummonedGUID; {
uint16 checkTimer; Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void DoAction(int32 a) override void KilledUnit(Unit* victim) override
{
if (victim && victim->GetGUID() == me->GetGUID())
return;
Talk(SAY_SLAY);
}
void JustSummoned(Creature* summoned) override
{
if (summoned)
{ {
if (a == -1337) BossAI::JustSummoned(summoned);
if (Creature* c = pInstance->instance->GetCreature(SummonedGUID)) summoned->SetPhaseMask(16, true);
c->DespawnOrUnsummon(); instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID());
} }
}
void JustDied(Unit* /*killer*/) override void SummonedCreatureDespawn(Creature* summoned) override
{
if (summoned)
{ {
if (pInstance) BossAI::SummonedCreatureDespawn(summoned);
{ if (summoned->IsAIEnabled)
pInstance->SetData(DATA_ACHIEV, 0); summoned->AI()->DoAction(-1337);
if (Creature* c = pInstance->instance->GetCreature(SummonedGUID)) instance->SetGuidData(DATA_DELETE_TRASH_MOB, summoned->GetGUID());
c->DespawnOrUnsummon();
}
me->DespawnOrUnsummon(5s);
} }
}
void SummonedCreatureDespawn(Creature* pSummoned) override void MoveInLineOfSight(Unit* /*who*/) override {}
{
if (pSummoned)
pInstance->SetGuidData(DATA_DELETE_TRASH_MOB, pSummoned->GetGUID());
}
void UpdateAI(uint32 diff) override void EnterEvadeMode(EvadeReason why) override
{
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
_EnterEvadeMode(why);
}
};
struct npc_vh_void_sentry : public NullCreatureAI
{
npc_vh_void_sentry(Creature* c) : NullCreatureAI(c)
{
_instance = c->GetInstanceScript();
_summonedGuid.Clear();
_events.ScheduleEvent(EVENT_CHECK_SUMMONER, 5s);
if (Creature* summoned = me->SummonCreature(NPC_VOID_SENTRY_BALL, *me, TEMPSUMMON_TIMED_DESPAWN, 300000))
{ {
if (checkTimer <= diff) summoned->SetPhaseMask(1, true);
{ _summonedGuid = summoned->GetGUID();
checkTimer = 5000; _instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID());
bool good = false;
if (me->IsSummon())
if (Unit* s = me->ToTempSummon()->GetSummonerUnit())
if (s->IsAlive())
good = true;
if (!good)
me->KillSelf();
}
else
checkTimer -= diff;
} }
}; }
void DoAction(int32 action) override
{
if (action == -1337)
if (Creature* voidSentry = _instance->instance->GetCreature(_summonedGuid))
voidSentry->DespawnOrUnsummon();
}
void JustDied(Unit* /*killer*/) override
{
_instance->SetData(DATA_ACHIEV, 0);
if (Creature* voidSentry = _instance->instance->GetCreature(_summonedGuid))
voidSentry->DespawnOrUnsummon();
me->DespawnOrUnsummon(5s);
}
void SummonedCreatureDespawn(Creature* summoned) override
{
if (summoned)
_instance->SetGuidData(DATA_DELETE_TRASH_MOB, summoned->GetGUID());
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (_events.ExecuteEvent() == EVENT_CHECK_SUMMONER)
{
bool good = false;
if (me->IsSummon())
if (Unit* s = me->ToTempSummon()->GetSummonerUnit())
if (s->IsAlive())
good = true;
if (!good)
me->KillSelf();
_events.Repeat(5s);
}
}
private:
InstanceScript* _instance;
ObjectGuid _summonedGuid;
EventMap _events;
}; };
void AddSC_boss_zuramat() void AddSC_boss_zuramat()
{ {
new boss_zuramat(); RegisterVioletHoldCreatureAI(boss_zuramat);
new npc_vh_void_sentry(); RegisterVioletHoldCreatureAI(npc_vh_void_sentry);
} }
@@ -22,7 +22,7 @@
#include "WorldStateDefines.h" #include "WorldStateDefines.h"
#include "violet_hold.h" #include "violet_hold.h"
enum vYells enum VHYells
{ {
CYANIGOSA_SAY_SPAWN = 3, CYANIGOSA_SAY_SPAWN = 3,
SAY_SINCLARI_LEAVING = 0, SAY_SINCLARI_LEAVING = 0,
@@ -30,175 +30,163 @@ enum vYells
SAY_SINCLARI_COMPLETE = 2, SAY_SINCLARI_COMPLETE = 2,
}; };
ObjectData const creatureData[] =
{
{ NPC_MORAGG, BOSS_MORAGG },
{ NPC_EREKEM, BOSS_EREKEM },
{ NPC_ICHORON, BOSS_ICHORON },
{ NPC_LAVANTHOR, BOSS_LAVANTHOR },
{ NPC_XEVOZZ, BOSS_XEVOZZ },
{ NPC_ZURAMAT, BOSS_ZURAMAT },
{ NPC_CYANIGOSA, DATA_CYANIGOSA },
{ NPC_SINCLARI, DATA_SINCLARI },
{ NPC_PRISON_DOOR_SEAL, DATA_DOOR_SEAL },
{ NPC_TELEPORTATION_PORTAL, DATA_TELEPORTATION_PORTAL },
{ 0, 0 }
};
ObjectData const goData[] =
{
{ GO_MAIN_DOOR, DATA_MAIN_DOOR },
{ GO_MORAGG_DOOR, DATA_MORAGG_CELL },
{ GO_EREKEM_DOOR, DATA_EREKEM_CELL },
{ GO_EREKEM_GUARD_1_DOOR, DATA_EREKEM_GUARD_1_CELL },
{ GO_EREKEM_GUARD_2_DOOR, DATA_EREKEM_GUARD_2_CELL },
{ GO_ICHORON_DOOR, DATA_ICHORON_CELL },
{ GO_LAVANTHOR_DOOR, DATA_LAVANTHOR_CELL },
{ GO_XEVOZZ_DOOR, DATA_XEVOZZ_CELL },
{ GO_ZURAMAT_DOOR, DATA_ZURAMAT_CELL },
{ 0, 0 }
};
class instance_violet_hold : public InstanceMapScript class instance_violet_hold : public InstanceMapScript
{ {
public: public:
instance_violet_hold() : InstanceMapScript("instance_violet_hold", MAP_VIOLET_HOLD) { } instance_violet_hold() : InstanceMapScript("instance_violet_hold", MAP_VIOLET_HOLD) { }
InstanceScript* GetInstanceScript(InstanceMap* pMap) const override InstanceScript* GetInstanceScript(InstanceMap* map) const override
{ {
return new instance_violet_hold_InstanceMapScript(pMap); return new instance_violet_hold_InstanceMapScript(map);
} }
struct instance_violet_hold_InstanceMapScript : public InstanceScript struct instance_violet_hold_InstanceMapScript : public InstanceScript
{ {
instance_violet_hold_InstanceMapScript(Map* pMap) : InstanceScript(pMap) {} instance_violet_hold_InstanceMapScript(Map* map) : InstanceScript(map)
{
uint32 m_auiEncounter[MAX_ENCOUNTER]; SetHeaders(DataHeader);
bool CLEANED; SetBossNumber(MAX_BOSS);
uint8 EncounterStatus; SetPersistentDataCount(PERSISTENT_DATA_COUNT);
uint32 uiFirstBoss, uiSecondBoss; LoadObjectData(creatureData, goData);
std::string str_data; }
EventMap events;
uint8 GateHealth;
uint8 WaveCount;
uint8 PortalLocation;
bool bAchiev;
bool bDefensesUsed;
GuidVector GO_ActivationCrystalGUID;
ObjectGuid GO_MainGateGUID;
ObjectGuid GO_MoraggCellGUID;
ObjectGuid GO_ErekemCellGUID;
ObjectGuid GO_ErekemRightGuardCellGUID;
ObjectGuid GO_ErekemLeftGuardCellGUID;
ObjectGuid GO_IchoronCellGUID;
ObjectGuid GO_LavanthorCellGUID;
ObjectGuid GO_XevozzCellGUID;
ObjectGuid GO_ZuramatCellGUID;
GuidSet trashMobs;
ObjectGuid NPC_SinclariGUID;
ObjectGuid NPC_GuardGUID[4];
ObjectGuid NPC_PortalGUID;
ObjectGuid NPC_DoorSealGUID;
ObjectGuid NPC_MoraggGUID;
ObjectGuid NPC_ErekemGUID;
ObjectGuid NPC_ErekemGuardGUID[2];
ObjectGuid NPC_IchoronGUID;
ObjectGuid NPC_LavanthorGUID;
ObjectGuid NPC_XevozzGUID;
ObjectGuid NPC_ZuramatGUID;
ObjectGuid NPC_CyanigosaGUID;
void Initialize() override void Initialize() override
{ {
SetHeaders(DataHeader); _cleaned = false;
memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); _encounterStatus = NOT_STARTED;
CLEANED = false; _events.Reset();
EncounterStatus = NOT_STARTED; _events.RescheduleEvent(EVENT_CHECK_PLAYERS, 0ms);
uiFirstBoss = 0; _gateHealth = 100;
uiSecondBoss = 0; _waveCount = 0;
events.Reset(); _portalLocation = 0;
events.RescheduleEvent(EVENT_CHECK_PLAYERS, 0ms); _defensesUsed = false;
GateHealth = 100;
WaveCount = 0;
PortalLocation = 0;
bDefensesUsed = false;
GO_ActivationCrystalGUID.clear(); _activationCrystalGuidList.clear();
} }
bool IsEncounterInProgress() const override bool IsEncounterInProgress() const override
{ {
return false; return _encounterStatus == IN_PROGRESS;
} }
void OnCreatureCreate(Creature* creature) override void OnCreatureCreate(Creature* creature) override
{ {
InstanceScript::OnCreatureCreate(creature);
switch (creature->GetEntry()) switch (creature->GetEntry())
{ {
case NPC_SINCLARI:
NPC_SinclariGUID = creature->GetGUID();
break;
case NPC_VIOLET_HOLD_GUARD: case NPC_VIOLET_HOLD_GUARD:
for (uint8 i = 0; i < 4; ++i) for (ObjectGuid& guid : _guardGuid)
if (!NPC_GuardGUID[i]) if (!guid)
{ {
NPC_GuardGUID[i] = creature->GetGUID(); guid = creature->GetGUID();
break; break;
} }
break; break;
case NPC_DEFENSE_DUMMY_TARGET: case NPC_DEFENSE_DUMMY_TARGET:
creature->ApplySpellImmune(0, IMMUNITY_ID, SPELL_ARCANE_LIGHTNING, true); creature->ApplySpellImmune(0, IMMUNITY_ID, SPELL_ARCANE_LIGHTNING, true);
break; break;
case NPC_TELEPORTATION_PORTAL:
NPC_PortalGUID = creature->GetGUID();
break;
case NPC_PRISON_DOOR_SEAL:
NPC_DoorSealGUID = creature->GetGUID();
break;
// BOSSES BELOW:
case NPC_XEVOZZ:
NPC_XevozzGUID = creature->GetGUID();
break;
case NPC_LAVANTHOR:
NPC_LavanthorGUID = creature->GetGUID();
break;
case NPC_ICHORON:
NPC_IchoronGUID = creature->GetGUID();
break;
case NPC_ZURAMAT:
NPC_ZuramatGUID = creature->GetGUID();
break;
case NPC_EREKEM:
NPC_ErekemGUID = creature->GetGUID();
break;
case NPC_EREKEM_GUARD: case NPC_EREKEM_GUARD:
if (!NPC_ErekemGuardGUID[0]) if (!_erekemGuardGuid[0])
NPC_ErekemGuardGUID[0] = creature->GetGUID(); _erekemGuardGuid[0] = creature->GetGUID();
else else
NPC_ErekemGuardGUID[1] = creature->GetGUID(); _erekemGuardGuid[1] = creature->GetGUID();
break;
case NPC_MORAGG:
NPC_MoraggGUID = creature->GetGUID();
break;
case NPC_CYANIGOSA:
NPC_CyanigosaGUID = creature->GetGUID();
break; break;
} }
} }
void OnGameObjectCreate(GameObject* go) override void OnGameObjectCreate(GameObject* go) override
{ {
switch (go->GetEntry()) InstanceScript::OnGameObjectCreate(go);
if (go->GetEntry() == GO_ACTIVATION_CRYSTAL)
{ {
case GO_ACTIVATION_CRYSTAL: HandleGameObject(ObjectGuid::Empty, false, go);
HandleGameObject(ObjectGuid::Empty, false, go); // make go not used yet go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); // not useable at the beginning _activationCrystalGuidList.push_back(go->GetGUID());
GO_ActivationCrystalGUID.push_back(go->GetGUID()); }
}
bool SetBossState(uint32 id, EncounterState state) override
{
if (!InstanceScript::SetBossState(id, state))
return false;
switch (id)
{
case BOSS_MORAGG:
case BOSS_EREKEM:
case BOSS_ICHORON:
case BOSS_LAVANTHOR:
case BOSS_XEVOZZ:
case BOSS_ZURAMAT:
if (state == DONE)
{
if (_waveCount == 6)
SetBossState(DATA_1ST_BOSS, DONE);
else if (_waveCount == 12)
SetBossState(DATA_2ND_BOSS, DONE);
_events.RescheduleEvent(EVENT_SUMMON_PORTAL, 35s);
}
else if (state == FAIL || state == NOT_STARTED)
{
_cleaned = false;
InstanceCleanup();
}
break; break;
case GO_MAIN_DOOR: case DATA_CYANIGOSA:
GO_MainGateGUID = go->GetGUID(); if (state == DONE)
{
_encounterStatus = DONE;
HandleGameObject(DATA_MAIN_DOOR, true);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 0);
if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{
sinclari->AI()->Talk(SAY_SINCLARI_COMPLETE);
sinclari->DespawnOrUnsummon();
sinclari->SetRespawnTime(3);
}
}
else if (state == FAIL || state == NOT_STARTED)
{
_cleaned = false;
InstanceCleanup();
}
break; break;
// BOSS GATES BELOW: default:
case GO_EREKEM_GUARD_1_DOOR:
GO_ErekemLeftGuardCellGUID = go->GetGUID();
break;
case GO_EREKEM_GUARD_2_DOOR:
GO_ErekemRightGuardCellGUID = go->GetGUID();
break;
case GO_EREKEM_DOOR:
GO_ErekemCellGUID = go->GetGUID();
break;
case GO_ZURAMAT_DOOR:
GO_ZuramatCellGUID = go->GetGUID();
break;
case GO_LAVANTHOR_DOOR:
GO_LavanthorCellGUID = go->GetGUID();
break;
case GO_MORAGG_DOOR:
GO_MoraggCellGUID = go->GetGUID();
break;
case GO_ICHORON_DOOR:
GO_IchoronCellGUID = go->GetGUID();
break;
case GO_XEVOZZ_DOOR:
GO_XevozzCellGUID = go->GetGUID();
break; break;
} }
return true;
} }
void SetData(uint32 type, uint32 data) override void SetData(uint32 type, uint32 data) override
@@ -208,90 +196,57 @@ public:
case DATA_ACTIVATE_DEFENSE_SYSTEM: case DATA_ACTIVATE_DEFENSE_SYSTEM:
{ {
if (data) if (data)
bDefensesUsed = true; _defensesUsed = true;
const Position pos = {1919.09546f, 812.29724f, 86.2905f, M_PI}; Position const pos = {1919.09546f, 812.29724f, 86.2905f, M_PI};
instance->SummonCreature(NPC_DEFENSE_SYSTEM, pos, 0, 6499); instance->SummonCreature(NPC_DEFENSE_SYSTEM, pos, 0, 6499);
} }
break; break;
case DATA_START_INSTANCE: case DATA_START_INSTANCE:
if (EncounterStatus == NOT_STARTED) if (_encounterStatus == NOT_STARTED)
{ {
EncounterStatus = IN_PROGRESS; _encounterStatus = IN_PROGRESS;
if (Creature* c = instance->GetCreature(NPC_SinclariGUID)) if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{ {
c->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); sinclari->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
c->AI()->Talk(SAY_SINCLARI_LEAVING); sinclari->AI()->Talk(SAY_SINCLARI_LEAVING);
/// @todo: Missing orientation for Sinclari's movement and "interaction" animation with the nearby crystal.
} }
events.RescheduleEvent(EVENT_GUARDS_FALL_BACK, 4s); _events.RescheduleEvent(EVENT_GUARDS_FALL_BACK, 4s);
} }
break; break;
case DATA_PORTAL_DEFEATED: case DATA_PORTAL_DEFEATED:
events.RescheduleEvent(EVENT_SUMMON_PORTAL, 3s); _events.RescheduleEvent(EVENT_SUMMON_PORTAL, 3s);
break; break;
case DATA_PORTAL_LOCATION: case DATA_PORTAL_LOCATION:
PortalLocation = data; _portalLocation = data;
break; break;
case DATA_DECRASE_DOOR_HEALTH: case DATA_DECREASE_DOOR_HEALTH:
if (GateHealth > 0) if (_gateHealth > 0)
--GateHealth; --_gateHealth;
if (GateHealth == 0) if (_gateHealth == 0)
{ {
CLEANED = false; _cleaned = false;
InstanceCleanup(); InstanceCleanup();
} }
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_PRISON_STATE, (uint32)GateHealth); DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_PRISON_STATE, (uint32)_gateHealth);
break; break;
case DATA_RELEASE_BOSS: case DATA_RELEASE_BOSS:
if (WaveCount == 6) if (_waveCount == 6)
StartBossEncounter(uiFirstBoss); StartBossEncounter(GetPersistentData(PERSISTENT_DATA_FIRST_BOSS));
else else
StartBossEncounter(uiSecondBoss); StartBossEncounter(GetPersistentData(PERSISTENT_DATA_SECOND_BOSS));
break;
case DATA_BOSS_DIED:
if (WaveCount == 6)
m_auiEncounter[0] = DONE;
else if (WaveCount == 12)
m_auiEncounter[1] = DONE;
else if (WaveCount == 18)
{
m_auiEncounter[2] = DONE;
EncounterStatus = DONE;
HandleGameObject(GO_MainGateGUID, true);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 0);
if (Creature* c = instance->GetCreature(NPC_SinclariGUID))
{
c->AI()->Talk(SAY_SINCLARI_COMPLETE);
c->DespawnOrUnsummon();
c->SetRespawnTime(3);
}
}
SaveToDB();
if (WaveCount < 18)
events.RescheduleEvent(EVENT_SUMMON_PORTAL, 35s);
break;
case DATA_FAILED:
CLEANED = false;
InstanceCleanup();
break; break;
case DATA_ACHIEV: case DATA_ACHIEV:
bAchiev = !!data; _achievementCompleted = !!data;
break; break;
} }
} }
void SetGuidData(uint32 type, ObjectGuid data) override void SetGuidData(uint32 type, ObjectGuid data) override
{ {
switch (type) if (type == DATA_ADD_TRASH_MOB)
{ _trashMobs.insert(data);
case DATA_ADD_TRASH_MOB: else if (type == DATA_DELETE_TRASH_MOB && !_cleaned)
trashMobs.insert(data); _trashMobs.erase(data);
break;
case DATA_DELETE_TRASH_MOB:
if (!CLEANED)
trashMobs.erase(data);
break;
}
} }
uint32 GetData(uint32 type) const override uint32 GetData(uint32 type) const override
@@ -299,15 +254,11 @@ public:
switch (type) switch (type)
{ {
case DATA_ENCOUNTER_STATUS: case DATA_ENCOUNTER_STATUS:
return (uint32)EncounterStatus; return (uint32)_encounterStatus;
case DATA_WAVE_COUNT: case DATA_WAVE_COUNT:
return (uint32)WaveCount; return (uint32)_waveCount;
case DATA_PORTAL_LOCATION: case DATA_PORTAL_LOCATION:
return PortalLocation; return _portalLocation;
case DATA_FIRST_BOSS_NUMBER:
return uiFirstBoss;
case DATA_SECOND_BOSS_NUMBER:
return uiSecondBoss;
} }
return 0; return 0;
@@ -315,212 +266,180 @@ public:
ObjectGuid GetGuidData(uint32 identifier) const override ObjectGuid GetGuidData(uint32 identifier) const override
{ {
switch (identifier) if (identifier == DATA_EREKEM_GUARD_1_GUID)
{ return _erekemGuardGuid[0];
case DATA_TELEPORTATION_PORTAL_GUID: if (identifier == DATA_EREKEM_GUARD_2_GUID)
return NPC_PortalGUID; return _erekemGuardGuid[1];
case DATA_DOOR_SEAL_GUID:
return NPC_DoorSealGUID;
case DATA_EREKEM_GUID:
return NPC_ErekemGUID;
case DATA_EREKEM_GUARD_1_GUID:
return NPC_ErekemGuardGUID[0];
case DATA_EREKEM_GUARD_2_GUID:
return NPC_ErekemGuardGUID[1];
case DATA_ICHORON_GUID:
return NPC_IchoronGUID;
}
return ObjectGuid::Empty; return ObjectGuid::Empty;
} }
void StartBossEncounter(uint8 uiBoss) void StartBossEncounter(uint32 bossId)
{ {
Creature* pBoss = nullptr; switch (bossId)
switch (uiBoss)
{ {
case BOSS_MORAGG: case BOSS_MORAGG:
HandleGameObject(GO_MoraggCellGUID, true); HandleGameObject(DATA_MORAGG_CELL, true);
pBoss = instance->GetCreature(NPC_MoraggGUID);
if (pBoss)
pBoss->GetMotionMaster()->MovePoint(0, BossStartMove1);
break; break;
case BOSS_EREKEM: case BOSS_EREKEM:
HandleGameObject(GO_ErekemCellGUID, true); HandleGameObject(DATA_EREKEM_CELL, true);
HandleGameObject(GO_ErekemRightGuardCellGUID, true); HandleGameObject(DATA_EREKEM_GUARD_2_CELL, true);
HandleGameObject(GO_ErekemLeftGuardCellGUID, true); HandleGameObject(DATA_EREKEM_GUARD_1_CELL, true);
pBoss = instance->GetCreature(NPC_ErekemGUID); if (Creature* guard1 = instance->GetCreature(_erekemGuardGuid[0]))
if (pBoss)
pBoss->GetMotionMaster()->MovePoint(0, BossStartMove2);
if (Creature* pGuard1 = instance->GetCreature(NPC_ErekemGuardGUID[0]))
{ {
pGuard1->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); guard1->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
pGuard1->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); guard1->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
pGuard1->SetImmuneToNPC(false); guard1->SetImmuneToNPC(false);
pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21); guard1->GetMotionMaster()->MovePoint(0, BossStartMove21);
} }
if (Creature* pGuard2 = instance->GetCreature(NPC_ErekemGuardGUID[1])) if (Creature* guard2 = instance->GetCreature(_erekemGuardGuid[1]))
{ {
pGuard2->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); guard2->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
pGuard2->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); guard2->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
pGuard2->SetImmuneToNPC(false); guard2->SetImmuneToNPC(false);
pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22); guard2->GetMotionMaster()->MovePoint(0, BossStartMove22);
} }
break; break;
case BOSS_ICHORON: case BOSS_ICHORON:
HandleGameObject(GO_IchoronCellGUID, true); HandleGameObject(DATA_ICHORON_CELL, true);
pBoss = instance->GetCreature(NPC_IchoronGUID);
if (pBoss)
pBoss->GetMotionMaster()->MovePoint(0, BossStartMove3);
break; break;
case BOSS_LAVANTHOR: case BOSS_LAVANTHOR:
HandleGameObject(GO_LavanthorCellGUID, true); HandleGameObject(DATA_LAVANTHOR_CELL, true);
pBoss = instance->GetCreature(NPC_LavanthorGUID);
if (pBoss)
pBoss->GetMotionMaster()->MovePoint(0, BossStartMove4);
break; break;
case BOSS_XEVOZZ: case BOSS_XEVOZZ:
HandleGameObject(GO_XevozzCellGUID, true); HandleGameObject(DATA_XEVOZZ_CELL, true);
pBoss = instance->GetCreature(NPC_XevozzGUID);
if (pBoss)
pBoss->GetMotionMaster()->MovePoint(0, BossStartMove5);
break; break;
case BOSS_ZURAMAT: case BOSS_ZURAMAT:
HandleGameObject(GO_ZuramatCellGUID, true); HandleGameObject(DATA_ZURAMAT_CELL, true);
pBoss = instance->GetCreature(NPC_ZuramatGUID);
if (pBoss)
pBoss->GetMotionMaster()->MovePoint(0, BossStartMove6);
break; break;
} }
if (pBoss) static Position const BossStartPositions[] =
{ {
pBoss->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); BossStartMove1, // BOSS_MORAGG
pBoss->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); BossStartMove2, // BOSS_EREKEM
pBoss->SetImmuneToNPC(false); BossStartMove3, // BOSS_ICHORON
pBoss->SetReactState(REACT_AGGRESSIVE); BossStartMove4, // BOSS_LAVANTHOR
if ((WaveCount == 6 && m_auiEncounter[0] == DONE) || (WaveCount == 12 && m_auiEncounter[1] == DONE)) BossStartMove5, // BOSS_XEVOZZ
pBoss->SetLootMode(0); BossStartMove6, // BOSS_ZURAMAT
};
Creature* boss = GetCreature(bossId);
if (boss)
{
boss->GetMotionMaster()->MovePoint(0, BossStartPositions[bossId - BOSS_MORAGG]);
boss->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
boss->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
boss->SetImmuneToNPC(false);
boss->SetReactState(REACT_AGGRESSIVE);
if ((_waveCount == 6 && GetBossState(DATA_1ST_BOSS) == DONE) || (_waveCount == 12 && GetBossState(DATA_2ND_BOSS) == DONE))
boss->SetLootMode(0);
} }
} }
void Update(uint32 diff) override void Update(uint32 diff) override
{ {
events.Update(diff); _events.Update(diff);
switch (events.ExecuteEvent()) switch (_events.ExecuteEvent())
{ {
case 0:
break;
case EVENT_CHECK_PLAYERS: case EVENT_CHECK_PLAYERS:
{ if (DoNeedCleanup(false))
if (DoNeedCleanup(false)) InstanceCleanup();
InstanceCleanup(); _events.Repeat(5s);
events.Repeat(5s);
}
break; break;
case EVENT_GUARDS_FALL_BACK: case EVENT_GUARDS_FALL_BACK:
{ for (ObjectGuid const& guid : _guardGuid)
for (uint8 i = 0; i < 4; ++i) if (Creature* guard = instance->GetCreature(guid))
if (Creature* c = instance->GetCreature(NPC_GuardGUID[i])) {
{ guard->SetReactState(REACT_PASSIVE);
c->SetReactState(REACT_PASSIVE); guard->CombatStop();
c->CombatStop(); guard->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); guard->GetMotionMaster()->MovePoint(0, guardMovePosition);
c->GetMotionMaster()->MovePoint(0, guardMovePosition); }
} _events.RescheduleEvent(EVENT_GUARDS_DISAPPEAR, 5s);
events.RescheduleEvent(EVENT_GUARDS_DISAPPEAR, 5s);
}
break; break;
case EVENT_GUARDS_DISAPPEAR: case EVENT_GUARDS_DISAPPEAR:
{ for (ObjectGuid const& guid : _guardGuid)
for (uint8 i = 0; i < 4; ++i) if (Creature* guard = instance->GetCreature(guid))
if (Creature* c = instance->GetCreature(NPC_GuardGUID[i])) guard->SetVisible(false);
c->SetVisible(false); _events.RescheduleEvent(EVENT_SINCLARI_FALL_BACK, 2s);
events.RescheduleEvent(EVENT_SINCLARI_FALL_BACK, 2s);
}
break; break;
case EVENT_SINCLARI_FALL_BACK: case EVENT_SINCLARI_FALL_BACK:
if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{ {
if (Creature* c = instance->GetCreature(NPC_SinclariGUID)) sinclari->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
{ sinclari->GetMotionMaster()->MovePoint(0, sinclariOutsidePosition);
c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
c->GetMotionMaster()->MovePoint(0, sinclariOutsidePosition);
}
SetData(DATA_ACTIVATE_DEFENSE_SYSTEM, 0);
events.RescheduleEvent(EVENT_START_ENCOUNTER, 4s);
} }
SetData(DATA_ACTIVATE_DEFENSE_SYSTEM, 0);
_events.RescheduleEvent(EVENT_START_ENCOUNTER, 4s);
break; break;
case EVENT_START_ENCOUNTER: case EVENT_START_ENCOUNTER:
if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{ {
if (Creature* c = instance->GetCreature(NPC_SinclariGUID)) sinclari->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
{ sinclari->AI()->Talk(SAY_SINCLARI_DOOR_LOCK);
c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
c->AI()->Talk(SAY_SINCLARI_DOOR_LOCK);
}
if (Creature* c = instance->GetCreature(NPC_DoorSealGUID))
{
c->RemoveAllAuras(); // just to be sure...
}
GateHealth = 100;
HandleGameObject(GO_MainGateGUID, false);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 1);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_PRISON_STATE, (uint32)GateHealth);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_WAVE_COUNT, (uint32)WaveCount);
for (ObjectGuid const& guid : GO_ActivationCrystalGUID)
if (GameObject* go = instance->GetGameObject(guid))
{
HandleGameObject(ObjectGuid::Empty, false, go); // not used yet
go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); // make it useable
}
events.RescheduleEvent(EVENT_SUMMON_PORTAL, 4s);
} }
if (Creature* doorSeal = GetCreature(DATA_DOOR_SEAL))
doorSeal->RemoveAllAuras();
_gateHealth = 100;
HandleGameObject(DATA_MAIN_DOOR, false);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 1);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_PRISON_STATE, (uint32)_gateHealth);
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_WAVE_COUNT, (uint32)_waveCount);
for (ObjectGuid const& guid : _activationCrystalGuidList)
if (GameObject* go = instance->GetGameObject(guid))
{
HandleGameObject(ObjectGuid::Empty, false, go);
go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
_events.RescheduleEvent(EVENT_SUMMON_PORTAL, 4s);
break; break;
case EVENT_SUMMON_PORTAL: case EVENT_SUMMON_PORTAL:
++WaveCount; ++_waveCount;
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_WAVE_COUNT, (uint32)WaveCount); DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_WAVE_COUNT, (uint32)_waveCount);
SetData(DATA_PORTAL_LOCATION, (GetData(DATA_PORTAL_LOCATION) + urand(1, 5)) % 6); SetData(DATA_PORTAL_LOCATION, (GetData(DATA_PORTAL_LOCATION) + urand(1, 5)) % 6);
if (Creature* c = instance->GetCreature(NPC_SinclariGUID)) if (Creature* sinclari = GetCreature(DATA_SINCLARI))
{ {
if (WaveCount % 6 != 0) if (_waveCount % 6 != 0)
c->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocations[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN); sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocations[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN);
else if (WaveCount == 6 || WaveCount == 12) // first or second boss else if (_waveCount == 6 || _waveCount == 12)
{ {
if (!uiFirstBoss || !uiSecondBoss) if (!GetPersistentData(PERSISTENT_DATA_FIRST_BOSS) || !GetPersistentData(PERSISTENT_DATA_SECOND_BOSS))
{ {
uiFirstBoss = urand(1, 6); uint32 firstBoss = urand(BOSS_MORAGG, BOSS_ZURAMAT);
do { uiSecondBoss = urand(1, 6); } uint32 secondBoss;
while (uiFirstBoss == uiSecondBoss); do { secondBoss = urand(BOSS_MORAGG, BOSS_ZURAMAT); }
SaveToDB(); while (firstBoss == secondBoss);
StorePersistentData(PERSISTENT_DATA_FIRST_BOSS, firstBoss);
StorePersistentData(PERSISTENT_DATA_SECOND_BOSS, secondBoss);
} }
c->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN); sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN);
} }
else // cyanigossa else
{ {
if (Creature* cyanigosa = c->SummonCreature(NPC_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN)) if (Creature* cyanigosa = sinclari->SummonCreature(NPC_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN))
{ {
cyanigosa->CastSpell(cyanigosa, SPELL_CYANIGOSA_BLUE_AURA, false); cyanigosa->CastSpell(cyanigosa, SPELL_CYANIGOSA_BLUE_AURA, false);
cyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN); cyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN);
cyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f); cyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f);
} }
events.RescheduleEvent(EVENT_CYANIGOSSA_TRANSFORM, 10s); _events.RescheduleEvent(EVENT_CYANIGOSA_TRANSFORM, 10s);
} }
} }
break; break;
case EVENT_CYANIGOSSA_TRANSFORM: case EVENT_CYANIGOSA_TRANSFORM:
if (Creature* c = instance->GetCreature(NPC_CyanigosaGUID)) if (Creature* cyanigosa = GetCreature(DATA_CYANIGOSA))
{ {
c->RemoveAurasDueToSpell(SPELL_CYANIGOSA_BLUE_AURA); cyanigosa->RemoveAurasDueToSpell(SPELL_CYANIGOSA_BLUE_AURA);
c->CastSpell(c, SPELL_CYANIGOSA_TRANSFORM, 0); cyanigosa->CastSpell(cyanigosa, SPELL_CYANIGOSA_TRANSFORM, 0);
events.RescheduleEvent(EVENT_CYANIGOSA_ATTACK, 2500ms); _events.RescheduleEvent(EVENT_CYANIGOSA_ATTACK, 2500ms);
} }
break; break;
case EVENT_CYANIGOSA_ATTACK: case EVENT_CYANIGOSA_ATTACK:
if (Creature* c = instance->GetCreature(NPC_CyanigosaGUID)) if (Creature* cyanigosa = GetCreature(DATA_CYANIGOSA))
{ {
c->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); cyanigosa->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
c->SetImmuneToNPC(false); cyanigosa->SetImmuneToNPC(false);
} }
break; break;
} }
@@ -531,121 +450,118 @@ public:
if (DoNeedCleanup(plr->IsAlive())) if (DoNeedCleanup(plr->IsAlive()))
InstanceCleanup(); InstanceCleanup();
if (EncounterStatus == IN_PROGRESS) if (_encounterStatus == IN_PROGRESS)
{ {
plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 1); plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 1);
plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_PRISON_STATE, (uint32)GateHealth); plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_PRISON_STATE, (uint32)_gateHealth);
plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_WAVE_COUNT, (uint32)WaveCount); plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_WAVE_COUNT, (uint32)_waveCount);
} }
else else
plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 0); plr->SendUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 0);
events.RescheduleEvent(EVENT_CHECK_PLAYERS, 5s); _events.RescheduleEvent(EVENT_CHECK_PLAYERS, 5s);
} }
bool DoNeedCleanup(bool enter) bool DoNeedCleanup(bool enter)
{ {
uint8 aliveCount = 0; uint32 aliveCount = instance->GetPlayersCountExceptGMs(true);
Map::PlayerList const& pl = instance->GetPlayers();
for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
if (Player* plr = itr->GetSource())
if (plr->IsAlive() && !plr->IsGameMaster() && !plr->HasAura(27827)/*spirit of redemption aura*/ )
++aliveCount;
bool need = enter ? aliveCount <= 1 : aliveCount == 0; bool need = enter ? aliveCount <= 1 : aliveCount == 0;
if (!need && CLEANED) if (!need && _cleaned)
CLEANED = false; _cleaned = false;
return need; return need;
} }
void InstanceCleanup() void InstanceCleanup()
{ {
if (CLEANED) if (_cleaned)
return; return;
CLEANED = true; _cleaned = true;
// reset defense crystals for (ObjectGuid const& guid : _activationCrystalGuidList)
for (ObjectGuid const& guid : GO_ActivationCrystalGUID)
if (GameObject* go = instance->GetGameObject(guid)) if (GameObject* go = instance->GetGameObject(guid))
{ {
HandleGameObject(ObjectGuid::Empty, false, go); // not used yet HandleGameObject(ObjectGuid::Empty, false, go);
go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); // not useable at the beginning go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
} }
// reset positions of Sinclari and Guards if (Creature* sinclari = GetCreature(DATA_SINCLARI))
if (Creature* c = instance->GetCreature(NPC_SinclariGUID))
{ {
c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); sinclari->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
c->DespawnOrUnsummon(); sinclari->DespawnOrUnsummon();
c->SetRespawnTime(3); sinclari->SetRespawnTime(3);
} }
for (uint8 i = 0; i < 4; ++i) for (ObjectGuid const& guid : _guardGuid)
if (Creature* c = instance->GetCreature(NPC_GuardGUID[i])) if (Creature* guard = instance->GetCreature(guid))
{ {
c->DespawnOrUnsummon(); guard->DespawnOrUnsummon();
c->SetRespawnTime(3); guard->SetRespawnTime(3);
if (m_auiEncounter[MAX_ENCOUNTER - 1] == DONE) guard->SetVisible(GetBossState(DATA_CYANIGOSA) != DONE);
c->SetVisible(false); guard->SetReactState(REACT_AGGRESSIVE);
else
c->SetVisible(true);
c->SetReactState(REACT_AGGRESSIVE);
} }
// remove portal if any if (Creature* portal = GetCreature(DATA_TELEPORTATION_PORTAL))
if (Creature* c = instance->GetCreature(NPC_PortalGUID)) portal->DespawnOrUnsummon();
c->DespawnOrUnsummon();
NPC_PortalGUID.Clear();
// remove trash for (ObjectGuid const& guid : _trashMobs)
for (ObjectGuid const& guid : trashMobs) if (Creature* trash = instance->GetCreature(guid))
if (Creature* c = instance->GetCreature(guid)) trash->DespawnOrUnsummon();
c->DespawnOrUnsummon();
trashMobs.clear(); _trashMobs.clear();
// clear door seal damaging auras: if (Creature* doorSeal = GetCreature(DATA_DOOR_SEAL))
if (Creature* c = instance->GetCreature(NPC_DoorSealGUID)) doorSeal->RemoveAllAuras();
c->RemoveAllAuras();
// open main gate HandleGameObject(DATA_MAIN_DOOR, true);
HandleGameObject(GO_MainGateGUID, true);
if (m_auiEncounter[MAX_ENCOUNTER - 1] != DONE) // instance not finished if (GetBossState(DATA_CYANIGOSA) != DONE)
{ {
// close all cells HandleGameObject(DATA_MORAGG_CELL, false);
HandleGameObject(GO_MoraggCellGUID, false); HandleGameObject(DATA_EREKEM_CELL, false);
HandleGameObject(GO_ErekemCellGUID, false); HandleGameObject(DATA_EREKEM_GUARD_2_CELL, false);
HandleGameObject(GO_ErekemRightGuardCellGUID, false); HandleGameObject(DATA_EREKEM_GUARD_1_CELL, false);
HandleGameObject(GO_ErekemLeftGuardCellGUID, false); HandleGameObject(DATA_ICHORON_CELL, false);
HandleGameObject(GO_IchoronCellGUID, false); HandleGameObject(DATA_LAVANTHOR_CELL, false);
HandleGameObject(GO_LavanthorCellGUID, false); HandleGameObject(DATA_XEVOZZ_CELL, false);
HandleGameObject(GO_XevozzCellGUID, false); HandleGameObject(DATA_ZURAMAT_CELL, false);
HandleGameObject(GO_ZuramatCellGUID, false);
// respawn bosses for (uint32 id = BOSS_MORAGG; id <= BOSS_ZURAMAT; ++id)
if (Creature* c = instance->GetCreature(NPC_MoraggGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } {
if (Creature* c = instance->GetCreature(NPC_MoraggGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } if (Creature* boss = GetCreature(id))
if (Creature* c = instance->GetCreature(NPC_ErekemGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } {
if (Creature* c = instance->GetCreature(NPC_ErekemGuardGUID[0])) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } boss->DespawnOrUnsummon();
if (Creature* c = instance->GetCreature(NPC_ErekemGuardGUID[1])) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } boss->SetRespawnTime(3);
if (Creature* c = instance->GetCreature(NPC_IchoronGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } boss->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
if (Creature* c = instance->GetCreature(NPC_LavanthorGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } boss->SetImmuneToNPC(true);
if (Creature* c = instance->GetCreature(NPC_XevozzGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } }
if (Creature* c = instance->GetCreature(NPC_ZuramatGUID)) { c->DespawnOrUnsummon(); c->SetRespawnTime(3); c->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); c->SetImmuneToNPC(true); } }
if (Creature* c = instance->GetCreature(NPC_CyanigosaGUID)) { c->DespawnOrUnsummon(); } if (Creature* guard1 = instance->GetCreature(_erekemGuardGuid[0]))
{
guard1->DespawnOrUnsummon();
guard1->SetRespawnTime(3);
guard1->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
guard1->SetImmuneToNPC(true);
}
if (Creature* guard2 = instance->GetCreature(_erekemGuardGuid[1]))
{
guard2->DespawnOrUnsummon();
guard2->SetRespawnTime(3);
guard2->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
guard2->SetImmuneToNPC(true);
}
if (Creature* cyanigosa = GetCreature(DATA_CYANIGOSA))
cyanigosa->DespawnOrUnsummon();
} }
// reinitialize variables and events
DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 0); DoUpdateWorldState(WORLD_STATE_VIOLET_HOLD_SHOW, 0);
EncounterStatus = NOT_STARTED; _encounterStatus = NOT_STARTED;
GateHealth = 100; _gateHealth = 100;
WaveCount = 0; _waveCount = 0;
bDefensesUsed = false; _defensesUsed = false;
if (m_auiEncounter[MAX_ENCOUNTER - 1] == DONE) if (GetBossState(DATA_CYANIGOSA) == DONE)
EncounterStatus = DONE; _encounterStatus = DONE;
events.Reset(); _events.Reset();
events.RescheduleEvent(EVENT_CHECK_PLAYERS, 5s); _events.RescheduleEvent(EVENT_CHECK_PLAYERS, 5s);
} }
bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override
@@ -653,35 +569,31 @@ public:
switch (criteria_id) switch (criteria_id)
{ {
case CRITERIA_DEFENSELESS: case CRITERIA_DEFENSELESS:
return GateHealth == 100 && !bDefensesUsed; return _gateHealth == 100 && !_defensesUsed;
case CRITERIA_A_VOID_DANCE: case CRITERIA_A_VOID_DANCE:
case CRITERIA_DEHYDRATION: case CRITERIA_DEHYDRATION:
return bAchiev; return _achievementCompleted;
} }
return false; return false;
} }
void ReadSaveDataMore(std::istringstream& data) override private:
{ bool _cleaned{ false };
EncounterStatus = NOT_STARTED; uint8 _encounterStatus{ NOT_STARTED };
CLEANED = false; EventMap _events;
events.Reset(); uint8 _gateHealth{ 100 };
events.RescheduleEvent(EVENT_CHECK_PLAYERS, 0ms); uint8 _waveCount{ 0 };
uint8 _portalLocation{ 0 };
bool _achievementCompleted{ false };
bool _defensesUsed{ false };
data >> m_auiEncounter[0]; GuidVector _activationCrystalGuidList;
data >> m_auiEncounter[1];
data >> m_auiEncounter[2];
data >> uiFirstBoss;
}
void WriteSaveDataMore(std::ostringstream& data) override // Multi-instance creature tracking (can't use ObjectData)
{ ObjectGuid _guardGuid[4];
data << m_auiEncounter[0] << ' ' ObjectGuid _erekemGuardGuid[2];
<< m_auiEncounter[1] << ' '
<< m_auiEncounter[2] << ' ' GuidSet _trashMobs;
<< uiFirstBoss << ' '
<< uiSecondBoss << ' ';
}
}; };
}; };
File diff suppressed because it is too large Load Diff
@@ -18,15 +18,57 @@
#ifndef DEF_VIOLET_HOLD_H #ifndef DEF_VIOLET_HOLD_H
#define DEF_VIOLET_HOLD_H #define DEF_VIOLET_HOLD_H
#define MAX_ENCOUNTER 3
#include "CreatureAIImpl.h" #include "CreatureAIImpl.h"
#define DataHeader "VIO" #define DataHeader "VIO"
#define VioletHoldScriptName "instance_violet_hold" #define VioletHoldScriptName "instance_violet_hold"
enum Creatures enum VHData
{
// Creature ObjectData IDs
// Boss creatures use VHBosses values directly (BOSS_MORAGG .. BOSS_ZURAMAT, DATA_CYANIGOSA)
DATA_SINCLARI = 10,
DATA_DOOR_SEAL,
DATA_TELEPORTATION_PORTAL,
// GO ObjectData IDs
DATA_MAIN_DOOR = 20,
DATA_MORAGG_CELL,
DATA_EREKEM_CELL,
DATA_EREKEM_GUARD_1_CELL,
DATA_EREKEM_GUARD_2_CELL,
DATA_ICHORON_CELL,
DATA_LAVANTHOR_CELL,
DATA_XEVOZZ_CELL,
DATA_ZURAMAT_CELL,
// Instance action/state IDs (used by SetData/GetData)
DATA_ENCOUNTER_STATUS = 30,
DATA_ACTIVATE_DEFENSE_SYSTEM,
DATA_START_INSTANCE,
DATA_ADD_TRASH_MOB,
DATA_DELETE_TRASH_MOB,
DATA_PORTAL_DEFEATED,
DATA_WAVE_COUNT,
DATA_PORTAL_LOCATION,
DATA_RELEASE_BOSS,
DATA_DECREASE_DOOR_HEALTH,
DATA_ACHIEV,
// Manual GUID tracking (multi-instance entries)
DATA_EREKEM_GUARD_1_GUID,
DATA_EREKEM_GUARD_2_GUID,
};
enum VHPersistentData
{
PERSISTENT_DATA_FIRST_BOSS,
PERSISTENT_DATA_SECOND_BOSS,
PERSISTENT_DATA_COUNT
};
enum VHCreatures
{ {
NPC_TELEPORTATION_PORTAL = 31011, NPC_TELEPORTATION_PORTAL = 31011,
NPC_DEFENSE_SYSTEM = 30837, NPC_DEFENSE_SYSTEM = 30837,
@@ -63,7 +105,7 @@ enum Creatures
NPC_AZURE_STALKER = 32191, NPC_AZURE_STALKER = 32191,
}; };
enum GameObjects enum VHGameObjects
{ {
GO_MAIN_DOOR = 191723, GO_MAIN_DOOR = 191723,
GO_XEVOZZ_DOOR = 191556, GO_XEVOZZ_DOOR = 191556,
@@ -78,19 +120,25 @@ enum GameObjects
GO_ACTIVATION_CRYSTAL = 193611, GO_ACTIVATION_CRYSTAL = 193611,
}; };
enum Bosses enum VHBosses
{ {
BOSS_NONE, // Encounter slot IDs (used by SetBossState/GetBossState)
BOSS_MORAGG, DATA_1ST_BOSS,
DATA_2ND_BOSS,
DATA_CYANIGOSA,
MAX_ENCOUNTER,
// Individual boss IDs (used by ObjectData and BossAI)
BOSS_MORAGG = MAX_ENCOUNTER,
BOSS_EREKEM, BOSS_EREKEM,
BOSS_ICHORON, BOSS_ICHORON,
BOSS_LAVANTHOR, BOSS_LAVANTHOR,
BOSS_XEVOZZ, BOSS_XEVOZZ,
BOSS_ZURAMAT, BOSS_ZURAMAT,
BOSS_CYANIGOSA MAX_BOSS
}; };
enum Spells enum VHSpells
{ {
SPELL_CONTROL_CRYSTAL_ACTIVATION = 57804, SPELL_CONTROL_CRYSTAL_ACTIVATION = 57804,
SPELL_DEFENSE_SYSTEM_SPAWN_EFFECT = 57886, SPELL_DEFENSE_SYSTEM_SPAWN_EFFECT = 57886,
@@ -104,7 +152,7 @@ enum Spells
SPELL_CYANIGOSA_BLUE_AURA = 45870 SPELL_CYANIGOSA_BLUE_AURA = 45870
}; };
enum Events enum VHInstanceEvents
{ {
EVENT_CHECK_PLAYERS = 1, EVENT_CHECK_PLAYERS = 1,
EVENT_GUARDS_FALL_BACK, EVENT_GUARDS_FALL_BACK,
@@ -112,7 +160,7 @@ enum Events
EVENT_SINCLARI_FALL_BACK, EVENT_SINCLARI_FALL_BACK,
EVENT_START_ENCOUNTER, EVENT_START_ENCOUNTER,
EVENT_SUMMON_PORTAL, EVENT_SUMMON_PORTAL,
EVENT_CYANIGOSSA_TRANSFORM, EVENT_CYANIGOSA_TRANSFORM,
EVENT_CYANIGOSA_ATTACK, EVENT_CYANIGOSA_ATTACK,
// Event defense system // Event defense system
@@ -120,32 +168,7 @@ enum Events
EVENT_ARCANE_LIGHTNING_INSTAKILL EVENT_ARCANE_LIGHTNING_INSTAKILL
}; };
enum Data enum VHAchievCriteria
{
DATA_ACTIVATE_DEFENSE_SYSTEM = 1,
DATA_ENCOUNTER_STATUS,
DATA_START_INSTANCE,
DATA_ADD_TRASH_MOB,
DATA_DELETE_TRASH_MOB,
DATA_PORTAL_DEFEATED,
DATA_WAVE_COUNT,
DATA_PORTAL_LOCATION,
DATA_TELEPORTATION_PORTAL_GUID,
DATA_DOOR_SEAL_GUID,
DATA_FIRST_BOSS_NUMBER,
DATA_SECOND_BOSS_NUMBER,
DATA_RELEASE_BOSS,
DATA_DECRASE_DOOR_HEALTH,
DATA_BOSS_DIED,
DATA_FAILED,
DATA_EREKEM_GUID,
DATA_EREKEM_GUARD_1_GUID,
DATA_EREKEM_GUARD_2_GUID,
DATA_ICHORON_GUID,
DATA_ACHIEV,
};
enum AchievCriteria
{ {
CRITERIA_DEFENSELESS = 6803, CRITERIA_DEFENSELESS = 6803,
CRITERIA_A_VOID_DANCE = 7587, CRITERIA_A_VOID_DANCE = 7587,
@@ -308,4 +331,6 @@ inline AI* GetVioletHoldAI(T* obj)
return GetInstanceAI<AI>(obj, VioletHoldScriptName); return GetInstanceAI<AI>(obj, VioletHoldScriptName);
} }
#define RegisterVioletHoldCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetVioletHoldAI)
#endif #endif