aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/scripts')
-rw-r--r--src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp1
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp187
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp15
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp34
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/oculus.h11
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_erekem.cpp271
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp389
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp97
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_moragg.cpp211
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp297
-rw-r--r--src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp114
-rw-r--r--src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp34
-rw-r--r--src/server/scripts/Northrend/VioletHold/violet_hold.cpp195
-rw-r--r--src/server/scripts/Northrend/VioletHold/violet_hold.h4
-rw-r--r--src/server/scripts/Northrend/isle_of_conquest.cpp13
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp56
16 files changed, 1372 insertions, 557 deletions
diff --git a/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp b/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp
index 46e831b0f83..7bd197774bc 100644
--- a/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp
+++ b/src/server/scripts/Kalimdor/ZulFarrak/instance_zulfarrak.cpp
@@ -111,6 +111,7 @@ public:
instance_zulfarrak_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
+ GahzRillaEncounter = NOT_STARTED;
PyramidPhase = 0;
major_wave_Timer = 0;
minor_wave_Timer = 0;
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
index ad510682e15..04ea31bd1dd 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -26,14 +26,6 @@
#include "ruby_sanctum.h"
#include "Player.h"
-/* ScriptData
-SDName: ruby_sanctum
-SDAuthors: Kaelima, Warpten
-SD%Complete: 90%
-SDComment: Based on Kaelima's initial work (half of it). Corporeality handling is a pure guess, we lack info.
-SDCategory: Chamber of Aspects
-EndScriptData */
-
enum Texts
{
// Shared
@@ -87,6 +79,8 @@ enum Spells
// Living Inferno
SPELL_BLAZING_AURA = 75885,
+ SPELL_SPAWN_LIVING_EMBERS = 75880,
+ SPELL_SUMMON_LIVING_EMBER = 75881,
// Halion Controller
SPELL_COSMETIC_FIRE_PILLAR = 76006,
@@ -143,7 +137,7 @@ enum Events
EVENT_CHECK_CORPOREALITY = 14,
EVENT_SHADOW_PULSARS_SHOOT = 15,
EVENT_TRIGGER_BERSERK = 16,
- EVENT_TWILIGHT_MENDING = 17
+ EVENT_TWILIGHT_MENDING = 17,
};
enum Actions
@@ -156,7 +150,13 @@ enum Actions
ACTION_MONITOR_CORPOREALITY = 3,
// Orb Carrier
- ACTION_SHOOT = 4
+ ACTION_SHOOT = 4,
+
+ // Living Inferno
+ ACTION_SUMMON_LIVING_EMBERS = 5,
+
+ // Meteor Flame
+ ACTION_SUMMON_FLAME = 6
};
enum Phases
@@ -174,7 +174,8 @@ enum Misc
DATA_MATERIAL_DAMAGE_TAKEN = 2,
DATA_STACKS_DISPELLED = 3,
DATA_FIGHT_PHASE = 4,
- DATA_EVADE_METHOD = 5
+ DATA_EVADE_METHOD = 5,
+ DATA_SPAWNED_FLAMES = 6,
};
enum OrbCarrierSeats
@@ -703,7 +704,7 @@ class npc_halion_controller : public CreatureScript
// The IsInCombat() check is needed because that check should be false when Halion is
// not engaged, while it would return true without as UpdateVictim() checks for
// combat state.
- if (!(_events.IsInPhase(PHASE_INTRO)) && me->IsInCombat() && !UpdateVictim())
+ if (!_events.IsInPhase(PHASE_INTRO) && me->IsInCombat() && !UpdateVictim())
{
EnterEvadeMode();
return;
@@ -894,8 +895,6 @@ class npc_halion_controller : public CreatureScript
}
};
-typedef npc_halion_controller::npc_halion_controllerAI controllerAI;
-
class npc_orb_carrier : public CreatureScript
{
public:
@@ -997,7 +996,7 @@ class npc_meteor_strike_initial : public CreatureScript
if (!owner)
return;
- // Let Halion Controller count as summoner
+ // Let Controller count as summoner
if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER)))
controller->AI()->JustSummoned(me);
@@ -1007,11 +1006,13 @@ class npc_meteor_strike_initial : public CreatureScript
if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI()))
{
Position const* ownerPos = halionAI->GetMeteorStrikePosition();
+ // Adjust randomness between 0 and pi.
+ float randomAdjustment = frand(static_cast<float>(M_PI / 14), static_cast<float>(13 * M_PI / 14));
float angle[4];
angle[0] = me->GetAngle(ownerPos);
- angle[1] = me->GetAngle(ownerPos) - static_cast<float>(M_PI/2);
- angle[2] = me->GetAngle(ownerPos) - static_cast<float>(-M_PI/2);
- angle[3] = me->GetAngle(ownerPos) - static_cast<float>(M_PI);
+ angle[1] = angle[0] + randomAdjustment;
+ angle[2] = angle[0] + static_cast<float>(M_PI);
+ angle[3] = angle[2] + randomAdjustment;
_meteorList.clear();
for (uint8 i = 0; i < 4; i++)
@@ -1020,7 +1021,10 @@ class npc_meteor_strike_initial : public CreatureScript
me->SetOrientation(angle[i]);
Position newPos = me->GetNearPosition(10.0f, 0.0f); // Exact distance
if (Creature* meteor = me->SummonCreature(NPC_METEOR_STRIKE_NORTH + i, newPos, TEMPSUMMON_TIMED_DESPAWN, 30000))
+ {
+ meteor->SetOrientation(angle[i]);
_meteorList.push_back(meteor);
+ }
}
}
}
@@ -1046,11 +1050,8 @@ class npc_meteor_strike : public CreatureScript
struct npc_meteor_strikeAI : public ScriptedAI
{
npc_meteor_strikeAI(Creature* creature) : ScriptedAI(creature),
- _instance(creature->GetInstanceScript())
+ _instance(creature->GetInstanceScript()), _spawnCount(0)
{
- _range = 5.0f;
- _spawnCount = 0;
-
SetCombatMovement(false);
}
@@ -1071,34 +1072,38 @@ class npc_meteor_strike : public CreatureScript
controller->AI()->JustSummoned(me);
}
- void UpdateAI(uint32 diff) override
+ void SetData(uint32 dataType, uint32 dataCount) override
{
- if (_spawnCount > 5)
- return;
+ if (dataType == DATA_SPAWNED_FLAMES)
+ _spawnCount += dataCount;
+ }
- _events.Update(diff);
+ uint32 GetData(uint32 dataType) const override
+ {
+ if (dataType == DATA_SPAWNED_FLAMES)
+ return _spawnCount;
+ return 0;
+ }
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
if (_events.ExecuteEvent() == EVENT_SPAWN_METEOR_FLAME)
{
- Position pos = me->GetNearPosition( _range, 0.0f);
-
+ Position pos = me->GetNearPosition(5.0f, 0.0f);
if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000))
{
- if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER)))
- controller->AI()->JustSummoned(flame);
+ flame->SetOrientation(me->GetOrientation());
- flame->CastSpell(flame, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
- ++_spawnCount;
+ flame->AI()->SetGUID(GetGUID());
+ flame->AI()->DoAction(ACTION_SUMMON_FLAME);
}
- _range += 5.0f;
- _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 800);
}
}
private:
InstanceScript* _instance;
EventMap _events;
- float _range;
uint8 _spawnCount;
};
@@ -1108,6 +1113,67 @@ class npc_meteor_strike : public CreatureScript
}
};
+class npc_meteor_strike_flame : public CreatureScript
+{
+ public:
+ npc_meteor_strike_flame() : CreatureScript("npc_meteor_strike_flame") { }
+
+ struct npc_meteor_strike_flameAI : public ScriptedAI
+ {
+ npc_meteor_strike_flameAI(Creature* creature) : ScriptedAI(creature),
+ _instance(creature->GetInstanceScript())
+ {
+ SetCombatMovement(false);
+ }
+
+ void SetGUID(ObjectGuid guid, int32 id /* = 0 */) override
+ {
+ _rootOwnerGuid = guid;
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action != ACTION_SUMMON_FLAME || _rootOwnerGuid.IsEmpty())
+ return;
+
+ me->CastSpell(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true);
+
+ Creature* meteorStrike = ObjectAccessor::GetCreature(*me, _rootOwnerGuid);
+ if (!meteorStrike || meteorStrike->AI()->GetData(DATA_SPAWNED_FLAMES) > 5)
+ return;
+
+ me->SetOrientation(me->GetOrientation() + frand(static_cast<float>(-M_PI / 16), static_cast<float>(M_PI / 16)));
+ Position pos = me->GetNearPosition(5.0f, 0.0f);
+
+ if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000))
+ {
+ flame->AI()->SetGUID(_rootOwnerGuid);
+ meteorStrike->AI()->SetData(DATA_SPAWNED_FLAMES, 1);
+ }
+ }
+
+ void IsSummonedBy(Unit* /*summoner*/) override
+ {
+ // Let Halion Controller count as summoner.
+ if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER)))
+ controller->AI()->JustSummoned(me);
+ }
+
+ void UpdateAI(uint32 diff) override { }
+ void EnterEvadeMode() override { }
+
+ private:
+ InstanceScript* _instance;
+ EventMap _events;
+ ObjectGuid _rootOwnerGuid = ObjectGuid::Empty;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetRubySanctumAI<npc_meteor_strike_flameAI>(creature);
+ }
+};
+
class npc_combustion_consumption : public CreatureScript
{
public:
@@ -1120,26 +1186,23 @@ class npc_combustion_consumption : public CreatureScript
{
SetCombatMovement(false);
- switch (me->GetEntry())
+ switch (creature->GetEntry())
{
case NPC_COMBUSTION:
_explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION;
_damageSpell = SPELL_COMBUSTION_DAMAGE_AURA;
- me->SetPhaseMask(0x01, true);
+ creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x01, true);
break;
case NPC_CONSUMPTION:
_explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION;
_damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA;
- me->SetPhaseMask(0x20, true);
+ creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x20, true);
break;
default: // Should never happen
_explosionSpell = 0;
_damageSpell = 0;
break;
}
-
- if (IsHeroic())
- me->SetPhaseMask(0x01 | 0x20, true);
}
void IsSummonedBy(Unit* summoner) override
@@ -1161,7 +1224,7 @@ class npc_combustion_consumption : public CreatureScript
me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount, me);
DoCast(me, _damageSpell);
- int32 damage = 1200 + (stackAmount * 1290); // Needs more researches.
+ int32 damage = 1200 + (stackAmount * 1290); // Needs more research.
summoner->CastCustomSpell(_explosionSpell, SPELLVALUE_BASE_POINT0, damage, summoner);
}
@@ -1194,6 +1257,10 @@ class npc_living_inferno : public CreatureScript
me->SetInCombatWithZone();
me->CastSpell(me, SPELL_BLAZING_AURA, true);
+ // SMSG_SPELL_GO for the living ember stuff isn't even sent to the client - Blizzard on drugs.
+ if (me->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC)
+ me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true);
+
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER)))
controller->AI()->JustSummoned(me);
@@ -1211,7 +1278,6 @@ class npc_living_inferno : public CreatureScript
}
};
-//! Need sniff data
class npc_living_ember : public CreatureScript
{
public:
@@ -1739,12 +1805,46 @@ class spell_halion_summon_exit_portals : public SpellScriptLoader
}
};
+class spell_halion_spawn_living_embers : public SpellScriptLoader
+{
+ public:
+ spell_halion_spawn_living_embers() : SpellScriptLoader("spell_halion_spawn_living_embers") { }
+
+ class spell_halion_spawn_living_embers_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_halion_spawn_living_embers_SpellScript);
+
+ void SelectMeteorFlames(std::list<WorldObject*>& unitList)
+ {
+ if (!unitList.empty())
+ Trinity::Containers::RandomResizeList(unitList, 10);
+ }
+
+ void HandleScript(SpellEffIndex /* effIndex */)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_LIVING_EMBER, true);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_spawn_living_embers_SpellScript::SelectMeteorFlames, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_halion_spawn_living_embers_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_halion_spawn_living_embers_SpellScript();
+ }
+};
+
void AddSC_boss_halion()
{
new boss_halion();
new boss_twilight_halion();
new npc_halion_controller();
+ new npc_meteor_strike_flame();
new npc_meteor_strike_initial();
new npc_meteor_strike();
new npc_combustion_consumption();
@@ -1766,4 +1866,5 @@ void AddSC_boss_halion()
new spell_halion_twilight_phasing();
new spell_halion_twilight_cutter();
new spell_halion_clear_debuffs();
+ new spell_halion_spawn_living_embers();
}
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
index c3f5c75e059..737a5d5c982 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
@@ -229,6 +229,21 @@ class instance_oculus : public InstanceMapScript
return true;
}
+ uint32 GetData(uint32 type) const override
+ {
+ if (type == DATA_CONSTRUCTS)
+ {
+ if (CentrifugueConstructCounter == 0)
+ return KILL_NO_CONSTRUCT;
+ else if (CentrifugueConstructCounter == 1)
+ return KILL_ONE_CONSTRUCT;
+ else if (CentrifugueConstructCounter > 1)
+ return KILL_MORE_CONSTRUCT;
+ }
+
+ return KILL_NO_CONSTRUCT;
+ }
+
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
index 450f97cb9b7..3ab9814b5b5 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp
@@ -20,6 +20,7 @@
#include "ScriptedGossip.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
+#include "SpellInfo.h"
#include "CombatAI.h"
#include "Player.h"
#include "Vehicle.h"
@@ -76,6 +77,11 @@ enum Drakes
SPELL_EMERALD_TOUCH_THE_NIGHTMARE = 50341, // (60 yds) - Instant - Consumes 30% of the caster's max health to inflict 25, 000 nature damage to an enemy dragon and reduce the damage it deals by 25% for 30 sec.
// you do not have access to until you kill the Mage-Lord Urom
SPELL_EMERALD_DREAM_FUNNEL = 50344, // (60 yds) - Channeled - Transfers 5% of the caster's max health to a friendly drake every second for 10 seconds as long as the caster channels.
+/*
+ * All Drakes
+ * GPS System
+ */
+ SPELL_GPS = 53389,
// Misc
POINT_LAND = 2,
@@ -101,7 +107,13 @@ enum Says
WHISPER_DRAKES_WELCOME = 1,
WHISPER_DRAKES_ABILITIES = 2,
WHISPER_DRAKES_SPECIAL = 3,
- WHISPER_DRAKES_LOWHEALTH = 4
+ WHISPER_DRAKES_LOWHEALTH = 4,
+ WHISPER_GPS_10_CONSTRUCTS = 5,
+ WHISPER_GPS_1_CONSTRUCT = 6,
+ WHISPER_GPS_VAROS = 7,
+ WHISPER_GPS_UROM = 8,
+ WHISPER_GPS_EREGOS = 9,
+ WHISPER_GPS_END = 10
};
class npc_verdisa_beglaristrasz_eternos : public CreatureScript
@@ -250,6 +262,26 @@ class npc_ruby_emerald_amber_drake : public CreatureScript
Initialize();
}
+ void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override
+ {
+ if (Unit* creator = ObjectAccessor::GetUnit(*me, me->GetCreatorGUID()))
+ if (spell->Id == SPELL_GPS)
+ {
+ if (_instance->GetBossState(DATA_EREGOS) == DONE)
+ Talk(WHISPER_GPS_END, creator);
+ else if (_instance->GetBossState(DATA_UROM) == DONE)
+ Talk(WHISPER_GPS_EREGOS, creator);
+ else if (_instance->GetBossState(DATA_VAROS) == DONE)
+ Talk(WHISPER_GPS_UROM, creator);
+ else if (_instance->GetData(DATA_CONSTRUCTS) == KILL_NO_CONSTRUCT)
+ Talk(WHISPER_GPS_VAROS, creator);
+ else if (_instance->GetData(DATA_CONSTRUCTS) == KILL_ONE_CONSTRUCT)
+ Talk(WHISPER_GPS_1_CONSTRUCT, creator);
+ else if (_instance->GetData(DATA_CONSTRUCTS) == KILL_MORE_CONSTRUCT)
+ Talk(WHISPER_GPS_10_CONSTRUCTS, creator);
+ }
+ }
+
void IsSummonedBy(Unit* summoner) override
{
if (_instance->GetBossState(DATA_EREGOS) == IN_PROGRESS)
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h
index fd46f0a6bcc..08fc15c5752 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h
+++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h
@@ -29,7 +29,9 @@ enum DataTypes
DATA_DRAKOS = 0,
DATA_VAROS = 1,
DATA_UROM = 2,
- DATA_EREGOS = 3
+ DATA_EREGOS = 3,
+ // GPS System
+ DATA_CONSTRUCTS = 4
};
enum CreatureIds
@@ -91,6 +93,13 @@ enum InstanceEvents
EVENT_EREGOS_INTRO
};
+enum ConstructKillState
+{
+ KILL_NO_CONSTRUCT = 0,
+ KILL_ONE_CONSTRUCT = 1,
+ KILL_MORE_CONSTRUCT = 2
+};
+
enum Misc
{
POINT_MOVE_OUT = 1
diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
index 5c8d4b8691a..1f9fc6d7981 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp
@@ -27,7 +27,8 @@ enum Spells
SPELL_EARTH_SHIELD = 54479,
SPELL_EARTH_SHOCK = 54511,
SPELL_LIGHTNING_BOLT = 53044,
- SPELL_STORMSTRIKE = 51876
+ SPELL_STORMSTRIKE = 51876,
+ SPELL_WINDFURY = 54493
};
enum Yells
@@ -40,11 +41,27 @@ 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:
boss_erekem() : CreatureScript("boss_erekem") { }
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_erekemAI>(creature);
+ }
+
struct boss_erekemAI : public ScriptedAI
{
boss_erekemAI(Creature* creature) : ScriptedAI(creature)
@@ -55,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->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
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
@@ -104,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);
}
@@ -133,68 +161,13 @@ public:
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- //spam stormstrike in hc mode if spawns are dead
- if (IsHeroic())
- {
- 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())
- DoCastVictim(SPELL_STORMSTRIKE);
- }
- }
- }
-
- if (uiEarthShieldTimer <= diff)
- {
- DoCast(me, SPELL_EARTH_SHIELD);
- uiEarthShieldTimer = 20000;
- } else uiEarthShieldTimer -= diff;
-
- if (uiChainHealTimer <= diff)
- {
- if (ObjectGuid TargetGUID = GetChainHealTargetGUID())
- {
- 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;
- }
- } 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;
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_NPC);
- 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();
+ events.ScheduleEvent(EVENT_EARTH_SHIELD, 20000);
+ events.ScheduleEvent(EVENT_BLOODLUST, 15000);
+ events.ScheduleEvent(EVENT_CHAIN_HEAL, 10000);
+ events.ScheduleEvent(EVENT_LIGHTNING_BOLT, 2000);
}
void JustDied(Unit* /*killer*/) override
@@ -219,27 +192,118 @@ public:
Talk(SAY_SLAY);
}
- ObjectGuid GetChainHealTargetGUID()
+ void UpdateAI(uint32 diff) override
{
- if (HealthBelowPct(85))
- return me->GetGUID();
+ if (!UpdateVictim())
+ return;
- Creature* pGuard1 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_1));
- if (pGuard1 && pGuard1->IsAlive() && !pGuard1->HealthAbovePct(75))
- return pGuard1->GetGUID();
+ 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));
+ }
+ }
+ }
- Creature* pGuard2 = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EREKEM_GUARD_2));
- if (pGuard2 && pGuard2->IsAlive() && !pGuard2->HealthAbovePct(75))
- return pGuard2->GetGUID();
+ events.Update(diff);
- return ObjectGuid::Empty;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ if (breakBondsCd <= 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())
+ {
+ 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
+ breakBondsCd -= diff;
+
+ switch (uint32 eventId = events.ExecuteEvent())
+ {
+ 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;
+ }
+
+ DoMeleeAttackIfReady();
}
- };
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_erekemAI>(creature);
- }
+ private:
+ EventMap events;
+ InstanceScript* instance;
+ uint8 phase;
+ int32 breakBondsCd;
+ };
};
enum GuardSpells
@@ -254,6 +318,11 @@ class npc_erekem_guard : public CreatureScript
public:
npc_erekem_guard() : CreatureScript("npc_erekem_guard") { }
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_erekem_guardAI>(creature);
+ }
+
struct npc_erekem_guardAI : public ScriptedAI
{
npc_erekem_guardAI(Creature* creature) : ScriptedAI(creature)
@@ -278,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
@@ -322,11 +394,6 @@ public:
} else uiGushingWoundTimer -= diff;
}
};
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<npc_erekem_guardAI>(creature);
- }
};
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 9be73febd52..137f63a381d 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp
@@ -27,12 +27,16 @@ enum Spells
SPELL_WATER_BLAST = 54237,
SPELL_WATER_BOLT_VOLLEY = 54241,
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_ICHOR_GLOBULE = 29321,
+ NPC_ICHORON_SUMMON_TARGET = 29326
};
enum Yells
@@ -48,26 +52,48 @@ 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 const 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:
@@ -78,33 +104,24 @@ public:
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();
@@ -131,6 +148,9 @@ public:
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_WATER_BOLT_VOLLEY, urand(10000, 15000));
+ events.ScheduleEvent(EVENT_WATER_BLAST, urand(6000, 9000));
}
void AttackStart(Unit* who) override
@@ -155,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;
}
}
@@ -180,6 +196,7 @@ public:
void DoExplodeCompleted()
{
bIsExploded = false;
+ bIsDrained = false;
if (!HealthBelowPct(25))
{
@@ -199,74 +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); // wrong target
- 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
@@ -295,22 +262,23 @@ public:
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
@@ -318,6 +286,145 @@ public:
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ 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
@@ -341,48 +448,68 @@ 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
{
+ 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* ichoron = instance->GetCreature(DATA_ICHORON))
- {
- if (me->IsWithinDist(ichoron, 2.0f, false))
- {
- if (ichoron->AI())
- ichoron->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
{
- DoCast(me, SPELL_SPLASH);
- if (Creature* ichoron = instance->GetCreature(DATA_ICHORON))
- if (ichoron->AI())
- ichoron->AI()->DoAction(ACTION_WATER_ELEMENT_KILLED);
+ int32 actualHp = me->GetHealth();
+ actualHp -= damage;
+
+ if (actualHp <= 0)
+ DoCast(SPELL_SPLASH);
}
+
+ void UpdateAI(uint32 diff) override
+ {
+ 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
diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
index 5040dccfa36..8dc0e32fb31 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp
@@ -27,41 +27,39 @@ enum Spells
SPELL_LAVA_BURN = 54249
};
+enum LavanthorEvents
+{
+ EVENT_CAUTERIZING_FLAMES = 1,
+ EVENT_FIREBOLT,
+ EVENT_FLAME_BREATH,
+ EVENT_LAVA_BURN
+};
+
class boss_lavanthor : public CreatureScript
{
public:
boss_lavanthor() : CreatureScript("boss_lavanthor") { }
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_lavanthorAI>(creature);
+ }
+
struct boss_lavanthorAI : public ScriptedAI
{
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->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, NOT_STARTED);
+
+ events.Reset();
}
void EnterCombat(Unit* /*who*/) override
@@ -72,11 +70,16 @@ public:
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
@@ -93,39 +96,38 @@ public:
}
}
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
- if (uiFireboltTimer <= diff)
- {
- DoCastVictim(SPELL_FIREBOLT);
- uiFireboltTimer = urand(5000, 13000);
- } else uiFireboltTimer -= diff;
-
- if (uiFlameBreathTimer <= diff)
- {
- DoCastVictim(SPELL_FLAME_BREATH);
- uiFlameBreathTimer = urand(10000, 15000);
- } else uiFlameBreathTimer -= diff;
+ events.Update(diff);
- if (uiLavaBurnTimer <= diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50.0f, true))
- DoCast(target, SPELL_LAVA_BURN);
- uiLavaBurnTimer = urand(15000, 23000);
- } else uiLavaBurnTimer -= diff;
+ 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();
@@ -144,12 +146,11 @@ public:
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
- };
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetInstanceAI<boss_lavanthorAI>(creature);
- }
+ 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 1c98806b127..f9e223d3bab 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp
@@ -17,6 +17,8 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
#include "violet_hold.h"
enum Spells
@@ -24,7 +26,18 @@ enum Spells
SPELL_CORROSIVE_SALIVA = 54527,
SPELL_OPTIC_LINK = 54396,
SPELL_RAY_OF_PAIN = 54438, // NYI missing spelldifficulty
- SPELL_RAY_OF_SUFFERING = 54442 // 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
@@ -36,24 +49,12 @@ public:
{
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->SetBossState(DATA_1ST_BOSS_EVENT, NOT_STARTED);
@@ -74,6 +75,13 @@ public:
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
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
@@ -90,25 +98,30 @@ public:
}
}
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
void UpdateAI(uint32 diff) override
{
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 (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- if (uiCorrosiveSalivaTimer <= diff)
+ 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();
}
@@ -126,6 +139,10 @@ public:
instance->SetData(DATA_WAVE_COUNT, 13);
}
}
+
+ private:
+ EventMap events;
+ InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -134,7 +151,149 @@ public:
}
};
+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()->Effects[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()->Effects[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 d1efcb8ca7a..4fb7646558d 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp
@@ -17,29 +17,33 @@
#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_BUFFET = 54226,
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
{
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
@@ -53,6 +57,22 @@ 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:
@@ -62,23 +82,9 @@ public:
{
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)
@@ -86,14 +92,15 @@ public:
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
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;
@@ -108,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
@@ -144,45 +147,10 @@ public:
instance->SetBossState(DATA_1ST_BOSS_EVENT, IN_PROGRESS);
else if (instance->GetData(DATA_WAVE_COUNT) == 12)
instance->SetBossState(DATA_2ND_BOSS_EVENT, IN_PROGRESS);
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override { }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if (uiArcaneBarrageVolley_Timer < diff)
- {
- DoCast(me, SPELL_ARCANE_BARRAGE_VOLLEY);
- uiArcaneBarrageVolley_Timer = urand(20000, 22000);
- }
- else uiArcaneBarrageVolley_Timer -= diff;
- if (uiArcaneBuffet_Timer)
- {
- if (uiArcaneBuffet_Timer < diff)
- {
- DoCastVictim(SPELL_ARCANE_BUFFET);
- uiArcaneBuffet_Timer = 0;
- }
- else uiArcaneBuffet_Timer -= diff;
- }
-
- if (uiSummonEtherealSphere_Timer < diff)
- {
- 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 -= diff;
-
- 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
@@ -208,6 +176,65 @@ public:
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;
+
+ 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
@@ -226,71 +253,137 @@ public:
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 DoAction(int32 action) override
+ {
+ if (action == ACTION_SUMMON)
+ DoCast(SPELL_SUMMON_PLAYERS);
}
void UpdateAI(uint32 diff) override
{
- if (!UpdateVictim())
- return;
+ 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 < diff)
+ 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 -= diff;
+ }
+
+ private:
+ InstanceScript* instance;
+ EventMap events;
+ bool arcanePower;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ethereal_sphereAI>(creature);
+ }
+};
+
+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 (uiSummonPlayers_Timer < diff)
+ 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();
+ }
+};
- uiSummonPlayers_Timer = urand(33000, 35000);
+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;
+
+ while (distance < 20.0f)
+ {
+ pos = caster->GetRandomNearPosition(60.0f);
+ distance = caster->GetDistance(pos);
}
- else uiSummonPlayers_Timer -= diff;
+
+ target.Relocate(pos);
+ }
+
+ void Register() override
+ {
+ OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_xevozz_summon_ethereal_sphere_SpellScript::HandleScript, EFFECT_0, TARGET_DEST_DB);
}
};
- CreatureAI* GetAI(Creature* creature) const override
+ SpellScript* GetSpellScript() const override
{
- return GetInstanceAI<npc_ethereal_sphereAI>(creature);
+ return new spell_xevozz_summon_ethereal_sphere_SpellScript();
}
};
@@ -298,4 +391,6 @@ 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 c29861f08a4..02e479a22f4 100644
--- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
+++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp
@@ -23,12 +23,8 @@ enum Spells
{
SPELL_SHROUD_OF_DARKNESS = 54524,
SPELL_SUMMON_VOID_SENTRY = 54369,
- SPELL_VOID_SHIFT = 54361
-};
-
-enum Creatures
-{
- NPC_VOID_SENTRY = 29364
+ SPELL_VOID_SHIFT = 54361,
+ SPELL_VOID_SHIFTED = 54343,
};
enum Yells
@@ -46,6 +42,13 @@ 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:
@@ -53,7 +56,7 @@ public:
struct boss_zuramatAI : public ScriptedAI
{
- boss_zuramatAI(Creature* creature) : ScriptedAI(creature)
+ boss_zuramatAI(Creature* creature) : ScriptedAI(creature), sentries(me)
{
Initialize();
instance = creature->GetInstanceScript();
@@ -61,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
{
@@ -82,6 +85,8 @@ public:
instance->SetData(DATA_2ND_BOSS_EVENT, NOT_STARTED);
Initialize();
+ events.Reset();
+ DespawnSentries();
}
void AttackStart(Unit* who) override
@@ -112,36 +117,17 @@ public:
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);
- }
+ 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
{
- 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
@@ -160,8 +146,12 @@ public:
void JustDied(Unit* /*killer*/) override
{
+ instance->SetData(DATA_ZURAMAT, 1);
+
Talk(SAY_DEATH);
+ DespawnSentries();
+
if (instance->GetData(DATA_WAVE_COUNT) == 6)
{
instance->SetBossState(DATA_1ST_BOSS_EVENT, DONE);
@@ -179,6 +169,44 @@ public:
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ 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
diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
index 28c56a02255..652b4815be0 100644
--- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp
@@ -145,6 +145,7 @@ public:
bCrystalActivated = false;
defenseless = true;
uiMainEventPhase = NOT_STARTED;
+ zuramatDead = false;
}
ObjectGuid uiErekemGuard[2];
@@ -178,6 +179,7 @@ public:
bool bIsDoorSpellCast;
bool bCrystalActivated;
bool defenseless;
+ bool zuramatDead;
std::list<uint8> NpcAtDoorCastingList;
@@ -199,16 +201,20 @@ public:
break;
default:
break;
+ case NPC_VOID_SENTRY:
+ if (zuramatDead)
+ {
+ creature->DespawnOrUnsummon();
+ zuramatDead = false;
+ }
+ break;
}
- /*
- BEWARE - SHIT.
if (creature->GetGUID() == uiFirstBoss || creature->GetGUID() == uiSecondBoss)
{
creature->AllLootRemovedFromCorpse();
creature->RemoveLootMode(1);
}
- */
}
void OnGameObjectCreate(GameObject* go) override
@@ -314,6 +320,9 @@ public:
uiRemoveNpc = 0; // might not have been reset after a wipe on a boss.
}
break;
+ case DATA_ZURAMAT:
+ zuramatDead = true;
+ break;
}
}
@@ -393,19 +402,23 @@ public:
if (Creature* pGuard1 = instance->GetCreature(uiErekemGuard[0]))
{
if (bForceRespawn)
+ {
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);
+ pGuard1->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
}
if (Creature* pGuard2 = instance->GetCreature(uiErekemGuard[1]))
{
if (bForceRespawn)
- pGuard2->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NON_ATTACKABLE);
+ {
+ 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);
+ pGuard2->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
}
break;
case BOSS_ICHORON:
@@ -448,6 +461,9 @@ public:
boss->Respawn();
boss->RemoveLootMode(1);
}
+ else
+ boss->GetMotionMaster()->MoveTargetedHome();
+
boss->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_NON_ATTACKABLE);
uiWaveCount = 0;
}
@@ -527,6 +543,7 @@ public:
return false;
}
+ zuramatDead = false;
return true;
}
@@ -557,6 +574,7 @@ 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]))
diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
index 8bcc80b5a84..b05da4b994c 100644
--- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
+++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp
@@ -28,6 +28,7 @@
#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
@@ -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
{
@@ -320,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);
@@ -347,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:
@@ -378,7 +386,6 @@ public:
if (Creature* pGuard = *itr)
{
pGuard->SetVisible(false);
- pGuard->SetReactState(REACT_PASSIVE);
}
}
uiTimer = 2000;
@@ -391,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;
@@ -548,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()
@@ -575,10 +632,13 @@ public:
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);
@@ -642,24 +702,39 @@ 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());
+ }
}
};
@@ -675,8 +750,23 @@ struct violet_hold_trashAI : public npc_escortAI
{
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:
@@ -691,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))
@@ -699,7 +789,7 @@ struct violet_hold_trashAI : public npc_escortAI
break;
case 2:
if (waypointId == 7)
- CreatureStartAttackDoor();
+ CreatureStartAttackDoor();
break;
case 3:
if (waypointId == 8)
@@ -1203,7 +1293,7 @@ public:
if (uiConeOfColdTimer <= diff)
{
- DoCast(SPELL_CONE_OF_COLD);
+ DoCast(SPELL_CONE_OF_COLD);
uiConeOfColdTimer = 5000;
} else uiConeOfColdTimer -= diff;
}
@@ -1334,7 +1424,6 @@ public:
}
};
-
class npc_violet_hold_arcane_sphere : public CreatureScript
{
public:
@@ -1391,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();
@@ -1406,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 275a7467d83..e8da9576c13 100644
--- a/src/server/scripts/Northrend/VioletHold/violet_hold.h
+++ b/src/server/scripts/Northrend/VioletHold/violet_hold.h
@@ -101,7 +101,9 @@ enum CreaturesIds
NPC_SINCLARI = 30658,
NPC_SABOTEOUR = 31079,
NPC_VIOLET_HOLD_GUARD = 30659,
- NPC_DEFENSE_SYSTEM = 30837
+ NPC_DEFENSE_SYSTEM = 30837,
+ NPC_VOID_SENTRY = 29364,
+ NPC_VOID_SENTRY_BALL = 29365
};
enum GameObjectIds
diff --git a/src/server/scripts/Northrend/isle_of_conquest.cpp b/src/server/scripts/Northrend/isle_of_conquest.cpp
index ba21b60f11d..f5514cc51a5 100644
--- a/src/server/scripts/Northrend/isle_of_conquest.cpp
+++ b/src/server/scripts/Northrend/isle_of_conquest.cpp
@@ -161,19 +161,6 @@ class spell_ioc_gunship_portal : public SpellScriptLoader
* Position: X: 7.305609 Y: -0.095246 Z: 34.51022 O: 0
*/
caster->TeleportTo(GetHitCreature()->GetWorldLocation(), TELE_TO_NOT_LEAVE_TRANSPORT);
- /*
- * HACK: This aura should be added by 20212 and 20213 but can't find any SMSG_SPELL_GO. Could't find their position.
- * ServerToClient: SMSG_AURA_UPDATE (0x0072)
- * [0] CasterGUID: Full: xxxxx Type: Unit Entry: 20212 Low: xxx
- * [0] Flags: None (0)
- * [0] Caster Level: 60
- * [0] Spell ID: 66656
- * [0] Charges: 0
- * [0] Effect Mask: 1
- * [0] Slot: 37
- * Guid: Full: xxxxx Type: Player2 Low: xxxxx
- */
- caster->AddAura(SPELL_PARACHUTE, caster);
}
void Register() override
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index 93e13667cb0..a1b218010aa 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -824,6 +824,60 @@ class spell_brewfest_barker_bunny : public SpellScriptLoader
}
};
+enum TorchSpells
+{
+ SPELL_TORCH_TOSSING_TRAINING = 45716,
+ SPELL_TORCH_TOSSING_PRACTICE = 46630,
+ SPELL_TORCH_TOSSING_TRAINING_SUCCESS_ALLIANCE = 45719,
+ SPELL_TORCH_TOSSING_TRAINING_SUCCESS_HORDE = 46651,
+ SPELL_BRAZIERS_HIT = 45724
+};
+
+// 45724 - Braziers Hit!
+class spell_midsummer_braziers_hit : public SpellScriptLoader
+{
+ public:
+ spell_midsummer_braziers_hit() : SpellScriptLoader("spell_midsummer_braziers_hit") { }
+
+ class spell_midsummer_braziers_hit_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_midsummer_braziers_hit_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_TORCH_TOSSING_TRAINING) || !sSpellMgr->GetSpellInfo(SPELL_TORCH_TOSSING_PRACTICE))
+ return false;
+ return true;
+ }
+
+ void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Player* player = GetTarget()->ToPlayer();
+ if (!player)
+ return;
+
+ if ((player->HasAura(SPELL_TORCH_TOSSING_TRAINING) && GetStackAmount() == 8) || (player->HasAura(SPELL_TORCH_TOSSING_PRACTICE) && GetStackAmount() == 20))
+ {
+ if (player->GetTeam() == ALLIANCE)
+ player->CastSpell(player, SPELL_TORCH_TOSSING_TRAINING_SUCCESS_ALLIANCE, true);
+ else if (player->GetTeam() == HORDE)
+ player->CastSpell(player, SPELL_TORCH_TOSSING_TRAINING_SUCCESS_HORDE, true);
+ Remove();
+ }
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_midsummer_braziers_hit_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AuraEffectHandleModes(AURA_EFFECT_HANDLE_REAPPLY));
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_midsummer_braziers_hit_AuraScript();
+ }
+};
+
void AddSC_holiday_spell_scripts()
{
// Love is in the Air
@@ -850,4 +904,6 @@ void AddSC_holiday_spell_scripts()
new spell_brewfest_relay_race_intro_force_player_to_throw();
new spell_brewfest_dismount_ram();
new spell_brewfest_barker_bunny();
+ // Midsummer Fire Festival
+ new spell_midsummer_braziers_hit();
}