diff options
author | DDuarte <dnpd.dd@gmail.com> | 2015-07-12 14:55:04 +0100 |
---|---|---|
committer | DDuarte <dnpd.dd@gmail.com> | 2015-07-12 14:55:04 +0100 |
commit | 9aa91061312ed50c52f868bfe19a7321a4e29b90 (patch) | |
tree | 880dc81eb8ff9808e69341c7e1f1511e36e2e3b5 /src | |
parent | 197e8d92a5785eaa5fde9ab8c8f96c626b356046 (diff) |
Scripts/VioletHold: cherry-pick multiple commits from 3.3.5
---
Scripts/VioletHold: picked some things from pull request #11399 (thx MitchedD for initial work)
(cherry picked from commit 34a721ba84643cf468f63e5c375949aaa3e15cac)
by joschiwald
---
Core/Scripts: Rework Violet Hold bosses adding missing spells/mechanics:
- Cyanigosa, Arcane Vacuum
- Ichoron, globules mechanic
- Moragg, optic link visuals
- Lavanthor, minor changes
- Zuramat, correctly implement void sentries
- Erekem, implement Windfury and correct management of Erekem Guards
- Script for the pre-event
Thx @ManuFe
(cherry picked from commit 0bb7f89e82c65f6b750e5d96766c2092031803b5)
Conflicts:
src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
by mik1893
---
Rename 2015_06_08_01_world.sql to 2015_06_25_00_world.sql
(cherry picked from commit 8176902b17ce7050029f70a87bec3284c1090785)
by MitchesD
---
Scripts/VioletHold: fixed non-pch build and codestyle
(cherry picked from commit e34f74dacea82f85b3b945e23f3432deda4595b7)
by MitchesD
---
Scripts/VioletHold: Fix codestyle and unwanted crash in Violet/Hold
closes #14952 and #14953
(cherry picked from commit 49809bd404ae7b58ac81086d52297532ec85972a)
by mik1893
---
Scripts/VioletHold: fix a crash during Ichoron encounter
Closes #14962
(cherry picked from commit 7c01638d45b3eaed7af124a43f21cc6d15407667)
by mik1893
---
Core/Misc: Fix build warnings
(cherry picked from commit 55681666b3cc0e33eeb5cdb77e638e68c19f452c)
Conflicts:
src/server/authserver/Main.cpp
by jackpoz
Diffstat (limited to 'src')
10 files changed, 1489 insertions, 1060 deletions
diff --git a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp index 36d2c5f8ed3..dc923e534b0 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp @@ -23,12 +23,9 @@ enum Spells { SPELL_ARCANE_VACUUM = 58694, SPELL_BLIZZARD = 58693, - H_SPELL_BLIZZARD = 59369, SPELL_MANA_DESTRUCTION = 59374, SPELL_TAIL_SWEEP = 58690, - H_SPELL_TAIL_SWEEP = 59283, SPELL_UNCONTROLLABLE_ENERGY = 58688, - H_SPELL_UNCONTROLLABLE_ENERGY = 59281, SPELL_TRANSFORM = 58668 }; @@ -48,17 +45,11 @@ class boss_cyanigosa : public CreatureScript public: boss_cyanigosa() : CreatureScript("boss_cyanigosa") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_cyanigosaAI>(creature); - } - - struct boss_cyanigosaAI : public ScriptedAI + struct boss_cyanigosaAI : public BossAI { - boss_cyanigosaAI(Creature* creature) : ScriptedAI(creature) + boss_cyanigosaAI(Creature* creature) : BossAI(creature, DATA_CYANIGOSA) { Initialize(); - instance = creature->GetInstanceScript(); } void Initialize() @@ -76,24 +67,20 @@ public: uint32 uiTailSweepTimer; uint32 uiUncontrollableEnergyTimer; - InstanceScript* instance; - void Reset() override { Initialize(); - instance->SetData(DATA_CYANIGOSA_EVENT, NOT_STARTED); + BossAI::Reset(); } - void EnterCombat(Unit* /*who*/) override + void EnterCombat(Unit* who) override { + BossAI::EnterCombat(who); Talk(SAY_AGGRO); - - instance->SetData(DATA_CYANIGOSA_EVENT, IN_PROGRESS); } void MoveInLineOfSight(Unit* /*who*/) override { } - void UpdateAI(uint32 diff) override { if (instance->GetData(DATA_REMOVE_NPC) == 1) @@ -102,13 +89,12 @@ public: instance->SetData(DATA_REMOVE_NPC, 0); } - //Return since we have no target if (!UpdateVictim()) return; if (uiArcaneVacuumTimer <= diff) { - DoCast(SPELL_ARCANE_VACUUM); + DoCastAOE(SPELL_ARCANE_VACUUM); uiArcaneVacuumTimer = 10000; } else uiArcaneVacuumTimer -= diff; @@ -121,7 +107,7 @@ public: if (uiTailSweepTimer <= diff) { - DoCast(SPELL_TAIL_SWEEP); + DoCastVictim(SPELL_TAIL_SWEEP); uiTailSweepTimer = 20000; } else uiTailSweepTimer -= diff; @@ -144,22 +130,23 @@ public: DoMeleeAttackIfReady(); } - void JustDied(Unit* /*killer*/) override + void JustDied(Unit* killer) override { + BossAI::JustDied(killer); Talk(SAY_DEATH); - - instance->SetData(DATA_CYANIGOSA_EVENT, DONE); } void KilledUnit(Unit* victim) override { - if (victim->GetTypeId() != TYPEID_PLAYER) - return; - - Talk(SAY_SLAY); + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_cyanigosaAI>(creature); + } }; class achievement_defenseless : public AchievementCriteriaScript diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp index 2fd98bd48cf..1f9fc6d7981 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp @@ -24,12 +24,11 @@ enum Spells SPELL_BLOODLUST = 54516, SPELL_BREAK_BONDS = 59463, SPELL_CHAIN_HEAL = 54481, - H_SPELL_CHAIN_HEAL = 59473, SPELL_EARTH_SHIELD = 54479, - H_SPELL_EARTH_SHIELD = 59471, SPELL_EARTH_SHOCK = 54511, SPELL_LIGHTNING_BOLT = 53044, - SPELL_STORMSTRIKE = 51876 + SPELL_STORMSTRIKE = 51876, + SPELL_WINDFURY = 54493 }; enum Yells @@ -42,6 +41,17 @@ enum Yells SAY_BOTH_ADDS_KILLED = 5 }; +enum ErekemEvents +{ + EVENT_EARTH_SHIELD = 1, + EVENT_CHAIN_HEAL, + EVENT_BLOODLUST, + EVENT_LIGHTNING_BOLT, + EVENT_EARTH_SHOCK, + EVENT_WINDFURY, + EVENT_STORMSTRIKE +}; + class boss_erekem : public CreatureScript { public: @@ -62,39 +72,50 @@ public: void Initialize() { - uiBloodlustTimer = 15000; - uiChainHealTimer = 0; - uiEarthShockTimer = urand(2000, 8000); - uiLightningBoltTimer = urand(5000, 10000); - uiEarthShieldTimer = 20000; + phase = 0; + breakBondsCd = 0; } - uint32 uiBloodlustTimer; - uint32 uiChainHealTimer; - uint32 uiEarthShockTimer; - uint32 uiLightningBoltTimer; - uint32 uiEarthShieldTimer; - - InstanceScript* instance; - void Reset() override { Initialize(); + if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); - if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) { - if (!pGuard1->IsAlive()) - pGuard1->Respawn(); + if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) + pGuard1->DespawnOrUnsummon(); + if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) + pGuard2->DespawnOrUnsummon(); } - if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) + else { - if (!pGuard2->IsAlive()) - pGuard2->Respawn(); + if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) + { + if (!pGuard1->IsAlive()) + pGuard1->Respawn(); + } + if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) + { + if (!pGuard2->IsAlive()) + pGuard2->Respawn(); + } } + + events.Reset(); + } + + void JustReachedHome() override + { + if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) + pGuard1->Respawn(); + + if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) + pGuard2->Respawn(); } void AttackStart(Unit* who) override @@ -111,13 +132,13 @@ public: if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) { - pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); + pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); if (!pGuard1->GetVictim() && pGuard1->AI()) pGuard1->AI()->AttackStart(who); } if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) { - pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); + pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); if (!pGuard2->GetVictim() && pGuard2->AI()) pGuard2->AI()->AttackStart(who); } @@ -129,125 +150,160 @@ public: Talk(SAY_AGGRO); DoCast(me, SPELL_EARTH_SHIELD); - if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_EREKEM_CELL))) - if (pDoor->GetGoState() == GO_STATE_READY) + if (GameObject* door = instance->GetGameObject(DATA_EREKEM_CELL)) + if (door->GetGoState() == GO_STATE_READY) { EnterEvadeMode(); return; } if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_NPC); + + events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000); + events.ScheduleEvent(EVENT_BLOODLUST, 15000); + events.ScheduleEvent(EVENT_CHAIN_HEAL, 10000); + events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2000); } - void MoveInLineOfSight(Unit* /*who*/) override { } + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + + if (instance->GetData(DATA_WAVE_COUNT) == 6) + { + instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); + instance->SetData(DATA_WAVE_COUNT, 7); + } + else if (instance->GetData(DATA_WAVE_COUNT) == 12) + { + instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE); + instance->SetData(DATA_WAVE_COUNT, 13); + } + } + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } void UpdateAI(uint32 diff) override { - //Return since we have no target if (!UpdateVictim()) return; - //spam stormstrike in hc mode if spawns are dead - if (IsHeroic()) - { + if (phase == 0) if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) { if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) { if (!pGuard1->IsAlive() && !pGuard2->IsAlive()) + { + phase = 1; DoCastVictim(SPELL_STORMSTRIKE); + DoCast(SPELL_WINDFURY); + events.Reset(); + events.ScheduleEvent(EVENT_EARTH_SHOCK, urand(2000, 8000)); + events.ScheduleEvent(EVENT_WINDFURY, urand(1500, 2000)); + events.ScheduleEvent(EVENT_STORMSTRIKE, urand(1500, 2000)); + } } } - } - if (uiEarthShieldTimer <= diff) - { - DoCast(me, SPELL_EARTH_SHIELD); - uiEarthShieldTimer = 20000; - } else uiEarthShieldTimer -= diff; + events.Update(diff); - if (uiChainHealTimer <= diff) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (breakBondsCd <= 0) { - ObjectGuid TargetGUID = GetChainHealTargetGUID(); - if (!TargetGUID.IsEmpty()) + if (Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1))) { - if (Creature* target = ObjectAccessor::GetCreature(*me, TargetGUID)) - DoCast(target, SPELL_CHAIN_HEAL); - - //If one of the adds is dead spawn heals faster - Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)); - Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)); - uiChainHealTimer = ((pGuard1 && !pGuard1->IsAlive()) || (pGuard2 && !pGuard2->IsAlive()) ? 3000 : 8000) + rand32() % 3000; + if (Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2))) + { + if (pGuard1->IsAlive()) + { + if (pGuard1->HasAuraType(SPELL_AURA_MOD_STUN) || pGuard1->HasAuraType(SPELL_AURA_MOD_ROOT) + || pGuard1->HasAuraType(SPELL_AURA_MOD_CONFUSE) || pGuard1->HasAuraType(SPELL_AURA_MOD_PACIFY) + || pGuard1->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) + { + DoCast(SPELL_BREAK_BONDS); + breakBondsCd = 10000; + return; + } + } + if (pGuard2->IsAlive()) + { + if (pGuard2->HasAuraType(SPELL_AURA_MOD_STUN) || pGuard2->HasAuraType(SPELL_AURA_MOD_ROOT) + || pGuard2->HasAuraType(SPELL_AURA_MOD_CONFUSE) || pGuard2->HasAuraType(SPELL_AURA_MOD_PACIFY) + || pGuard2->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) + { + DoCast(SPELL_BREAK_BONDS); + breakBondsCd = 10000; + return; + } + } + } } - } else uiChainHealTimer -= diff; - - if (uiBloodlustTimer <= diff) - { - DoCast(me, SPELL_BLOODLUST); - uiBloodlustTimer = urand(35000, 45000); - } else uiBloodlustTimer -= diff; - - if (uiEarthShockTimer <= diff) - { - DoCastVictim(SPELL_EARTH_SHOCK); - uiEarthShockTimer = urand(8000, 13000); - } else uiEarthShockTimer -= diff; - - if (uiLightningBoltTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_LIGHTNING_BOLT); - uiLightningBoltTimer = urand(18000, 24000); - } else uiLightningBoltTimer -= diff; - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - if (instance->GetData(DATA_WAVE_COUNT) == 6) - { - instance->SetData(DATA_1ST_BOSS_EVENT, DONE); - instance->SetData(DATA_WAVE_COUNT, 7); } - else if (instance->GetData(DATA_WAVE_COUNT) == 12) + else + breakBondsCd -= diff; + + switch (uint32 eventId = events.ExecuteEvent()) { - instance->SetData(DATA_2ND_BOSS_EVENT, DONE); - instance->SetData(DATA_WAVE_COUNT, 13); + case EVENT_EARTH_SHIELD: + if (Unit* ally = DoSelectLowestHpFriendly(30.0f)) + DoCast(ally, SPELL_EARTH_SHIELD); + events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000); + break; + case EVENT_BLOODLUST: + DoCast(SPELL_BLOODLUST); + events.ScheduleEvent(EVENT_BLOODLUST, urand(35000, 45000)); + break; + case EVENT_LIGHTNING_BOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_LIGHTNING_BOLT); + events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2500); + break; + case EVENT_CHAIN_HEAL: + if (Unit* ally = DoSelectLowestHpFriendly(40.0f)) + DoCast(ally, SPELL_CHAIN_HEAL); + { + Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)); + Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)); + events.ScheduleEvent(EVENT_CHAIN_HEAL, ((pGuard1 && !pGuard1->IsAlive()) || (pGuard2 && !pGuard2->IsAlive()) ? 3000 : 8000 + rand() % 3000)); + } + break; + case EVENT_EARTH_SHOCK: + DoCastVictim(SPELL_EARTH_SHOCK); + events.ScheduleEvent(EVENT_EARTH_SHOCK, urand(8000, 13000)); + break; + case EVENT_WINDFURY: + DoCast(SPELL_WINDFURY); + events.ScheduleEvent(EVENT_WINDFURY, urand(1500, 2000)); + break; + case EVENT_STORMSTRIKE: + DoCastVictim(SPELL_STORMSTRIKE); + events.ScheduleEvent(EVENT_STORMSTRIKE, urand(1500, 2000)); + break; + default: + break; } - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER) - return; - Talk(SAY_SLAY); + DoMeleeAttackIfReady(); } - ObjectGuid GetChainHealTargetGUID() - { - if (HealthBelowPct(85)) - return me->GetGUID(); - - Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1)); - if (pGuard1 && pGuard1->IsAlive() && !pGuard1->HealthAbovePct(75)) - return pGuard1->GetGUID(); - - Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2)); - if (pGuard2 && pGuard2->IsAlive() && !pGuard2->HealthAbovePct(75)) - return pGuard2->GetGUID(); - - return ObjectGuid::Empty; - } + private: + EventMap events; + InstanceScript* instance; + uint8 phase; + int32 breakBondsCd; }; - }; enum GuardSpells @@ -291,6 +347,9 @@ public: void Reset() override { Initialize(); + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC); } void AttackStart(Unit* who) override @@ -309,7 +368,6 @@ public: void MoveInLineOfSight(Unit* /*who*/) override { } - void UpdateAI(uint32 diff) override { if (!UpdateVictim()) @@ -336,7 +394,6 @@ public: } else uiGushingWoundTimer -= diff; } }; - }; void AddSC_boss_erekem() diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp index 48fe8049d19..cfdacb10896 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp @@ -23,19 +23,20 @@ enum Spells { SPELL_DRAINED = 59820, SPELL_FRENZY = 54312, - SPELL_FRENZY_H = 59522, SPELL_PROTECTIVE_BUBBLE = 54306, SPELL_WATER_BLAST = 54237, - SPELL_WATER_BLAST_H = 59520, SPELL_WATER_BOLT_VOLLEY = 54241, - SPELL_WATER_BOLT_VOLLEY_H = 59521, SPELL_SPLASH = 59516, - SPELL_WATER_GLOBULE = 54268 + SPELL_BURST = 54379, + SPELL_WATER_GLOBULE = 54268, + SPELL_MERGE = 54269, + SPELL_WATER_GLOBULE_VISUAL = 54260 }; enum IchoronCreatures { NPC_ICHOR_GLOBULE = 29321, + NPC_ICHORON_SUMMON_TARGET = 29326 }; enum Yells @@ -51,75 +52,83 @@ enum Yells enum Actions { - ACTION_WATER_ELEMENT_HIT = 1, - ACTION_WATER_ELEMENT_KILLED = 2, + ACTION_WATER_ELEMENT_HIT = 1 }; -/// @todo get those positions from spawn of creature 29326 -#define MAX_SPAWN_LOC 5 -static Position SpawnLoc[MAX_SPAWN_LOC]= +enum IchoronEvents { - {1840.64f, 795.407f, 44.079f, 1.676f}, - {1886.24f, 757.733f, 47.750f, 5.201f}, - {1877.91f, 845.915f, 43.417f, 3.560f}, - {1918.97f, 850.645f, 47.225f, 4.136f}, - {1935.50f, 796.224f, 52.492f, 4.224f}, + EVENT_WATER_BLAST = 1, + EVENT_WATER_BOLT_VOLLEY +}; + +enum GlobuleEvents +{ + EVENT_GLOBULE_MOVE = 1 }; enum Misc { + DATA_GLOBULE_PATH = 0, DATA_DEHYDRATION = 1 }; + +#define MAX_GLOBULE_PATHS 10 + +Position const globulePaths[MAX_GLOBULE_PATHS] = +{ + // first target + { 1861.357f, 804.039f, 44.008f, 6.268f }, + { 1869.375f, 803.976f, 38.781f, 0.009f }, + // second target + { 1888.063f, 763.488f, 47.667f, 1.744f }, + { 1882.865f, 776.385f, 38.824f, 1.882f }, + // third target + { 1935.140f, 817.752f, 52.181f, 1.885f }, + { 1916.642f, 826.337f, 39.139f, 2.851f }, + // fourth target + { 1930.257f, 833.053f, 46.906f, 4.579f }, + { 1916.642f, 826.337f, 39.139f, 2.851f }, + // fifth target + { 1878.248f, 841.883f, 43.334f, 4.717f }, + { 1879.438f, 834.443f, 38.699f, 4.831f } +}; + class boss_ichoron : public CreatureScript { public: boss_ichoron() : CreatureScript("boss_ichoron") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_ichoronAI>(creature); - } - struct boss_ichoronAI : public ScriptedAI { boss_ichoronAI(Creature* creature) : ScriptedAI(creature), m_waterElements(creature) { Initialize(); - instance = creature->GetInstanceScript(); + instance = creature->GetInstanceScript(); } void Initialize() { bIsExploded = false; bIsFrenzy = false; + bIsDrained = false; dehydration = true; - uiBubbleCheckerTimer = 1000; - uiWaterBoltVolleyTimer = urand(10000, 15000); + drainedTimer = 50; + burstTimer = 15000; } - bool bIsExploded; - bool bIsFrenzy; - bool dehydration; - - uint32 uiBubbleCheckerTimer; - uint32 uiWaterBoltVolleyTimer; - - InstanceScript* instance; - - SummonList m_waterElements; - void Reset() override { Initialize(); + events.Reset(); me->SetVisible(true); DespawnWaterElements(); if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) override @@ -128,16 +137,20 @@ public: DoCast(me, SPELL_PROTECTIVE_BUBBLE); - if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_ICHORON_CELL))) - if (pDoor->GetGoState() == GO_STATE_READY) + if (GameObject* door = instance->GetGameObject(DATA_ICHORON_CELL)) + if (door->GetGoState() == GO_STATE_READY) { EnterEvadeMode(); return; } + if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + + events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000)); + events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000)); } void AttackStart(Unit* who) override @@ -162,18 +175,14 @@ public: switch (param) { case ACTION_WATER_ELEMENT_HIT: - me->ModifyHealth(int32(me->CountPctFromMaxHealth(1))); - + { if (bIsExploded) DoExplodeCompleted(); + me->SetHealth(me->GetHealth() + me->CountPctFromMaxHealth(3)); dehydration = false; - break; - case ACTION_WATER_ELEMENT_KILLED: - uint32 damage = me->CountPctFromMaxHealth(3); - me->ModifyHealth(-int32(damage)); - me->LowerPlayerDamageReq(damage); - break; + } + break; } } @@ -187,6 +196,7 @@ public: void DoExplodeCompleted() { bIsExploded = false; + bIsDrained = false; if (!HealthBelowPct(25)) { @@ -206,75 +216,24 @@ public: return 0; } - void MoveInLineOfSight(Unit* /*who*/) override { } - - - void UpdateAI(uint32 uiDiff) override + void MoveInLineOfSight(Unit* who) override { - if (!UpdateVictim()) + if (!who->ToCreature()) return; - if (!bIsFrenzy && HealthBelowPct(25) && !bIsExploded) - { - Talk(SAY_ENRAGE); - DoCast(me, SPELL_FRENZY, true); - bIsFrenzy = true; - } - - if (!bIsFrenzy) - { - if (uiBubbleCheckerTimer <= uiDiff) - { - if (!bIsExploded) - { - if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE)) - { - Talk(SAY_SHATTER); - DoCast(me, SPELL_WATER_BLAST); - DoCast(me, SPELL_DRAINED); - bIsExploded = true; - me->AttackStop(); - me->SetVisible(false); - for (uint8 i = 0; i < 10; i++) - { - int tmp = urand(0, MAX_SPAWN_LOC-1); - me->SummonCreature(NPC_ICHOR_GLOBULE, SpawnLoc[tmp], TEMPSUMMON_CORPSE_DESPAWN); - } - } - } - else - { - bool bIsWaterElementsAlive = false; - if (!m_waterElements.empty()) - { - for (SummonList::const_iterator itr = m_waterElements.begin(); itr != m_waterElements.end(); ++itr) - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) - if (temp->IsAlive()) - { - bIsWaterElementsAlive = true; - break; - } - } + if (who->GetEntry() != NPC_ICHOR_GLOBULE) + return; - if (!bIsWaterElementsAlive) - DoExplodeCompleted(); - } - uiBubbleCheckerTimer = 1000; - } - else uiBubbleCheckerTimer -= uiDiff; - } + if (!me->IsWithinDist(who, 4.0f, false)) + return; - if (!bIsExploded) - { - if (uiWaterBoltVolleyTimer <= uiDiff) - { - DoCast(me, SPELL_WATER_BOLT_VOLLEY); - uiWaterBoltVolleyTimer = urand(10000, 15000); - } - else uiWaterBoltVolleyTimer -= uiDiff; + if (who->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + return; - DoMeleeAttackIfReady(); - } + who->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + who->CastSpell(who, SPELL_MERGE); + DoAction(ACTION_WATER_ELEMENT_HIT); + who->ToCreature()->DespawnOrUnsummon(1000); } void JustDied(Unit* /*killer*/) override @@ -291,45 +250,187 @@ public: if (instance->GetData(DATA_WAVE_COUNT) == 6) { - instance->SetData(DATA_1ST_BOSS_EVENT, DONE); + instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 7); } else if (instance->GetData(DATA_WAVE_COUNT) == 12) { - instance->SetData(DATA_2ND_BOSS_EVENT, DONE); + instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 13); } } void JustSummoned(Creature* summoned) override { - if (summoned) - { - summoned->SetSpeed(MOVE_RUN, 0.3f); - summoned->GetMotionMaster()->MoveFollow(me, 0, 0); - m_waterElements.Summon(summoned); - instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); - } + summoned->SetSpeed(MOVE_RUN, 0.3f); + m_waterElements.Summon(summoned); + + instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); } void SummonedCreatureDespawn(Creature* summoned) override { - if (summoned) + m_waterElements.Despawn(summoned); + + if (m_waterElements.empty() && bIsExploded) { - m_waterElements.Despawn(summoned); - instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); + me->RemoveAllAuras(); + DoExplodeCompleted(); } + + instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); } void KilledUnit(Unit* victim) override { - if (victim->GetTypeId() != TYPEID_PLAYER) + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) return; - Talk(SAY_SLAY); + if (!bIsFrenzy && HealthBelowPct(25) && !bIsExploded) + { + Talk(SAY_ENRAGE); + DoCast(me, SPELL_FRENZY, true); + bIsFrenzy = true; + } + + if (!bIsFrenzy) + { + if (!bIsExploded) + { + if (!me->HasAura(SPELL_PROTECTIVE_BUBBLE)) + { + bIsExploded = true; + Talk(SAY_SHATTER); + DoCast(SPELL_BURST); + me->RemoveAllAuras(); + burstTimer = 15000; + + std::list<Creature*> summonTargets; + GetCreatureListWithEntryInGrid(summonTargets, me, NPC_ICHORON_SUMMON_TARGET, 200.0f); + std::list<Creature*>::iterator itr = summonTargets.begin(); + + for (uint8 i = 0; i < MAX_GLOBULE_PATHS; i++) + { + std::advance(itr, urand(0, summonTargets.size() - 1)); // I take a random minion in the list + Position targetPos = (*itr)->GetRandomNearPosition(10.0f); + itr = summonTargets.begin(); + TempSummon* globule = me->SummonCreature(NPC_ICHOR_GLOBULE, targetPos, TEMPSUMMON_CORPSE_DESPAWN); + DoCast(globule, SPELL_WATER_GLOBULE_VISUAL); + + float minDistance = 1000.0f; + uint8 nextPath = 0; + // I move the globules to next position. the 10 positions are in couples, defined in globulePaths, so i have to increase by 2. + for (uint8 gpath = 0; gpath < MAX_GLOBULE_PATHS; gpath += 2) + { + if (globule->GetDistance(globulePaths[gpath]) < minDistance) + { + minDistance = globule->GetDistance(globulePaths[gpath]); + nextPath = gpath; + } + } + + globule->GetAI()->SetData(DATA_GLOBULE_PATH, nextPath); + } + return; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + switch (uint32 eventId = events.ExecuteEvent()) + { + case EVENT_WATER_BLAST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_WATER_BLAST); + events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000)); + break; + case EVENT_WATER_BOLT_VOLLEY: + DoCast(SPELL_WATER_BOLT_VOLLEY); + events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000)); + break; + } + + DoMeleeAttackIfReady(); + } + else if (!bIsDrained) + { + if (drainedTimer <= 0) + { + bIsDrained = true; + drainedTimer = 50; + uint32 damage = me->CountPctFromMaxHealth(30); + if (me->GetHealth() < damage) + me->SetHealth(me->CountPctFromMaxHealth(1)); + else + { + me->SetHealth(me->GetHealth() - damage); + me->LowerPlayerDamageReq(damage); + } + DoCast(SPELL_DRAINED); + me->SetVisible(false); + me->AttackStop(); + } + else + drainedTimer -= diff; + } + else if (bIsDrained) + { + if (burstTimer <= 0) + { + DoExplodeCompleted(); + } + else + burstTimer -= diff; + } + } + else + { + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + events.Update(diff); + + switch (uint32 eventId = events.ExecuteEvent()) + { + case EVENT_WATER_BLAST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_WATER_BLAST); + events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000)); + break; + case EVENT_WATER_BOLT_VOLLEY: + DoCast(SPELL_WATER_BOLT_VOLLEY); + events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(10000, 15000)); + break; + } + + DoMeleeAttackIfReady(); + } } + + private: + InstanceScript* instance; + SummonList m_waterElements; + EventMap events; + bool bIsExploded; + bool bIsFrenzy; + bool bIsDrained; + bool dehydration; + int32 drainedTimer; + int32 burstTimer; }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_ichoronAI>(creature); + } }; class npc_ichor_globule : public CreatureScript @@ -337,11 +438,6 @@ class npc_ichor_globule : public CreatureScript public: npc_ichor_globule() : CreatureScript("npc_ichor_globule") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_ichor_globuleAI>(creature); - } - struct npc_ichor_globuleAI : public ScriptedAI { npc_ichor_globuleAI(Creature* creature) : ScriptedAI(creature) @@ -352,51 +448,74 @@ public: void Initialize() { - uiRangeCheck_Timer = 1000; + pathId = 0; } - InstanceScript* instance; - - uint32 uiRangeCheck_Timer; - void Reset() override { Initialize(); - DoCast(me, SPELL_WATER_GLOBULE); + events.Reset(); + DoCast(SPELL_WATER_GLOBULE); + me->SetReactState(REACT_PASSIVE); } - void AttackStart(Unit* /*who*/) override + void SetData(uint32 id, uint32 data) override { - return; + if (id == DATA_GLOBULE_PATH) + { + pathId = data; + me->GetMotionMaster()->MovePoint(0, globulePaths[pathId]); + } } - void UpdateAI(uint32 uiDiff) override + void MovementInform(uint32 type, uint32 id) override { - if (uiRangeCheck_Timer < uiDiff) + if (type != POINT_MOTION_TYPE) + return; + + switch (id) { - if (Creature* pIchoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON))) - { - if (me->IsWithinDist(pIchoron, 2.0f, false)) - { - if (pIchoron->AI()) - pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_HIT); - me->DespawnOrUnsummon(); - } - } - uiRangeCheck_Timer = 1000; + case 0: + me->GetMotionMaster()->Clear(); + events.ScheduleEvent(EVENT_GLOBULE_MOVE, 500); + break; + case 1: + me->GetMotionMaster()->Clear(); + if (Creature* ichoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON))) + me->GetMotionMaster()->MoveFollow(ichoron, 0.0f, 0.0f); + break; } - else uiRangeCheck_Timer -= uiDiff; } - void JustDied(Unit* /*killer*/) override + // on retail spell casted on a creature's death are not casted after death but keeping mob at 1 health, casting it and then letting the mob die. + // this feature should be still implemented + void DamageTaken(Unit* /*attacker*/, uint32 &damage) override + { + int32 actualHp = me->GetHealth(); + actualHp -= damage; + + if (actualHp <= 0) + DoCast(SPELL_SPLASH); + } + + void UpdateAI(uint32 diff) override { - DoCast(me, SPELL_SPLASH); - if (Creature* pIchoron = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_ICHORON))) - if (pIchoron->AI()) - pIchoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED); + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_GLOBULE_MOVE) + me->GetMotionMaster()->MovePoint(1, globulePaths[pathId + 1]); } + + private: + InstanceScript* instance; + EventMap events; + uint8 pathId; }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_ichor_globuleAI>(creature); + } }; class achievement_dehydration : public AchievementCriteriaScript diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp index c3df7b71b83..8dc0e32fb31 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp @@ -21,13 +21,18 @@ enum Spells { - SPELL_CAUTERIZING_FLAMES = 59466, //Only in heroic - SPELL_FIREBOLT = 54235, - H_SPELL_FIREBOLT = 59468, - SPELL_FLAME_BREATH = 54282, - H_SPELL_FLAME_BREATH = 59469, - SPELL_LAVA_BURN = 54249, - H_SPELL_LAVA_BURN = 59594 + SPELL_CAUTERIZING_FLAMES = 59466, // Only in heroic + SPELL_FIREBOLT = 54235, + SPELL_FLAME_BREATH = 54282, + SPELL_LAVA_BURN = 54249 +}; + +enum LavanthorEvents +{ + EVENT_CAUTERIZING_FLAMES = 1, + EVENT_FIREBOLT, + EVENT_FLAME_BREATH, + EVENT_LAVA_BURN }; class boss_lavanthor : public CreatureScript @@ -44,46 +49,37 @@ public: { boss_lavanthorAI(Creature* creature) : ScriptedAI(creature) { - Initialize(); instance = creature->GetInstanceScript(); } - void Initialize() - { - uiFireboltTimer = 1000; - uiFlameBreathTimer = 5000; - uiLavaBurnTimer = 10000; - uiCauterizingFlamesTimer = 3000; - } - - uint32 uiFireboltTimer; - uint32 uiFlameBreathTimer; - uint32 uiLavaBurnTimer; - uint32 uiCauterizingFlamesTimer; - - InstanceScript* instance; - void Reset() override { - Initialize(); if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); + + events.Reset(); } void EnterCombat(Unit* /*who*/) override { - if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_LAVANTHOR_CELL))) - if (pDoor->GetGoState() == GO_STATE_READY) - { - EnterEvadeMode(); - return; - } - if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); - else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + if (GameObject* door = instance->GetGameObject(DATA_LAVANTHOR_CELL)) + if (door->GetGoState() == GO_STATE_READY) + { + EnterEvadeMode(); + return; + } + if (instance->GetData(DATA_WAVE_COUNT) == 6) + instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (instance->GetData(DATA_WAVE_COUNT) == 12) + instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + + events.ScheduleEvent(EVENT_FIREBOLT, 1000); + events.ScheduleEvent(EVENT_FLAME_BREATH, 5000); + events.ScheduleEvent(EVENT_LAVA_BURN, 10000); + if (IsHeroic()) + events.ScheduleEvent(EVENT_CAUTERIZING_FLAMES, 3000); } void AttackStart(Unit* who) override @@ -100,40 +96,38 @@ public: } } - void MoveInLineOfSight(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override { - //Return since we have no target if (!UpdateVictim()) return; - if (uiFireboltTimer <= diff) - { - DoCastVictim(SPELL_FIREBOLT); - uiFireboltTimer = urand(5000, 13000); - } else uiFireboltTimer -= diff; + events.Update(diff); - if (uiFlameBreathTimer <= diff) - { - DoCastVictim(SPELL_FLAME_BREATH); - uiFlameBreathTimer = urand(10000, 15000); - } else uiFlameBreathTimer -= diff; - - if (uiLavaBurnTimer <= diff) - { - DoCastVictim(SPELL_LAVA_BURN); - uiLavaBurnTimer = urand(15000, 23000); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (IsHeroic()) + switch (uint32 eventId = events.ExecuteEvent()) { - if (uiCauterizingFlamesTimer <= diff) - { - DoCastVictim(SPELL_CAUTERIZING_FLAMES); - uiCauterizingFlamesTimer = urand(10000, 16000); - } else uiCauterizingFlamesTimer -= diff; + case EVENT_FIREBOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_FIREBOLT); + events.ScheduleEvent(EVENT_FIREBOLT, urand(5000, 13000)); + break; + case EVENT_FLAME_BREATH: + DoCast(SPELL_FLAME_BREATH); + events.ScheduleEvent(EVENT_FLAME_BREATH, urand(10000, 15000)); + break; + case EVENT_LAVA_BURN: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_LAVA_BURN); + events.ScheduleEvent(EVENT_LAVA_BURN, urand(15000, 23000)); + break; + case EVENT_CAUTERIZING_FLAMES: + DoCast(SPELL_CAUTERIZING_FLAMES); + events.ScheduleEvent(EVENT_CAUTERIZING_FLAMES, urand(10000, 16000)); + break; + default: + break; } DoMeleeAttackIfReady(); @@ -143,17 +137,20 @@ public: { if (instance->GetData(DATA_WAVE_COUNT) == 6) { - instance->SetData(DATA_1ST_BOSS_EVENT, DONE); + instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 7); } else if (instance->GetData(DATA_WAVE_COUNT) == 12) { - instance->SetData(DATA_2ND_BOSS_EVENT, DONE); + instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 13); } } - }; + private: + EventMap events; + InstanceScript* instance; + }; }; void AddSC_boss_lavanthor() diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp index 9a6422dec32..8f2fe578d6e 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp @@ -17,13 +17,27 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" #include "violet_hold.h" -//Spells enum Spells { SPELL_CORROSIVE_SALIVA = 54527, - SPELL_OPTIC_LINK = 54396 + SPELL_OPTIC_LINK = 54396, + SPELL_RAY_OF_PAIN = 54438, // NYI missing spelldifficulty + SPELL_RAY_OF_SUFFERING = 54442, // NYI missing spelldifficulty + + // Visual + SPELL_OPTIC_LINK_LEVEL_1 = 54393, + SPELL_OPTIC_LINK_LEVEL_2 = 54394, + SPELL_OPTIC_LINK_LEVEL_3 = 54395 +}; + +enum MoraggEvents +{ + EVENT_CORROSIVE_SALIVA = 1, + EVENT_OPTIC_LINK }; class boss_moragg : public CreatureScript @@ -31,52 +45,43 @@ class boss_moragg : public CreatureScript public: boss_moragg() : CreatureScript("boss_moragg") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_moraggAI>(creature); - } - struct boss_moraggAI : public ScriptedAI { boss_moraggAI(Creature* creature) : ScriptedAI(creature) { - Initialize(); instance = creature->GetInstanceScript(); } - void Initialize() - { - uiOpticLinkTimer = 10000; - uiCorrosiveSalivaTimer = 5000; - } - - uint32 uiOpticLinkTimer; - uint32 uiCorrosiveSalivaTimer; - - InstanceScript* instance; - void Reset() override { - Initialize(); + events.Reset(); if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) override { - if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_MORAGG_CELL))) - if (pDoor->GetGoState() == GO_STATE_READY) + if (GameObject* door = instance->GetGameObject(DATA_MORAGG_CELL)) + if (door->GetGoState() == GO_STATE_READY) { EnterEvadeMode(); return; } + if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); + + me->SetInCombatWithZone(); + + DoCast(SPELL_RAY_OF_PAIN); + DoCast(SPELL_RAY_OF_SUFFERING); + events.ScheduleEvent(EVENT_OPTIC_LINK, 15000); + events.ScheduleEvent(EVENT_CORROSIVE_SALIVA, 5000); } void AttackStart(Unit* who) override @@ -93,48 +98,202 @@ public: } } - void MoveInLineOfSight(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override { - //Return since we have no target if (!UpdateVictim()) return; - if (uiOpticLinkTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - DoCast(target, SPELL_OPTIC_LINK); - uiOpticLinkTimer = 15000; - } else uiOpticLinkTimer -= diff; + events.Update(diff); - if (uiCorrosiveSalivaTimer <= diff) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (uint32 eventId = events.ExecuteEvent()) { - DoCastVictim(SPELL_CORROSIVE_SALIVA); - uiCorrosiveSalivaTimer = 10000; - } else uiCorrosiveSalivaTimer -= diff; + case EVENT_OPTIC_LINK: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_OPTIC_LINK); + events.ScheduleEvent(EVENT_OPTIC_LINK, 25000); + break; + case EVENT_CORROSIVE_SALIVA: + DoCastVictim(SPELL_CORROSIVE_SALIVA); + events.ScheduleEvent(EVENT_CORROSIVE_SALIVA, 10000); + break; + default: + break; + } DoMeleeAttackIfReady(); } + void JustDied(Unit* /*killer*/) override { if (instance->GetData(DATA_WAVE_COUNT) == 6) { - instance->SetData(DATA_1ST_BOSS_EVENT, DONE); + instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 7); } else if (instance->GetData(DATA_WAVE_COUNT) == 12) { - instance->SetData(DATA_2ND_BOSS_EVENT, DONE); + instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 13); } } + + private: + EventMap events; + InstanceScript* instance; }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_moraggAI>(creature); + } +}; + +class spell_moragg_ray_of_suffering : public SpellScriptLoader +{ +public: + spell_moragg_ray_of_suffering() : SpellScriptLoader("spell_moragg_ray_of_suffering") { } + + class spell_moragg_ray_of_suffering_AuraScript : public AuraScript + { + PrepareAuraScript(spell_moragg_ray_of_suffering_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + std::list<HostileReference*> players = GetTarget()->getThreatManager().getThreatList(); + if (!players.empty()) + { + std::list<HostileReference*>::iterator itr = players.begin(); + std::advance(itr, urand(0, players.size() - 1)); + + uint32 triggerSpell = GetSpellInfo()->GetEffect(aurEff->GetEffIndex())->TriggerSpell; + GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_MAX_TARGETS, 1, (*itr)->getTarget(), TRIGGERED_FULL_MASK, NULL, aurEff); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_of_suffering_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_moragg_ray_of_suffering_AuraScript(); + } +}; + +class spell_moragg_ray_of_pain : public SpellScriptLoader +{ +public: + spell_moragg_ray_of_pain() : SpellScriptLoader("spell_moragg_ray_of_pain") { } + + class spell_moragg_ray_of_pain_AuraScript : public AuraScript + { + PrepareAuraScript(spell_moragg_ray_of_pain_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + std::list<HostileReference*> players = GetTarget()->getThreatManager().getThreatList(); + if (!players.empty()) + { + std::list<HostileReference*>::iterator itr = players.begin(); + std::advance(itr, urand(0, players.size() - 1)); + + uint32 triggerSpell = GetSpellInfo()->GetEffect(aurEff->GetEffIndex())->TriggerSpell; + GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_MAX_TARGETS, 1, (*itr)->getTarget(), TRIGGERED_FULL_MASK, NULL, aurEff); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_ray_of_pain_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_moragg_ray_of_pain_AuraScript(); + } +}; + +class spell_moragg_optic_link : public SpellScriptLoader +{ +public: + spell_moragg_optic_link() : SpellScriptLoader("spell_moragg_optic_link") { } + + class spell_moragg_optic_link_AuraScript : public AuraScript + { + PrepareAuraScript(spell_moragg_optic_link_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + switch (aurEff->GetTickNumber()) // Different visual based on tick + { + case 1: + case 2: + case 3: + GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); + break; + case 4: + case 5: + case 6: + case 7: + GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); + GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_2, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); + break; + case 8: + case 9: + case 10: + case 11: + GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_1, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); + GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_2, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); + GetTarget()->CastCustomSpell(SPELL_OPTIC_LINK_LEVEL_3, SPELLVALUE_MAX_TARGETS, 1, (Unit*)NULL, TRIGGERED_FULL_MASK, NULL, aurEff); + break; + default: + break; + } + } + + void OnUpdate(AuraEffect* aurEff) + { + switch (aurEff->GetTickNumber()) + { + case 1: + aurEff->SetAmount(aurEff->GetAmount() + 250); // base amount is 500 + break; + case 4: + aurEff->SetAmount(aurEff->GetAmount() * 2); // goes to 1500 + break; + case 8: + aurEff->SetAmount(aurEff->GetAmount() * 2); // goes to 3000 + break; + default: + break; + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_moragg_optic_link_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_moragg_optic_link_AuraScript::OnUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_moragg_optic_link_AuraScript(); + } }; void AddSC_boss_moragg() { new boss_moragg(); + new spell_moragg_ray_of_suffering(); + new spell_moragg_ray_of_pain(); + new spell_moragg_optic_link(); } diff --git a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp index 833b06cfbff..4fb7646558d 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp @@ -17,24 +17,24 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "violet_hold.h" +#include "SpellInfo.h" +#include "SpellScript.h" #include "Player.h" +#include "violet_hold.h" enum Spells { SPELL_ARCANE_BARRAGE_VOLLEY = 54202, - SPELL_ARCANE_BARRAGE_VOLLEY_H = 59483, SPELL_ARCANE_BUFFET = 54226, - SPELL_ARCANE_BUFFET_H = 59485, SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102, - SPELL_SUMMON_ETHEREAL_SPHERE_2 = 54137, + SPELL_SUMMON_ETHEREAL_SPHERE_2 = 61337, SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138 }; enum NPCs { NPC_ETHEREAL_SPHERE = 29271, - //NPC_ETHEREAL_SPHERE2 = 32582, // heroic only? + NPC_ETHEREAL_SPHERE2 = 32582 }; enum CreatureSpells @@ -42,7 +42,8 @@ enum CreatureSpells SPELL_ARCANE_POWER = 54160, H_SPELL_ARCANE_POWER = 59474, SPELL_SUMMON_PLAYERS = 54164, - SPELL_POWER_BALL_VISUAL = 54141 + SPELL_POWER_BALL_VISUAL = 54141, + SPELL_POWER_BALL_DAMAGE_TRIGGER = 54207 }; enum Yells @@ -56,52 +57,50 @@ enum Yells SAY_SUMMON_ENERGY = 6 }; +enum XevozzEvents +{ + EVENT_ARCANE_BARRAGE = 1, + EVENT_ARCANE_BUFFET, + EVENT_SUMMON_SPHERE, + EVENT_SUMMON_SPHERE_2, + EVENT_RANGE_CHECK, + EVENT_SUMMON_PLAYERS, + EVENT_DESPAWN_SPHERE +}; + +enum SphereActions +{ + ACTION_SUMMON = 1, +}; + class boss_xevozz : public CreatureScript { public: boss_xevozz() : CreatureScript("boss_xevozz") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_xevozzAI>(creature); - } - struct boss_xevozzAI : public ScriptedAI { boss_xevozzAI(Creature* creature) : ScriptedAI(creature) { - Initialize(); - instance = creature->GetInstanceScript(); + instance = creature->GetInstanceScript(); } - void Initialize() - { - uiSummonEtherealSphere_Timer = urand(10000, 12000); - uiArcaneBarrageVolley_Timer = urand(20000, 22000); - uiArcaneBuffet_Timer = uiSummonEtherealSphere_Timer + urand(5000, 6000); - } - - InstanceScript* instance; - - uint32 uiSummonEtherealSphere_Timer; - uint32 uiArcaneBarrageVolley_Timer; - uint32 uiArcaneBuffet_Timer; - void Reset() override { if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED); else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); - Initialize(); DespawnSphere(); + events.Reset(); } void DespawnSphere() { std::list<Creature*> assistList; GetCreatureListWithEntryInGrid(assistList, me, NPC_ETHEREAL_SPHERE, 150.0f); + GetCreatureListWithEntryInGrid(assistList, me, NPC_ETHEREAL_SPHERE2, 150.0f); if (assistList.empty()) return; @@ -116,11 +115,7 @@ public: void JustSummoned(Creature* summoned) override { summoned->SetSpeed(MOVE_RUN, 0.5f); - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - summoned->AddThreat(target, 0.00f); - summoned->AI()->AttackStart(target); - } + summoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f); } void AttackStart(Unit* who) override @@ -139,58 +134,23 @@ public: void EnterCombat(Unit* /*who*/) override { - Talk(SAY_AGGRO); - if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_XEVOZZ_CELL))) - if (pDoor->GetGoState() == GO_STATE_READY) + if (GameObject* door = instance->GetGameObject(DATA_XEVOZZ_CELL)) + if (door->GetGoState() == GO_STATE_READY) { EnterEvadeMode(); return; } - if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); - else if (instance->GetData(DATA_WAVE_COUNT) == 12) - instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); - } - - void MoveInLineOfSight(Unit* /*who*/) override { } + Talk(SAY_AGGRO); - void UpdateAI(uint32 uiDiff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (uiArcaneBarrageVolley_Timer < uiDiff) - { - DoCast(me, SPELL_ARCANE_BARRAGE_VOLLEY); - uiArcaneBarrageVolley_Timer = urand(20000, 22000); - } - else uiArcaneBarrageVolley_Timer -= uiDiff; - - if (uiArcaneBuffet_Timer) - { - if (uiArcaneBuffet_Timer < uiDiff) - { - DoCastVictim(SPELL_ARCANE_BUFFET); - uiArcaneBuffet_Timer = 0; - } - else uiArcaneBuffet_Timer -= uiDiff; - } - - if (uiSummonEtherealSphere_Timer < uiDiff) - { - Talk(SAY_SPAWN); - DoCast(me, SPELL_SUMMON_ETHEREAL_SPHERE_1); - if (IsHeroic()) // extra one for heroic - me->SummonCreature(NPC_ETHEREAL_SPHERE, me->GetPositionX() - 5 + rand32() % 10, me->GetPositionY() - 5 + rand32() % 10, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 40000); - - uiSummonEtherealSphere_Timer = urand(45000, 47000); - uiArcaneBuffet_Timer = urand(5000, 6000); - } - else uiSummonEtherealSphere_Timer -= uiDiff; + if (instance->GetData(DATA_WAVE_COUNT) == 6) + instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + else if (instance->GetData(DATA_WAVE_COUNT) == 12) + instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS); - DoMeleeAttackIfReady(); + events.ScheduleEvent(EVENT_SUMMON_SPHERE, 5000); + events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(8000, 10000)); + events.ScheduleEvent(EVENT_ARCANE_BUFFET, urand(10000, 11000)); } void JustDied(Unit* /*killer*/) override @@ -201,24 +161,86 @@ public: if (instance->GetData(DATA_WAVE_COUNT) == 6) { - instance->SetData(DATA_1ST_BOSS_EVENT, DONE); + instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 7); } else if (instance->GetData(DATA_WAVE_COUNT) == 12) { - instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); + instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED); instance->SetData(DATA_WAVE_COUNT, 13); } } + void KilledUnit(Unit* victim) override { - if (victim->GetTypeId() != TYPEID_PLAYER) + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void SpellHit(Unit* who, const SpellInfo* spell) override + { + if (!who->ToCreature()) + return; + + if ((spell->Id == SPELL_ARCANE_POWER) || (spell->Id == H_SPELL_ARCANE_POWER)) + Talk(SAY_SUMMON_ENERGY); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - Talk(SAY_SLAY); + switch (uint32 eventId = events.ExecuteEvent()) + { + case EVENT_ARCANE_BARRAGE: + DoCast(SPELL_ARCANE_BARRAGE_VOLLEY); + events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(8000, 10000)); + break; + case EVENT_ARCANE_BUFFET: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_ARCANE_BUFFET); + events.ScheduleEvent(EVENT_ARCANE_BUFFET, urand(15000, 20000)); + break; + case EVENT_SUMMON_SPHERE: + Talk(SAY_REPEAT_SUMMON); + DoCast(SPELL_SUMMON_ETHEREAL_SPHERE_1); + if (IsHeroic()) + events.ScheduleEvent(EVENT_SUMMON_SPHERE_2, 2500); + events.ScheduleEvent(EVENT_SUMMON_PLAYERS, urand(33000, 35000)); + events.ScheduleEvent(EVENT_SUMMON_SPHERE, urand(45000, 47000)); + break; + case EVENT_SUMMON_SPHERE_2: + Talk(SAY_REPEAT_SUMMON); + DoCast(SPELL_SUMMON_ETHEREAL_SPHERE_2); + break; + case EVENT_SUMMON_PLAYERS: + if (Creature* sphere = me->FindNearestCreature(NPC_ETHEREAL_SPHERE, 150.0f)) + sphere->GetAI()->DoAction(ACTION_SUMMON); + else if (Creature* sphere = me->FindNearestCreature(NPC_ETHEREAL_SPHERE2, 150.0f)) + sphere->GetAI()->DoAction(ACTION_SUMMON); + break; + default: + break; + } + + DoMeleeAttackIfReady(); } + + private: + InstanceScript* instance; + EventMap events; }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_xevozzAI>(creature); + } }; class npc_ethereal_sphere : public CreatureScript @@ -226,83 +248,149 @@ class npc_ethereal_sphere : public CreatureScript public: npc_ethereal_sphere() : CreatureScript("npc_ethereal_sphere") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_ethereal_sphereAI>(creature); - } - struct npc_ethereal_sphereAI : public ScriptedAI { npc_ethereal_sphereAI(Creature* creature) : ScriptedAI(creature) { Initialize(); - instance = creature->GetInstanceScript(); + instance = creature->GetInstanceScript(); } void Initialize() { - uiSummonPlayers_Timer = urand(33000, 35000); - uiRangeCheck_Timer = 1000; + arcanePower = false; } - InstanceScript* instance; - - uint32 uiSummonPlayers_Timer; - uint32 uiRangeCheck_Timer; - void Reset() override { Initialize(); + events.Reset(); + DoCast(SPELL_POWER_BALL_VISUAL); + DoCast(SPELL_POWER_BALL_DAMAGE_TRIGGER); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->setFaction(16); + events.ScheduleEvent(EVENT_DESPAWN_SPHERE, 40000); + events.ScheduleEvent(EVENT_RANGE_CHECK, 1000); } - void UpdateAI(uint32 uiDiff) override + void DoAction(int32 action) override { - //Return since we have no target - if (!UpdateVictim()) - return; + if (action == ACTION_SUMMON) + DoCast(SPELL_SUMMON_PLAYERS); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); - if (!me->HasAura(SPELL_POWER_BALL_VISUAL)) - DoCast(me, SPELL_POWER_BALL_VISUAL); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (uiRangeCheck_Timer < uiDiff) + switch (uint32 eventId = events.ExecuteEvent()) { - if (Creature* pXevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ))) - { - float fDistance = me->GetDistance2d(pXevozz); - if (fDistance <= 3) - DoCast(pXevozz, SPELL_ARCANE_POWER); - else - DoCast(me, 35845); //Is it blizzlike? - } - uiRangeCheck_Timer = 1000; + case EVENT_RANGE_CHECK: + if (Creature* xevozz = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_XEVOZZ))) + { + if (me->IsWithinDist(xevozz, 3.0f) && !arcanePower) + { + DoCast(SPELL_ARCANE_POWER); + arcanePower = true; + events.ScheduleEvent(EVENT_DESPAWN_SPHERE, 8000); + } + } + events.ScheduleEvent(EVENT_RANGE_CHECK, 1000); + break; + case EVENT_DESPAWN_SPHERE: + me->DespawnOrUnsummon(); + break; } - else uiRangeCheck_Timer -= uiDiff; + } + + private: + InstanceScript* instance; + EventMap events; + bool arcanePower; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_ethereal_sphereAI>(creature); + } +}; - if (uiSummonPlayers_Timer < uiDiff) +class spell_xevozz_summon_players : public SpellScriptLoader +{ +public: + spell_xevozz_summon_players() : SpellScriptLoader("spell_xevozz_summon_players") { } + + class spell_xevozz_summon_players_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xevozz_summon_players_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + + if (target) { - DoCast(me, SPELL_SUMMON_PLAYERS); // not working right + Position pos = GetOriginalCaster()->GetPosition(); - Map* map = me->GetMap(); - if (map && map->IsDungeon()) - { - Map::PlayerList const &PlayerList = map->GetPlayers(); + target->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); + } + } - if (!PlayerList.isEmpty()) - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - if (i->GetSource()->IsAlive()) - DoTeleportPlayer(i->GetSource(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), i->GetSource()->GetOrientation()); - } + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_xevozz_summon_players_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_xevozz_summon_players_SpellScript(); + } +}; + +class spell_xevozz_summon_ethereal_sphere : public SpellScriptLoader +{ +public: + spell_xevozz_summon_ethereal_sphere() : SpellScriptLoader("spell_xevozz_summon_ethereal_sphere") { } + + class spell_xevozz_summon_ethereal_sphere_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xevozz_summon_ethereal_sphere_SpellScript); + + void HandleScript(SpellDestination& target) + { + Unit* caster = GetOriginalCaster(); + Position pos; + float distance = 0.0f; - uiSummonPlayers_Timer = urand(33000, 35000); + while (distance < 20.0f) + { + pos = caster->GetRandomNearPosition(60.0f); + distance = caster->GetDistance(pos); } - else uiSummonPlayers_Timer -= uiDiff; + + target.Relocate(pos); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_xevozz_summon_ethereal_sphere_SpellScript::HandleScript, EFFECT_0, TARGET_DEST_DB); } }; + SpellScript* GetSpellScript() const override + { + return new spell_xevozz_summon_ethereal_sphere_SpellScript(); + } }; void AddSC_boss_xevozz() { new boss_xevozz(); new npc_ethereal_sphere(); + new spell_xevozz_summon_players(); + new spell_xevozz_summon_ethereal_sphere(); } diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp index 1043c1db29a..02e479a22f4 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp @@ -22,15 +22,9 @@ enum Spells { SPELL_SHROUD_OF_DARKNESS = 54524, - H_SPELL_SHROUD_OF_DARKNESS = 59745, SPELL_SUMMON_VOID_SENTRY = 54369, SPELL_VOID_SHIFT = 54361, - H_SPELL_VOID_SHIFT = 59743, -}; - -enum Creatures -{ - NPC_VOID_SENTRY = 29364 + SPELL_VOID_SHIFTED = 54343, }; enum Yells @@ -48,19 +42,21 @@ enum Misc DATA_VOID_DANCE = 2153 }; +enum ZuramatEvents +{ + EVENT_VOID_SHIFT = 1, + EVENT_SUMMON_VOID, + EVENT_SHROUD_OF_DARKNESS +}; + class boss_zuramat : public CreatureScript { public: boss_zuramat() : CreatureScript("boss_zuramat") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_zuramatAI>(creature); - } - struct boss_zuramatAI : public ScriptedAI { - boss_zuramatAI(Creature* creature) : ScriptedAI(creature) + boss_zuramatAI(Creature* creature) : ScriptedAI(creature), sentries(me) { Initialize(); instance = creature->GetInstanceScript(); @@ -68,18 +64,18 @@ public: void Initialize() { - SpellShroudOfDarknessTimer = 22000; - SpellVoidShiftTimer = 15000; - SpellSummonVoidTimer = 12000; voidDance = true; } - InstanceScript* instance; - - uint32 SpellVoidShiftTimer; - uint32 SpellSummonVoidTimer; - uint32 SpellShroudOfDarknessTimer; - bool voidDance; + void DespawnSentries() + { + sentries.DespawnAll(); + std::list<Creature*> sentrylist; + GetCreatureListWithEntryInGrid(sentrylist, me, NPC_VOID_SENTRY_BALL, 200.0f); + if (!sentrylist.empty()) + for (std::list<Creature*>::const_iterator itr = sentrylist.begin(); itr != sentrylist.end(); ++itr) + (*itr)->DespawnOrUnsummon(); + } void Reset() override { @@ -89,6 +85,8 @@ public: instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED); Initialize(); + events.Reset(); + DespawnSentries(); } void AttackStart(Unit* who) override @@ -107,48 +105,29 @@ public: void EnterCombat(Unit* /*who*/) override { - Talk(SAY_AGGRO); - if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_ZURAMAT_CELL))) - if (pDoor->GetGoState() == GO_STATE_READY) + if (GameObject* door = instance->GetGameObject(DATA_ZURAMAT_CELL)) + if (door->GetGoState() == GO_STATE_READY) { EnterEvadeMode(); return; } + + Talk(SAY_AGGRO); + if (instance->GetData(DATA_WAVE_COUNT) == 6) - instance->SetData(DATA_1ST_BOSS_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS); else if (instance->GetData(DATA_WAVE_COUNT) == 12) instance->SetData(DATA_2ND_BOSS_EVENT, IN_PROGRESS); - } - - void MoveInLineOfSight(Unit* /*who*/) override { } + me->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_SHROUD_OF_DARKNESS, urand(18000, 20000)); + events.ScheduleEvent(EVENT_VOID_SHIFT, 9000); + events.ScheduleEvent(EVENT_SUMMON_VOID, 4000); + } - void UpdateAI(uint32 diff) override + void JustSummoned(Creature* summon) override { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (SpellSummonVoidTimer <= diff) - { - DoCastVictim(SPELL_SUMMON_VOID_SENTRY, false); - SpellSummonVoidTimer = 20000; - } else SpellSummonVoidTimer -=diff; - - if (SpellVoidShiftTimer <= diff) - { - if (Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(unit, SPELL_VOID_SHIFT); - SpellVoidShiftTimer = 20000; - } else SpellVoidShiftTimer -=diff; - - if (SpellShroudOfDarknessTimer <= diff) - { - DoCastVictim(SPELL_SHROUD_OF_DARKNESS); - SpellShroudOfDarknessTimer = 20000; - } else SpellShroudOfDarknessTimer -=diff; - - DoMeleeAttackIfReady(); + sentries.Summon(summon); } void SummonedCreatureDies(Creature* summoned, Unit* /*who*/) override @@ -167,29 +146,73 @@ public: void JustDied(Unit* /*killer*/) override { + instance->SetData(DATA_ZURAMAT, 1); + Talk(SAY_DEATH); + DespawnSentries(); + if (instance->GetData(DATA_WAVE_COUNT) == 6) { - instance->SetData(DATA_1ST_BOSS_EVENT, DONE); + instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 7); } else if (instance->GetData(DATA_WAVE_COUNT) == 12) { - instance->SetData(DATA_2ND_BOSS_EVENT, DONE); + instance->SetBossState(DATA_2ND_BOSS_EVENT, DONE); instance->SetData(DATA_WAVE_COUNT, 13); } } void KilledUnit(Unit* victim) override { - if (victim->GetTypeId() != TYPEID_PLAYER) + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) return; - Talk(SAY_SLAY); + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (uint32 eventId = events.ExecuteEvent()) + { + case EVENT_SUMMON_VOID: + DoCast(SPELL_SUMMON_VOID_SENTRY); + events.ScheduleEvent(EVENT_SUMMON_VOID, urand(7000, 10000)); + break; + case EVENT_VOID_SHIFT: + if (Unit* unit = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(unit, SPELL_VOID_SHIFT); + events.ScheduleEvent(EVENT_VOID_SHIFT, 15000); + break; + case EVENT_SHROUD_OF_DARKNESS: + DoCast(SPELL_SHROUD_OF_DARKNESS); + events.ScheduleEvent(EVENT_SHROUD_OF_DARKNESS, urand(18000, 20000)); + break; + default: + break; + } + + DoMeleeAttackIfReady(); } + + private: + InstanceScript* instance; + EventMap events; + SummonList sentries; + bool voidDance; }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_zuramatAI>(creature); + } }; class achievement_void_dance : public AchievementCriteriaScript diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp index ef9ad806c89..e9c526df42e 100644 --- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp @@ -22,8 +22,6 @@ #include "Player.h" #include "TemporarySummon.h" -#define MAX_ENCOUNTER 3 - /* Violet Hold encounters: 0 - First boss 1 - Second boss @@ -38,21 +36,6 @@ 6 - Zuramat 7 - Cyanigosa */ -enum GameObjects -{ - GO_MAIN_DOOR = 191723, - GO_XEVOZZ_DOOR = 191556, - GO_LAVANTHOR_DOOR = 191566, - GO_ICHORON_DOOR = 191722, - GO_ZURAMAT_DOOR = 191565, - GO_EREKEM_DOOR = 191564, - GO_EREKEM_GUARD_1_DOOR = 191563, - GO_EREKEM_GUARD_2_DOOR = 191562, - GO_MORAGG_DOOR = 191606, - GO_INTRO_ACTIVATION_CRYSTAL = 193615, - GO_ACTIVATION_CRYSTAL = 193611 -}; - enum AzureSaboteurSpells { SABOTEUR_SHIELD_DISRUPTION = 58291, @@ -64,7 +47,7 @@ enum CrystalSpells SPELL_ARCANE_LIGHTNING = 57930 }; -const Position PortalLocation[] = +Position const PortalLocation[] = { {1877.51f, 850.104f, 44.6599f, 4.7822f }, // WP 1 {1918.37f, 853.437f, 47.1624f, 4.12294f}, // WP 2 @@ -74,21 +57,21 @@ const Position PortalLocation[] = {1908.31f, 809.657f, 38.7037f, 3.08701f} // WP 6 }; -const Position ArcaneSphere = {1887.060059f, 806.151001f, 61.321602f, 0.0f}; -const Position BossStartMove1 = {1894.684448f, 739.390503f, 47.668003f, 0.0f}; -const Position BossStartMove2 = {1875.173950f, 860.832703f, 43.333565f, 0.0f}; -const Position BossStartMove21 = {1858.854614f, 855.071411f, 43.333565f, 0.0f}; -const Position BossStartMove22 = {1891.926636f, 863.388977f, 43.333565f, 0.0f}; -const Position BossStartMove3 = {1916.138062f, 778.152222f, 35.772308f, 0.0f}; -const Position BossStartMove4 = {1853.618286f, 758.557617f, 38.657505f, 0.0f}; -const Position BossStartMove5 = {1906.683960f, 842.348022f, 38.637459f, 0.0f}; -const Position BossStartMove6 = {1928.207031f, 852.864441f, 47.200813f, 0.0f}; - -const Position CyanigosasSpawnLocation = {1930.281250f, 804.407715f, 52.410946f, 3.139621f}; -const Position MiddleRoomLocation = {1892.291260f, 805.696838f, 38.438862f, 3.139621f}; -const Position MiddleRoomPortalSaboLocation = {1896.622925f, 804.854126f, 38.504772f, 3.139621f}; - -//Cyanigosa's prefight event data +Position const ArcaneSphere = {1887.060059f, 806.151001f, 61.321602f, 0.0f}; +Position const BossStartMove1 = {1894.684448f, 739.390503f, 47.668003f, 0.0f}; +Position const BossStartMove2 = {1875.173950f, 860.832703f, 43.333565f, 0.0f}; +Position const BossStartMove21 = {1858.854614f, 855.071411f, 43.333565f, 0.0f}; +Position const BossStartMove22 = {1891.926636f, 863.388977f, 43.333565f, 0.0f}; +Position const BossStartMove3 = {1916.138062f, 778.152222f, 35.772308f, 0.0f}; +Position const BossStartMove4 = {1853.618286f, 758.557617f, 38.657505f, 0.0f}; +Position const BossStartMove5 = {1906.683960f, 842.348022f, 38.637459f, 0.0f}; +Position const BossStartMove6 = {1928.207031f, 852.864441f, 47.200813f, 0.0f}; + +Position const CyanigosasSpawnLocation = {1930.281250f, 804.407715f, 52.410946f, 3.139621f}; +Position const MiddleRoomLocation = {1892.291260f, 805.696838f, 38.438862f, 3.139621f}; +Position const MiddleRoomPortalSaboLocation = {1896.622925f, 804.854126f, 38.504772f, 3.139621f}; + +// Cyanigosa's prefight event data enum Yells { CYANIGOSA_SAY_SPAWN = 0 @@ -100,21 +83,45 @@ enum Spells CYANIGOSA_BLUE_AURA = 47759, }; +ObjectData const creatureData[] = +{ + { NPC_XEVOZZ, DATA_XEVOZZ }, + { NPC_LAVANTHOR, DATA_LAVANTHOR }, + { NPC_ICHORON, DATA_ICHORON }, + { NPC_ZURAMAT, DATA_ZURAMAT }, + { NPC_EREKEM, DATA_EREKEM }, + { NPC_MORAGG, DATA_MORAGG }, + { NPC_CYANIGOSA, DATA_CYANIGOSA }, + { NPC_SINCLARI, DATA_SINCLARI }, + { 0, 0 } // END +}; + +ObjectData const gameObjectData[] = +{ + { GO_EREKEM_GUARD_1_DOOR, DATA_EREKEM_LEFT_GUARD_CELL }, + { GO_EREKEM_GUARD_2_DOOR, DATA_EREKEM_RIGHT_GUARD_CELL }, + { GO_EREKEM_DOOR, DATA_EREKEM_CELL }, + { GO_ZURAMAT_DOOR, DATA_ZURAMAT_CELL }, + { GO_LAVANTHOR_DOOR, DATA_LAVANTHOR_CELL }, + { GO_MORAGG_DOOR, DATA_MORAGG_CELL }, + { GO_ICHORON_DOOR, DATA_ICHORON_CELL }, + { GO_XEVOZZ_DOOR, DATA_XEVOZZ_CELL }, + { GO_MAIN_DOOR, DATA_MAIN_DOOR }, + { 0, 0 } // END +}; + class instance_violet_hold : public InstanceMapScript { public: instance_violet_hold() : InstanceMapScript("instance_violet_hold", 608) { } - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_violet_hold_InstanceMapScript(map); - } - struct instance_violet_hold_InstanceMapScript : public InstanceScript { instance_violet_hold_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); + SetBossNumber(EncounterCount); + LoadObjectData(creatureData, gameObjectData); uiRemoveNpc = 0; @@ -138,29 +145,11 @@ public: bCrystalActivated = false; defenseless = true; uiMainEventPhase = NOT_STARTED; - - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + zuramatDead = false; } - ObjectGuid uiMoragg; - ObjectGuid uiErekem; ObjectGuid uiErekemGuard[2]; - ObjectGuid uiIchoron; - ObjectGuid uiLavanthor; - ObjectGuid uiXevozz; - ObjectGuid uiZuramat; - ObjectGuid uiCyanigosa; - ObjectGuid uiSinclari; - - ObjectGuid uiMoraggCell; - ObjectGuid uiErekemCell; - ObjectGuid uiErekemLeftGuardCell; - ObjectGuid uiErekemRightGuardCell; - ObjectGuid uiIchoronCell; - ObjectGuid uiLavanthorCell; - ObjectGuid uiXevozzCell; - ObjectGuid uiZuramatCell; - ObjectGuid uiMainDoor; + ObjectGuid uiTeleportationPortal; ObjectGuid uiSaboteurPortal; @@ -180,7 +169,6 @@ public: uint8 uiDoorIntegrity; - uint16 m_auiEncounter[MAX_ENCOUNTER]; uint8 uiCountErekemGuards; uint8 uiCountActivationCrystals; uint8 uiCyanigosaEventPhase; @@ -191,132 +179,93 @@ public: bool bIsDoorSpellCast; bool bCrystalActivated; bool defenseless; + bool zuramatDead; std::list<uint8> NpcAtDoorCastingList; - std::string str_data; - - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; - } - void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + switch (creature->GetEntry()) { - case CREATURE_XEVOZZ: - uiXevozz = creature->GetGUID(); - break; - case CREATURE_LAVANTHOR: - uiLavanthor = creature->GetGUID(); - break; - case CREATURE_ICHORON: - uiIchoron = creature->GetGUID(); - break; - case CREATURE_ZURAMAT: - uiZuramat = creature->GetGUID(); - break; - case CREATURE_EREKEM: - uiErekem = creature->GetGUID(); - break; - case CREATURE_EREKEM_GUARD: + case NPC_EREKEM_GUARD: if (uiCountErekemGuards < 2) { uiErekemGuard[uiCountErekemGuards++] = creature->GetGUID(); - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); } break; - case CREATURE_MORAGG: - uiMoragg = creature->GetGUID(); + case NPC_CYANIGOSA: + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); break; - case CREATURE_CYANIGOSA: - uiCyanigosa = creature->GetGUID(); - creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + default: break; - case CREATURE_SINCLARI: - uiSinclari = creature->GetGUID(); + case NPC_VOID_SENTRY: + if (zuramatDead) + { + creature->DespawnOrUnsummon(); + zuramatDead = false; + } break; } - /* - BEWARE - SHIT. - if (creature->GetGUID() == uiFirstBoss || creature->GetGUID() == uiSecondBoss) + /*if (creature->GetGUID() == uiFirstBoss || creature->GetGUID() == uiSecondBoss) { creature->AllLootRemovedFromCorpse(); creature->RemoveLootMode(1); - } - */ + }*/ } void OnGameObjectCreate(GameObject* go) override { + InstanceScript::OnGameObjectCreate(go); + switch (go->GetEntry()) { - case GO_EREKEM_GUARD_1_DOOR: - uiErekemLeftGuardCell = go->GetGUID(); - break; - case GO_EREKEM_GUARD_2_DOOR: - uiErekemRightGuardCell = go->GetGUID(); - break; - case GO_EREKEM_DOOR: - uiErekemCell = go->GetGUID(); - break; - case GO_ZURAMAT_DOOR: - uiZuramatCell = go->GetGUID(); - break; - case GO_LAVANTHOR_DOOR: - uiLavanthorCell = go->GetGUID(); - break; - case GO_MORAGG_DOOR: - uiMoraggCell = go->GetGUID(); - break; - case GO_ICHORON_DOOR: - uiIchoronCell = go->GetGUID(); - break; - case GO_XEVOZZ_DOOR: - uiXevozzCell = go->GetGUID(); - break; - case GO_MAIN_DOOR: - uiMainDoor = go->GetGUID(); - break; case GO_ACTIVATION_CRYSTAL: if (uiCountActivationCrystals < 4) uiActivationCrystal[uiCountActivationCrystals++] = go->GetGUID(); break; + default: + break; } } - void SetData(uint32 type, uint32 data) override + bool SetBossState(uint32 type, EncounterState state) override { + if (!InstanceScript::SetBossState(type, state)) + return false; + switch (type) { case DATA_1ST_BOSS_EVENT: - UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_EREKEM, NULL); - m_auiEncounter[0] = data; - if (data == DONE) - SaveToDB(); + if (state == DONE) + UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_EREKEM, nullptr); break; case DATA_2ND_BOSS_EVENT: - UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, CREATURE_MORAGG, NULL); - m_auiEncounter[1] = data; - if (data == DONE) - SaveToDB(); - break; - case DATA_CYANIGOSA_EVENT: - m_auiEncounter[2] = data; - if (data == DONE) + if (state == DONE) + UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_MORAGG, nullptr); + break; + case DATA_CYANIGOSA: + if (state == DONE) { - SaveToDB(); uiMainEventPhase = DONE; - if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) - pMainDoor->SetGoState(GO_STATE_ACTIVE); + if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR)) + mainDoor->SetGoState(GO_STATE_ACTIVE); } break; + default: + break; + } + + return true; + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { case DATA_WAVE_COUNT: uiWaveCount = data; bActive = true; @@ -340,21 +289,8 @@ public: NpcAtDoorCastingList.pop_back(); break; case DATA_MAIN_DOOR: - if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) - { - switch (data) - { - case GO_STATE_ACTIVE: - pMainDoor->SetGoState(GO_STATE_ACTIVE); - break; - case GO_STATE_READY: - pMainDoor->SetGoState(GO_STATE_READY); - break; - case GO_STATE_ACTIVE_ALTERNATIVE: - pMainDoor->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - break; - } - } + if (GameObject* mainDoor = GetGameObject(type)) + mainDoor->SetGoState(GOState(data)); break; case DATA_START_BOSS_ENCOUNTER: switch (uiWaveCount) @@ -374,7 +310,7 @@ public: uiMainEventPhase = data; if (data == IN_PROGRESS) // Start event { - if (GameObject* mainDoor = instance->GetGameObject(uiMainDoor)) + if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR)) mainDoor->SetGoState(GO_STATE_READY); uiWaveCount = 1; bActive = true; @@ -384,6 +320,9 @@ public: uiRemoveNpc = 0; // might not have been reset after a wipe on a boss. } break; + case DATA_ZURAMAT: + zuramatDead = true; + break; } } @@ -404,9 +343,6 @@ public: { switch (type) { - case DATA_1ST_BOSS_EVENT: return m_auiEncounter[0]; - case DATA_2ND_BOSS_EVENT: return m_auiEncounter[1]; - case DATA_CYANIGOSA_EVENT: return m_auiEncounter[2]; case DATA_WAVE_COUNT: return uiWaveCount; case DATA_REMOVE_NPC: return uiRemoveNpc; case DATA_PORTAL_LOCATION: return uiLocation; @@ -421,125 +357,114 @@ public: return 0; } - ObjectGuid GetGuidData(uint32 identifier) const override + ObjectGuid GetGuidData(uint32 type) const override { - switch (identifier) + switch (type) { - case DATA_MORAGG: return uiMoragg; - case DATA_EREKEM: return uiErekem; case DATA_EREKEM_GUARD_1: return uiErekemGuard[0]; case DATA_EREKEM_GUARD_2: return uiErekemGuard[1]; - case DATA_ICHORON: return uiIchoron; - case DATA_LAVANTHOR: return uiLavanthor; - case DATA_XEVOZZ: return uiXevozz; - case DATA_ZURAMAT: return uiZuramat; - case DATA_CYANIGOSA: return uiCyanigosa; - case DATA_MORAGG_CELL: return uiMoraggCell; - case DATA_EREKEM_CELL: return uiErekemCell; - case DATA_EREKEM_RIGHT_GUARD_CELL: return uiErekemRightGuardCell; - case DATA_EREKEM_LEFT_GUARD_CELL: return uiErekemLeftGuardCell; - case DATA_ICHORON_CELL: return uiIchoronCell; - case DATA_LAVANTHOR_CELL: return uiLavanthorCell; - case DATA_XEVOZZ_CELL: return uiXevozzCell; - case DATA_ZURAMAT_CELL: return uiZuramatCell; - case DATA_MAIN_DOOR: return uiMainDoor; - case DATA_SINCLARI: return uiSinclari; case DATA_TELEPORTATION_PORTAL: return uiTeleportationPortal; case DATA_SABOTEUR_PORTAL: return uiSaboteurPortal; } - return ObjectGuid::Empty; + return InstanceScript::GetGuidData(type); } void SpawnPortal() { SetData(DATA_PORTAL_LOCATION, (GetData(DATA_PORTAL_LOCATION) + urand(1, 5))%6); - if (Creature* pSinclari = instance->GetCreature(uiSinclari)) - if (Creature* portal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, PortalLocation[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN)) + if (Creature* sinclari = GetCreature(DATA_SINCLARI)) + if (Creature* portal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[GetData(DATA_PORTAL_LOCATION)], TEMPSUMMON_CORPSE_DESPAWN)) uiTeleportationPortal = portal->GetGUID(); } void StartBossEncounter(uint8 uiBoss, bool bForceRespawn = true) { - Creature* pBoss = NULL; + Creature* boss = nullptr; switch (uiBoss) { case BOSS_MORAGG: - HandleGameObject(uiMoraggCell, bForceRespawn); - pBoss = instance->GetCreature(uiMoragg); - if (pBoss) - pBoss->GetMotionMaster()->MovePoint(0, BossStartMove1); + HandleGameObject(GetObjectGuid(DATA_MORAGG_CELL), bForceRespawn); + boss = GetCreature(DATA_MORAGG); + if (boss) + boss->GetMotionMaster()->MovePoint(0, BossStartMove1); break; case BOSS_EREKEM: - HandleGameObject(uiErekemCell, bForceRespawn); - HandleGameObject(uiErekemRightGuardCell, bForceRespawn); - HandleGameObject(uiErekemLeftGuardCell, bForceRespawn); - - pBoss = instance->GetCreature(uiErekem); + HandleGameObject(GetObjectGuid(DATA_EREKEM_CELL), bForceRespawn); + HandleGameObject(GetObjectGuid(DATA_EREKEM_LEFT_GUARD_CELL), bForceRespawn); + HandleGameObject(GetObjectGuid(DATA_EREKEM_RIGHT_GUARD_CELL), bForceRespawn); - if (pBoss) - pBoss->GetMotionMaster()->MovePoint(0, BossStartMove2); + boss = GetCreature(DATA_EREKEM); + if (boss) + boss->GetMotionMaster()->MovePoint(0, BossStartMove2); if (Creature* pGuard1 = instance->GetCreature(uiErekemGuard[0])) { if (bForceRespawn) - pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + { + pGuard1->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE); + pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21); + } else pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); - pGuard1->GetMotionMaster()->MovePoint(0, BossStartMove21); } if (Creature* pGuard2 = instance->GetCreature(uiErekemGuard[1])) { if (bForceRespawn) + { pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22); + } else pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); - pGuard2->GetMotionMaster()->MovePoint(0, BossStartMove22); } break; case BOSS_ICHORON: - HandleGameObject(uiIchoronCell, bForceRespawn); - pBoss = instance->GetCreature(uiIchoron); - if (pBoss) - pBoss->GetMotionMaster()->MovePoint(0, BossStartMove3); + HandleGameObject(GetObjectGuid(DATA_ICHORON_CELL), bForceRespawn); + boss = GetCreature(DATA_ICHORON); + if (boss) + boss->GetMotionMaster()->MovePoint(0, BossStartMove3); break; case BOSS_LAVANTHOR: - HandleGameObject(uiLavanthorCell, bForceRespawn); - pBoss = instance->GetCreature(uiLavanthor); - if (pBoss) - pBoss->GetMotionMaster()->MovePoint(0, BossStartMove4); + HandleGameObject(GetObjectGuid(DATA_LAVANTHOR_CELL), bForceRespawn); + boss = GetCreature(DATA_LAVANTHOR); + if (boss) + boss->GetMotionMaster()->MovePoint(0, BossStartMove4); break; case BOSS_XEVOZZ: - HandleGameObject(uiXevozzCell, bForceRespawn); - pBoss = instance->GetCreature(uiXevozz); - if (pBoss) - pBoss->GetMotionMaster()->MovePoint(0, BossStartMove5); + HandleGameObject(GetObjectGuid(DATA_XEVOZZ_CELL), bForceRespawn); + boss = GetCreature(DATA_XEVOZZ); + if (boss) + boss->GetMotionMaster()->MovePoint(0, BossStartMove5); break; case BOSS_ZURAMAT: - HandleGameObject(uiZuramatCell, bForceRespawn); - pBoss = instance->GetCreature(uiZuramat); - if (pBoss) - pBoss->GetMotionMaster()->MovePoint(0, BossStartMove6); + HandleGameObject(GetObjectGuid(DATA_ZURAMAT_CELL), bForceRespawn); + boss = GetCreature(DATA_ZURAMAT); + if (boss) + boss->GetMotionMaster()->MovePoint(0, BossStartMove6); break; } // generic boss state changes - if (pBoss) + if (boss) { - pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); - pBoss->SetReactState(REACT_AGGRESSIVE); + boss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + boss->SetReactState(REACT_AGGRESSIVE); if (!bForceRespawn) { - if (pBoss->isDead()) + if (boss->isDead()) { // respawn but avoid to be looted again - pBoss->Respawn(); - pBoss->RemoveLootMode(1); + boss->Respawn(); + boss->RemoveLootMode(1); } - pBoss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + else + boss->GetMotionMaster()->MoveTargetedHome(); + + boss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); uiWaveCount = 0; } } @@ -555,12 +480,12 @@ public: case 6: if (uiFirstBoss == 0) uiFirstBoss = urand(1, 6); - if (Creature* pSinclari = instance->GetCreature(uiSinclari)) + if (Creature* sinclari = GetCreature(DATA_SINCLARI)) { - if (Creature* pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN)) - uiSaboteurPortal = pPortal->GetGUID(); - if (Creature* pAzureSaboteur = pSinclari->SummonCreature(CREATURE_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN)) - pAzureSaboteur->CastSpell(pAzureSaboteur, SABOTEUR_SHIELD_EFFECT, false); + if (Creature* portal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN)) + uiSaboteurPortal = portal->GetGUID(); + if (Creature* azureSaboteur = sinclari->SummonCreature(NPC_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN)) + azureSaboteur->CastSpell(azureSaboteur, SABOTEUR_SHIELD_EFFECT, false); } break; case 12: @@ -569,25 +494,22 @@ public: { uiSecondBoss = urand(1, 6); } while (uiSecondBoss == uiFirstBoss); - if (Creature* pSinclari = instance->GetCreature(uiSinclari)) + if (Creature* sinclari = GetCreature(DATA_SINCLARI)) { - if (Creature* pPortal = pSinclari->SummonCreature(CREATURE_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN)) + if (Creature* pPortal = sinclari->SummonCreature(NPC_TELEPORTATION_PORTAL, MiddleRoomPortalSaboLocation, TEMPSUMMON_CORPSE_DESPAWN)) uiSaboteurPortal = pPortal->GetGUID(); - if (Creature* pAzureSaboteur = pSinclari->SummonCreature(CREATURE_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN)) + if (Creature* pAzureSaboteur = sinclari->SummonCreature(NPC_SABOTEOUR, MiddleRoomLocation, TEMPSUMMON_DEAD_DESPAWN)) pAzureSaboteur->CastSpell(pAzureSaboteur, SABOTEUR_SHIELD_EFFECT, false); } break; case 18: - { - Creature* pSinclari = instance->GetCreature(uiSinclari); - if (pSinclari) - pSinclari->SummonCreature(CREATURE_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN); + if (Creature* sinclari = GetCreature(DATA_SINCLARI)) + sinclari->SummonCreature(NPC_CYANIGOSA, CyanigosasSpawnLocation, TEMPSUMMON_DEAD_DESPAWN); break; - } case 1: { - if (GameObject* pMainDoor = instance->GetGameObject(uiMainDoor)) - pMainDoor->SetGoState(GO_STATE_READY); + if (GameObject* mainDoor = GetGameObject(DATA_MAIN_DOOR)) + mainDoor->SetGoState(GO_STATE_READY); DoUpdateWorldState(WORLD_STATE_VH_PRISON_STATE, 100); // no break } @@ -597,54 +519,15 @@ public: } } - std::string GetSaveData() override + void WriteSaveDataMore(std::ostringstream& data) override { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << "V H " << (uint16)m_auiEncounter[0] - << ' ' << (uint16)m_auiEncounter[1] - << ' ' << (uint16)m_auiEncounter[2] - << ' ' << (uint16)uiFirstBoss - << ' ' << (uint16)uiSecondBoss; - - str_data = saveStream.str(); - - OUT_SAVE_INST_DATA_COMPLETE; - return str_data; + data << uiFirstBoss << ' ' << uiSecondBoss; } - void Load(const char* in) override + void ReadSaveDataMore(std::istringstream& data) override { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - - char dataHead1, dataHead2; - uint16 data0, data1, data2, data3, data4; - - std::istringstream loadStream(in); - loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2 >> data3 >> data4; - - if (dataHead1 == 'V' && dataHead2 == 'H') - { - m_auiEncounter[0] = data0; - m_auiEncounter[1] = data1; - m_auiEncounter[2] = data2; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - m_auiEncounter[i] = NOT_STARTED; - - uiFirstBoss = uint8(data3); - uiSecondBoss = uint8(data4); - } else OUT_LOAD_INST_DATA_FAIL; - - OUT_LOAD_INST_DATA_COMPLETE; + data >> uiFirstBoss; + data >> uiSecondBoss; } bool CheckWipe() @@ -660,6 +543,7 @@ public: return false; } + zuramatDead = false; return true; } @@ -690,59 +574,57 @@ public: SetData(DATA_MAIN_DOOR, GO_STATE_ACTIVE); SetData(DATA_WAVE_COUNT, 0); uiMainEventPhase = NOT_STARTED; + uiActivationTimer = 5000; for (int i = 0; i < 4; ++i) if (GameObject* crystal = instance->GetGameObject(uiActivationCrystal[i])) crystal->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - if (Creature* pSinclari = instance->GetCreature(uiSinclari)) + if (Creature* sinclari = GetCreature(DATA_SINCLARI)) { - pSinclari->SetVisible(true); + sinclari->SetVisible(true); std::list<Creature*> GuardList; - pSinclari->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); + sinclari->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); if (!GuardList.empty()) { - for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) + for (Creature* guard : GuardList) { - if (Creature* pGuard = *itr) - { - pGuard->SetVisible(true); - pGuard->SetReactState(REACT_AGGRESSIVE); - pGuard->GetMotionMaster()->MovePoint(1, pGuard->GetHomePosition()); - } + guard->SetVisible(true); + guard->SetReactState(REACT_AGGRESSIVE); + guard->GetMotionMaster()->MovePoint(1, guard->GetHomePosition()); } } - pSinclari->GetMotionMaster()->MovePoint(1, pSinclari->GetHomePosition()); - pSinclari->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + sinclari->GetMotionMaster()->MovePoint(1, sinclari->GetHomePosition()); + sinclari->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } } // Cyanigosa is spawned but not tranformed, prefight event - Creature* pCyanigosa = instance->GetCreature(uiCyanigosa); - if (pCyanigosa && !pCyanigosa->HasAura(CYANIGOSA_SPELL_TRANSFORM)) + Creature* cyanigosa = GetCreature(DATA_CYANIGOSA); + if (cyanigosa && !cyanigosa->HasAura(CYANIGOSA_SPELL_TRANSFORM)) { if (uiCyanigosaEventTimer <= diff) { switch (uiCyanigosaEventPhase) { case 1: - pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_BLUE_AURA, false); - pCyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN); + cyanigosa->CastSpell(cyanigosa, CYANIGOSA_BLUE_AURA, false); + cyanigosa->AI()->Talk(CYANIGOSA_SAY_SPAWN); uiCyanigosaEventTimer = 7*IN_MILLISECONDS; ++uiCyanigosaEventPhase; break; case 2: - pCyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f); - pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_BLUE_AURA, false); + cyanigosa->GetMotionMaster()->MoveJump(MiddleRoomLocation.GetPositionX(), MiddleRoomLocation.GetPositionY(), MiddleRoomLocation.GetPositionZ(), 10.0f, 20.0f); + cyanigosa->CastSpell(cyanigosa, CYANIGOSA_BLUE_AURA, false); uiCyanigosaEventTimer = 7*IN_MILLISECONDS; ++uiCyanigosaEventPhase; break; case 3: - pCyanigosa->RemoveAurasDueToSpell(CYANIGOSA_BLUE_AURA); - pCyanigosa->CastSpell(pCyanigosa, CYANIGOSA_SPELL_TRANSFORM, 0); - pCyanigosa->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); - pCyanigosa->SetReactState(REACT_AGGRESSIVE); + cyanigosa->RemoveAurasDueToSpell(CYANIGOSA_BLUE_AURA); + cyanigosa->CastSpell(cyanigosa, CYANIGOSA_SPELL_TRANSFORM, 0); + cyanigosa->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE); + cyanigosa->SetReactState(REACT_AGGRESSIVE); uiCyanigosaEventTimer = 2*IN_MILLISECONDS; ++uiCyanigosaEventPhase; break; @@ -815,6 +697,11 @@ public: } } }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override + { + return new instance_violet_hold_InstanceMapScript(map); + } }; void AddSC_instance_violet_hold() diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index 645a9da4764..b05da4b994c 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -28,22 +28,23 @@ #define GOSSIP_START_EVENT "Get your people to safety, we'll keep the Blue Dragonflight's forces at bay." #define GOSSIP_ITEM_1 "Activate the crystals when we get in trouble, right" #define GOSSIP_I_WANT_IN "I'm not fighting, so send me in now!" +#define SAY_EVENT_LOCK "I'm locking the door. Good luck, and thank you for doing this." #define SPAWN_TIME 20000 enum PortalCreatures { - CREATURE_AZURE_INVADER_1 = 30661, - CREATURE_AZURE_INVADER_2 = 30961, - CREATURE_AZURE_SPELLBREAKER_1 = 30662, - CREATURE_AZURE_SPELLBREAKER_2 = 30962, - CREATURE_AZURE_BINDER_1 = 30663, - CREATURE_AZURE_BINDER_2 = 30918, - CREATURE_AZURE_MAGE_SLAYER_1 = 30664, - CREATURE_AZURE_MAGE_SLAYER_2 = 30963, - CREATURE_AZURE_CAPTAIN = 30666, - CREATURE_AZURE_SORCEROR = 30667, - CREATURE_AZURE_RAIDER = 30668, - CREATURE_AZURE_STALKER = 32191 + NPC_AZURE_INVADER_1 = 30661, + NPC_AZURE_INVADER_2 = 30961, + NPC_AZURE_SPELLBREAKER_1 = 30662, + NPC_AZURE_SPELLBREAKER_2 = 30962, + NPC_AZURE_BINDER_1 = 30663, + NPC_AZURE_BINDER_2 = 30918, + NPC_AZURE_MAGE_SLAYER_1 = 30664, + NPC_AZURE_MAGE_SLAYER_2 = 30963, + NPC_AZURE_CAPTAIN = 30666, + NPC_AZURE_SORCEROR = 30667, + NPC_AZURE_RAIDER = 30668, + NPC_AZURE_STALKER = 32191 }; enum AzureInvaderSpells @@ -59,7 +60,7 @@ enum AzureSellbreakerSpells SPELL_ARCANE_BLAST = 58462, SPELL_SLOW = 25603, SPELL_CHAINS_OF_ICE = 58464, - SPELL_CONE_OF_COLD = 58463 + SPELL_CONE_OF_COLD = 58463, }; enum AzureBinderSpells @@ -67,7 +68,7 @@ enum AzureBinderSpells SPELL_ARCANE_BARRAGE = 58456, SPELL_ARCANE_EXPLOSION = 58455, SPELL_FROST_NOVA = 58458, - SPELL_FROSTBOLT = 58457 + SPELL_FROSTBOLT = 58457, }; enum AzureMageSlayerSpells @@ -85,7 +86,7 @@ enum AzureCaptainSpells enum AzureSorcerorSpells { SPELL_ARCANE_STREAM = 60181, - SPELL_MANA_DETONATION = 60182 + SPELL_MANA_DETONATION = 60182, }; enum AzureRaiderSpells @@ -114,7 +115,7 @@ enum TrashDoorSpell enum Spells { SPELL_PORTAL_CHANNEL = 58012, - SPELL_CRYSTAL_ACTIVATION = 57804, + SPELL_CRYSTAL_ACTIVATION = 57804, // visual effect SPELL_ARCANE_SPHERE_PASSIVE = 44263 }; @@ -242,9 +243,21 @@ const float SaboteurFinalPos6[5][3] = {1931.063354f, 848.468445f, 47.190434f} }; -const Position MovePosition = {1806.955566f, 803.851807f, 44.363323f, 0.0f}; -const Position playerTeleportPosition = {1830.531006f, 803.939758f, 44.340508f, 6.281611f}; -const Position sinclariOutsidePosition = {1817.315674f, 804.060608f, 44.363998f, 0.0f}; +const Position PortalLocation[] = +{ + { 1877.51f, 850.104f, 44.6599f, 4.7822f }, // WP 1 + { 1936.07f, 803.198f, 53.3749f, 3.12414f }, // WP 3 + { 1890.64f, 753.471f, 48.7224f, 1.71042f }, // WP 5 +}; + +#define MAX_PRE_EVENT_PORTAL 3 + +ObjectGuid preEventPortalGUID[MAX_PRE_EVENT_PORTAL] = { ObjectGuid::Empty }; + +const Position MovePosition = { 1806.955566f, 803.851807f, 44.363323f, 0.0f }; +const Position playerTeleportPosition = { 1830.531006f, 803.939758f, 44.340508f, 6.281611f }; +const Position sinclariOutsidePosition = { 1820.429810f, 804.066040f, 44.363998f, 0.0f }; +const Position sinclariCrystalPosition = { 1828.868286f, 798.468811f, 44.363998f, 3.890467f }; class npc_sinclari_vh : public CreatureScript { @@ -258,7 +271,7 @@ public: { case GOSSIP_ACTION_INFO_DEF+1: player->CLOSE_GOSSIP_MENU(); - ENSURE_AI(npc_sinclari_vh::npc_sinclariAI, (creature->AI()))->uiPhase = 1; + ENSURE_AI(npc_sinclari_vh::npc_sinclariAI, creature->AI())->uiPhase = 1; if (InstanceScript* instance = creature->GetInstanceScript()) instance->SetData(DATA_MAIN_EVENT_PHASE, SPECIAL); break; @@ -296,17 +309,12 @@ public: return true; } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_sinclariAI>(creature); - } - struct npc_sinclariAI : public ScriptedAI { npc_sinclariAI(Creature* creature) : ScriptedAI(creature) { Initialize(); - instance = creature->GetInstanceScript(); + instance = creature->GetInstanceScript(); } void Initialize() @@ -325,6 +333,9 @@ public: Initialize(); me->SetReactState(REACT_AGGRESSIVE); + for (uint8 i = 0; i < MAX_PRE_EVENT_PORTAL; i++) + if (TempSummon* summon = me->SummonCreature(NPC_TELEPORTATION_PORTAL, PortalLocation[i], TEMPSUMMON_MANUAL_DESPAWN)) + preEventPortalGUID[i] = summon->GetGUID(); std::list<Creature*> GuardList; me->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); @@ -345,8 +356,6 @@ public: void UpdateAI(uint32 uiDiff) override { - ScriptedAI::UpdateAI(uiDiff); - if (uiPhase) { if (uiTimer <= uiDiff) @@ -354,25 +363,17 @@ public: switch (uiPhase) { case 1: - Talk(SAY_SINCLARI_1); - uiTimer = 4000; - uiPhase = 2; + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(0, sinclariCrystalPosition); + uiTimer = 1000; + uiPhase = 6; break; case 2: { - std::list<Creature*> GuardList; - me->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); - if (!GuardList.empty()) - for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) - { - if (Creature* pGuard = *itr) - { - pGuard->SetWalk(false); - pGuard->GetMotionMaster()->MovePoint(0, MovePosition); - } - } - uiTimer = 6000; - uiPhase = 3; + me->SetFacingTo(me->GetOrientation() - 3.14f); + Talk(SAY_SINCLARI_1); + uiTimer = 1500; + uiPhase = 7; break; } case 3: @@ -385,7 +386,6 @@ public: if (Creature* pGuard = *itr) { pGuard->SetVisible(false); - pGuard->SetReactState(REACT_PASSIVE); } } uiTimer = 2000; @@ -398,11 +398,58 @@ public: uiPhase = 5; break; case 5: - instance->SetData(DATA_MAIN_EVENT_PHASE, IN_PROGRESS); + me->SetFacingTo(0.006673f); + me->Say(SAY_EVENT_LOCK, LANG_UNIVERSAL, me); // need to change to db say me->SetReactState(REACT_PASSIVE); + uiTimer = 3000; + uiPhase = 8; + break; + case 6: + me->GetMotionMaster()->MovementExpired(); + me->HandleEmoteCommand(EMOTE_STATE_USE_STANDING); + uiTimer = 2000; + uiPhase = 2; + break; + case 7: + { + std::list<Creature*> creatures; + GetCreatureListWithEntryInGrid(creatures, me, NPC_TELEPORTATION_PORTAL, 200.0f); + GetCreatureListWithEntryInGrid(creatures, me, NPC_AZURE_BINDER_1, 200.0f); + GetCreatureListWithEntryInGrid(creatures, me, NPC_AZURE_MAGE_SLAYER_1, 200.0f); + GetCreatureListWithEntryInGrid(creatures, me, NPC_AZURE_INVADER_1, 200.0f); + DoCast(SPELL_CRYSTAL_ACTIVATION); + if (!creatures.empty()) + { + for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr) + (*itr)->DisappearAndDie(); + } + uiTimer = 500; + uiPhase = 9; + } + break; + case 8: + instance->SetData(DATA_MAIN_EVENT_PHASE, IN_PROGRESS); uiTimer = 0; uiPhase = 0; break; + case 9: + { + std::list<Creature*> GuardList; + me->GetCreatureListWithEntryInGrid(GuardList, NPC_VIOLET_HOLD_GUARD, 40.0f); + if (!GuardList.empty()) + for (std::list<Creature*>::const_iterator itr = GuardList.begin(); itr != GuardList.end(); ++itr) + { + if (Creature* pGuard = *itr) + { + pGuard->SetReactState(REACT_PASSIVE); + pGuard->SetWalk(false); + pGuard->GetMotionMaster()->MovePoint(0, MovePosition); + } + } + uiTimer = 4000; + uiPhase = 3; + } + break; } } else uiTimer -= uiDiff; @@ -415,6 +462,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_sinclariAI>(creature); + } }; class npc_azure_saboteur : public CreatureScript @@ -422,14 +473,9 @@ class npc_azure_saboteur : public CreatureScript public: npc_azure_saboteur() : CreatureScript("npc_azure_saboteur") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_saboteurAI>(creature); - } - struct npc_azure_saboteurAI : public npc_escortAI { - npc_azure_saboteurAI(Creature* creature):npc_escortAI(creature) + npc_azure_saboteurAI(Creature* creature) : npc_escortAI(creature) { instance = creature->GetInstanceScript(); bHasGotMovingPoints = false; @@ -532,13 +578,16 @@ public: { me->CastSpell(me, SABOTEUR_SHIELD_DISRUPTION, false); me->DisappearAndDie(); - Creature* pSaboPort = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_SABOTEUR_PORTAL)); - if (pSaboPort) + if (Creature* pSaboPort = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_SABOTEUR_PORTAL))) pSaboPort->DisappearAndDie(); instance->SetData(DATA_START_BOSS_ENCOUNTER, 1); } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_saboteurAI>(creature); + } }; class npc_teleportation_portal_vh : public CreatureScript @@ -546,11 +595,6 @@ class npc_teleportation_portal_vh : public CreatureScript public: npc_teleportation_portal_vh() : CreatureScript("npc_teleportation_portal_vh") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_teleportation_portalAI>(creature); - } - struct npc_teleportation_portalAI : public ScriptedAI { npc_teleportation_portalAI(Creature* creature) : ScriptedAI(creature), listOfMobs(me) @@ -558,6 +602,9 @@ public: Initialize(); instance = creature->GetInstanceScript(); uiTypeOfMobsPortal = urand(0, 1); // 0 - elite mobs 1 - portal guardian or portal keeper with regular mobs + + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == NOT_STARTED) + uiTypeOfMobsPortal = 2; } void Initialize() @@ -583,13 +630,15 @@ public: void MoveInLineOfSight(Unit* /*who*/) override { } - void UpdateAI(uint32 diff) override { - if (instance->GetData(DATA_REMOVE_NPC) == 1) + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) { - me->DespawnOrUnsummon(); - instance->SetData(DATA_REMOVE_NPC, 0); + if (instance->GetData(DATA_REMOVE_NPC) == 1) + { + me->DespawnOrUnsummon(); + instance->SetData(DATA_REMOVE_NPC, 0); + } } uint8 uiWaveCount = instance->GetData(DATA_WAVE_COUNT); @@ -608,7 +657,7 @@ public: uint8 k = uiWaveCount < 12 ? 2 : 3; for (uint8 i = 0; i < k; ++i) { - uint32 entry = RAND(CREATURE_AZURE_CAPTAIN, CREATURE_AZURE_RAIDER, CREATURE_AZURE_STALKER, CREATURE_AZURE_SORCEROR); + uint32 entry = RAND(NPC_AZURE_CAPTAIN, NPC_AZURE_RAIDER, NPC_AZURE_STALKER, NPC_AZURE_SORCEROR); DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN); } me->SetVisible(false); @@ -633,14 +682,14 @@ public: uint8 k = instance->GetData(DATA_WAVE_COUNT) < 12 ? 3 : 4; for (uint8 i = 0; i < k; ++i) { - uint32 entry = RAND(CREATURE_AZURE_INVADER_1, CREATURE_AZURE_INVADER_2, CREATURE_AZURE_SPELLBREAKER_1, CREATURE_AZURE_SPELLBREAKER_2, CREATURE_AZURE_MAGE_SLAYER_1, CREATURE_AZURE_MAGE_SLAYER_2, CREATURE_AZURE_BINDER_1, CREATURE_AZURE_BINDER_2); + uint32 entry = RAND(NPC_AZURE_INVADER_1, NPC_AZURE_INVADER_2, NPC_AZURE_SPELLBREAKER_1, NPC_AZURE_SPELLBREAKER_2, NPC_AZURE_MAGE_SLAYER_1, NPC_AZURE_MAGE_SLAYER_2, NPC_AZURE_BINDER_1, NPC_AZURE_BINDER_2); DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN); } } else { bPortalGuardianOrKeeperOrEliteSpawn = true; - uint32 entry = RAND(CREATURE_PORTAL_GUARDIAN, CREATURE_PORTAL_KEEPER); + uint32 entry = RAND(NPC_PORTAL_GUARDIAN, NPC_PORTAL_KEEPER); if (Creature* pPortalKeeper = DoSummon(entry, me, 2.0f, 0, TEMPSUMMON_DEAD_DESPAWN)) me->CastSpell(pPortalKeeper, SPELL_PORTAL_CHANNEL, false); } @@ -653,37 +702,71 @@ public: me->RemoveCorpse(); } break; + case 2: // Pre-event + if (uiSpawnTimer <= diff) + { + uint32 entry = RAND(NPC_AZURE_INVADER_1, NPC_AZURE_MAGE_SLAYER_1, NPC_AZURE_BINDER_1); + DoSummon(entry, me, 2.0f, 20000, TEMPSUMMON_DEAD_DESPAWN); + uiSpawnTimer = SPAWN_TIME; + } else uiSpawnTimer -= diff; + break; } } void JustDied(Unit* /*killer*/) override { - instance->SetData(DATA_WAVE_COUNT, instance->GetData(DATA_WAVE_COUNT)+1); + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) + instance->SetData(DATA_WAVE_COUNT, instance->GetData(DATA_WAVE_COUNT) + 1); } void JustSummoned(Creature* summoned) override { - listOfMobs.Summon(summoned); - instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) + { + listOfMobs.Summon(summoned); + instance->SetGuidData(DATA_ADD_TRASH_MOB, summoned->GetGUID()); + } } void SummonedCreatureDies(Creature* summoned, Unit* /*killer*/) override { - listOfMobs.Despawn(summoned); - instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == IN_PROGRESS) + { + listOfMobs.Despawn(summoned); + instance->SetGuidData(DATA_DEL_TRASH_MOB, summoned->GetGUID()); + } } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_teleportation_portalAI>(creature); + } }; struct violet_hold_trashAI : public npc_escortAI { - violet_hold_trashAI(Creature* creature):npc_escortAI(creature) + violet_hold_trashAI(Creature* creature) : npc_escortAI(creature) { instance = creature->GetInstanceScript(); bHasGotMovingPoints = false; - portalLocationID = instance->GetData(DATA_PORTAL_LOCATION); - secondPortalRouteID = 0; + + + if (instance->GetData(DATA_MAIN_EVENT_PHASE) == NOT_STARTED) + { + if (Creature* portal = me->FindNearestCreature(NPC_TELEPORTATION_PORTAL, 10.0f)) + { + ObjectGuid portalGUID = portal->GetGUID(); + for (uint8 i = 0; i < MAX_PRE_EVENT_PORTAL; i++) + if (portalGUID == preEventPortalGUID[i]) + portalLocationID = i * 2; + } + } + else + { + portalLocationID = instance->GetData(DATA_PORTAL_LOCATION); + Reset(); + } } public: @@ -698,7 +781,7 @@ struct violet_hold_trashAI : public npc_escortAI { case 0: if (waypointId == 5) - CreatureStartAttackDoor(); + CreatureStartAttackDoor(); break; case 1: if ((waypointId == 8 && secondPortalRouteID == 0) || (waypointId == 7 && secondPortalRouteID == 1)) @@ -706,7 +789,7 @@ struct violet_hold_trashAI : public npc_escortAI break; case 2: if (waypointId == 7) - CreatureStartAttackDoor(); + CreatureStartAttackDoor(); break; case 3: if (waypointId == 8) @@ -723,7 +806,7 @@ struct violet_hold_trashAI : public npc_escortAI } } - void UpdateAI(uint32) override + void UpdateAI(uint32 diff) override { if (instance->GetData(DATA_MAIN_EVENT_PHASE) != IN_PROGRESS) me->CastStop(); @@ -778,6 +861,8 @@ struct violet_hold_trashAI : public npc_escortAI SetDespawnAtEnd(false); Start(true, true); } + + npc_escortAI::UpdateAI(diff); } void JustDied(Unit* /*killer*/) override @@ -791,7 +876,6 @@ struct violet_hold_trashAI : public npc_escortAI DoCast(SPELL_DESTROY_DOOR_SEAL); instance->SetData(DATA_NPC_PRESENCE_AT_DOOR_ADD, 1); } - }; class npc_azure_invader : public CreatureScript @@ -799,11 +883,6 @@ class npc_azure_invader : public CreatureScript public: npc_azure_invader() : CreatureScript("npc_azure_invader") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_invaderAI>(creature); - } - struct npc_azure_invaderAI : public violet_hold_trashAI { npc_azure_invaderAI(Creature* creature) : violet_hold_trashAI(creature) @@ -833,12 +912,11 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; - if (me->GetEntry() == CREATURE_AZURE_INVADER_1) + if (me->GetEntry() == NPC_AZURE_INVADER_1) { if (uiCleaveTimer <= diff) { @@ -848,14 +926,13 @@ public: if (uiImpaleTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_IMPALE); uiImpaleTimer = 4000; } else uiImpaleTimer -= diff; } - if (me->GetEntry() == CREATURE_AZURE_INVADER_2) + if (me->GetEntry() == NPC_AZURE_INVADER_2) { if (uiBrutalStrikeTimer <= diff) { @@ -876,6 +953,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_invaderAI>(creature); + } }; class npc_azure_binder : public CreatureScript @@ -883,11 +964,6 @@ class npc_azure_binder : public CreatureScript public: npc_azure_binder() : CreatureScript("npc_azure_binder") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_binderAI>(creature); - } - struct npc_azure_binderAI : public violet_hold_trashAI { npc_azure_binderAI(Creature* creature) : violet_hold_trashAI(creature) @@ -917,12 +993,11 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; - if (me->GetEntry() == CREATURE_AZURE_BINDER_1) + if (me->GetEntry() == NPC_AZURE_BINDER_1) { if (uiArcaneExplosionTimer <= diff) { @@ -930,16 +1005,15 @@ public: uiArcaneExplosionTimer = 5000; } else uiArcaneExplosionTimer -= diff; - if (uiArcainBarrageTimer <= diff) + if (uiArcainBarrageTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) - DoCast(target, SPELL_ARCANE_BARRAGE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + DoCast(target, SPELL_ARCANE_BARRAGE); uiArcainBarrageTimer = 6000; } else uiArcainBarrageTimer -= diff; } - if (me->GetEntry() == CREATURE_AZURE_BINDER_2) + if (me->GetEntry() == NPC_AZURE_BINDER_2) { if (uiFrostNovaTimer <= diff) { @@ -949,8 +1023,7 @@ public: if (uiFrostboltTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_FROSTBOLT); uiFrostboltTimer = 6000; } else uiFrostboltTimer -= diff; @@ -960,6 +1033,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_binderAI>(creature); + } }; class npc_azure_mage_slayer : public CreatureScript @@ -967,11 +1044,6 @@ class npc_azure_mage_slayer : public CreatureScript public: npc_azure_mage_slayer() : CreatureScript("npc_azure_mage_slayer") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_mage_slayerAI>(creature); - } - struct npc_azure_mage_slayerAI : public violet_hold_trashAI { npc_azure_mage_slayerAI(Creature* creature) : violet_hold_trashAI(creature) @@ -997,12 +1069,11 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; - if (me->GetEntry() == CREATURE_AZURE_MAGE_SLAYER_1) + if (me->GetEntry() == NPC_AZURE_MAGE_SLAYER_1) { if (uiArcaneEmpowermentTimer <= diff) { @@ -1011,12 +1082,11 @@ public: } else uiArcaneEmpowermentTimer -= diff; } - if (me->GetEntry() == CREATURE_AZURE_MAGE_SLAYER_2) + if (me->GetEntry() == NPC_AZURE_MAGE_SLAYER_2) { if (uiSpellLockTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_SPELL_LOCK); uiSpellLockTimer = 9000; } else uiSpellLockTimer -= diff; @@ -1026,6 +1096,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_mage_slayerAI>(creature); + } }; class npc_azure_raider : public CreatureScript @@ -1033,11 +1107,6 @@ class npc_azure_raider : public CreatureScript public: npc_azure_raider() : CreatureScript("npc_azure_raider") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_raiderAI>(creature); - } - struct npc_azure_raiderAI : public violet_hold_trashAI { npc_azure_raiderAI(Creature* creature) : violet_hold_trashAI(creature) @@ -1063,7 +1132,6 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; @@ -1084,6 +1152,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_raiderAI>(creature); + } }; class npc_azure_stalker : public CreatureScript @@ -1114,7 +1186,6 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; @@ -1123,8 +1194,7 @@ public: { if (_tacticalBlinkTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true)) DoCast(target, SPELL_TACTICAL_BLINK); _tacticalBlinkTimer = 6000; _tacticalBlinkCast = true; @@ -1135,8 +1205,8 @@ public: { if (_backstabTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 10, true); - DoCast(target, SPELL_BACKSTAB); + if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 10, true)) + DoCast(target, SPELL_BACKSTAB); _tacticalBlinkCast = false; _backstabTimer =1300; } else _backstabTimer -= diff; @@ -1191,43 +1261,39 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; - if (me->GetEntry() == CREATURE_AZURE_SPELLBREAKER_1) + if (me->GetEntry() == NPC_AZURE_SPELLBREAKER_1) { if (uiArcaneBlastTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_ARCANE_BLAST); uiArcaneBlastTimer = 6000; } else uiArcaneBlastTimer -= diff; if (uiSlowTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_SLOW); uiSlowTimer = 5000; } else uiSlowTimer -= diff; } - if (me->GetEntry() == CREATURE_AZURE_SPELLBREAKER_2) + if (me->GetEntry() == NPC_AZURE_SPELLBREAKER_2) { if (uiChainsOfIceTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_CHAINS_OF_ICE); uiChainsOfIceTimer = 7000; } else uiChainsOfIceTimer -= diff; if (uiConeOfColdTimer <= diff) { - DoCast(SPELL_CONE_OF_COLD); + DoCast(SPELL_CONE_OF_COLD); uiConeOfColdTimer = 5000; } else uiConeOfColdTimer -= diff; } @@ -1247,11 +1313,6 @@ class npc_azure_captain : public CreatureScript public: npc_azure_captain() : CreatureScript("npc_azure_captain") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_captainAI>(creature); - } - struct npc_azure_captainAI : public violet_hold_trashAI { npc_azure_captainAI(Creature* creature) : violet_hold_trashAI(creature) @@ -1277,7 +1338,6 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; @@ -1298,6 +1358,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_captainAI>(creature); + } }; class npc_azure_sorceror : public CreatureScript @@ -1305,11 +1369,6 @@ class npc_azure_sorceror : public CreatureScript public: npc_azure_sorceror() : CreatureScript("npc_azure_sorceror") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<npc_azure_sorcerorAI>(creature); - } - struct npc_azure_sorcerorAI : public violet_hold_trashAI { npc_azure_sorcerorAI(Creature* creature) : violet_hold_trashAI(creature) @@ -1337,15 +1396,13 @@ public: void UpdateAI(uint32 diff) override { violet_hold_trashAI::UpdateAI(diff); - npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; if (uiArcaneStreamTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) DoCast(target, SPELL_ARCANE_STREAM); uiArcaneStreamTimer = urand(0, 5000)+5000; uiArcaneStreamTimerStartingValueHolder = uiArcaneStreamTimer; @@ -1360,8 +1417,12 @@ public: DoMeleeAttackIfReady(); } }; -}; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_azure_sorcerorAI>(creature); + } +}; class npc_violet_hold_arcane_sphere : public CreatureScript { @@ -1419,6 +1480,33 @@ public: } }; +class spell_crystal_activation : public SpellScriptLoader +{ +public: + spell_crystal_activation() : SpellScriptLoader("spell_crystal_activation") { } + + class spell_crystal_activation_SpellScript : public SpellScript + { + PrepareSpellScript(spell_crystal_activation_SpellScript); + + void HandleSendEvent(SpellEffIndex effIndex) + { + if (GetHitUnit()->GetEntry() == NPC_VIOLET_HOLD_GUARD) + PreventHitDefaultEffect(effIndex); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_crystal_activation_SpellScript::HandleSendEvent, EFFECT_0, SPELL_EFFECT_SEND_EVENT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_crystal_activation_SpellScript(); + } +}; + void AddSC_violet_hold() { new npc_sinclari_vh(); @@ -1434,4 +1522,5 @@ void AddSC_violet_hold() new npc_azure_saboteur(); new npc_violet_hold_arcane_sphere(); new go_activation_crystal(); + new spell_crystal_activation(); } diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.h b/src/server/scripts/Northrend/VioletHold/violet_hold.h index 404d1f493e6..e8da9576c13 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.h +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.h @@ -18,13 +18,18 @@ #ifndef DEF_VIOLET_HOLD_H #define DEF_VIOLET_HOLD_H -#define DataHeader "VIO" +#define DataHeader "VH" + +uint32 const EncounterCount = 3; enum Data { + // Main encounters DATA_1ST_BOSS_EVENT, DATA_2ND_BOSS_EVENT, - DATA_CYANIGOSA_EVENT, + DATA_CYANIGOSA, + + // Misc DATA_WAVE_COUNT, DATA_REMOVE_NPC, DATA_PORTAL_LOCATION, @@ -38,10 +43,8 @@ enum Data DATA_ACTIVATE_CRYSTAL, DATA_MAIN_EVENT_PHASE, DATA_DEFENSELESS, -}; -enum Data64 -{ + // Bosses DATA_MORAGG, DATA_EREKEM, DATA_EREKEM_GUARD_1, @@ -50,7 +53,8 @@ enum Data64 DATA_LAVANTHOR, DATA_XEVOZZ, DATA_ZURAMAT, - DATA_CYANIGOSA, + + // Cells DATA_MORAGG_CELL, DATA_EREKEM_CELL, DATA_EREKEM_LEFT_GUARD_CELL, @@ -59,6 +63,8 @@ enum Data64 DATA_LAVANTHOR_CELL, DATA_XEVOZZ_CELL, DATA_ZURAMAT_CELL, + + // Misc DATA_MAIN_DOOR, DATA_SINCLARI, DATA_TELEPORTATION_PORTAL, @@ -81,33 +87,50 @@ enum Bosses enum CreaturesIds { - CREATURE_TELEPORTATION_PORTAL = 31011, - CREATURE_PORTAL_GUARDIAN = 30660, - CREATURE_PORTAL_KEEPER = 30695, - CREATURE_XEVOZZ = 29266, - CREATURE_LAVANTHOR = 29312, - CREATURE_ICHORON = 29313, - CREATURE_ZURAMAT = 29314, - CREATURE_EREKEM = 29315, - CREATURE_EREKEM_GUARD = 29395, - CREATURE_MORAGG = 29316, - CREATURE_CYANIGOSA = 31134, - CREATURE_SINCLARI = 30658, - CREATURE_SABOTEOUR = 31079, - NPC_VIOLET_HOLD_GUARD = 30659, - NPC_DEFENSE_SYSTEM = 30837 + NPC_TELEPORTATION_PORTAL = 31011, + NPC_PORTAL_GUARDIAN = 30660, + NPC_PORTAL_KEEPER = 30695, + NPC_XEVOZZ = 29266, + NPC_LAVANTHOR = 29312, + NPC_ICHORON = 29313, + NPC_ZURAMAT = 29314, + NPC_EREKEM = 29315, + NPC_EREKEM_GUARD = 29395, + NPC_MORAGG = 29316, + NPC_CYANIGOSA = 31134, + NPC_SINCLARI = 30658, + NPC_SABOTEOUR = 31079, + NPC_VIOLET_HOLD_GUARD = 30659, + NPC_DEFENSE_SYSTEM = 30837, + NPC_VOID_SENTRY = 29364, + NPC_VOID_SENTRY_BALL = 29365 +}; + +enum GameObjectIds +{ + GO_MAIN_DOOR = 191723, + GO_XEVOZZ_DOOR = 191556, + GO_LAVANTHOR_DOOR = 191566, + GO_ICHORON_DOOR = 191722, + GO_ZURAMAT_DOOR = 191565, + GO_EREKEM_DOOR = 191564, + GO_EREKEM_GUARD_1_DOOR = 191563, + GO_EREKEM_GUARD_2_DOOR = 191562, + GO_MORAGG_DOOR = 191606, + GO_INTRO_ACTIVATION_CRYSTAL = 193615, + GO_ACTIVATION_CRYSTAL = 193611 }; enum WorldStateIds { - WORLD_STATE_VH = 3816, - WORLD_STATE_VH_PRISON_STATE = 3815, - WORLD_STATE_VH_WAVE_COUNT = 3810, + WORLD_STATE_VH = 3816, + WORLD_STATE_VH_PRISON_STATE = 3815, + WORLD_STATE_VH_WAVE_COUNT = 3810, }; enum Events { - EVENT_ACTIVATE_CRYSTAL = 20001 + EVENT_ACTIVATE_CRYSTAL = 20001 }; #endif |