aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManuel <manue.l@live.com.ar>2011-03-26 21:36:06 -0300
committerManuel <manue.l@live.com.ar>2011-03-26 21:36:06 -0300
commit21a2c56af32f006664d3e982e34b181848b49635 (patch)
tree801a21ca615c9e8e8890f914cad8460ad0c588f3 /src
parent75bf08c08144892ff6c7351d2602af2046a47db7 (diff)
Scripts/Eye of Eternity: Implemented script for Malygos encounter, please report any issue you find.
Thanks for the help to Machiavelli and Shauren. Signed-off-by: Manuel <manue.l@live.com.ar>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp3
-rwxr-xr-xsrc/server/game/Scripting/ScriptLoader.cpp4
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp1173
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h51
-rw-r--r--src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp267
5 files changed, 1377 insertions, 121 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index fad6eb8a706..eff6f5b577d 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -15242,6 +15242,9 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
sScriptMgr->OnPlayerKilledByCreature(killer, killed);
}
}
+
+ if (Vehicle* veh = pVictim->GetVehicle())
+ pVictim->ExitVehicle();
}
void Unit::SetControlled(bool apply, UnitState state)
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 1076efe82d8..9069bf401fb 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -400,6 +400,8 @@ void AddSC_boss_varos();
void AddSC_boss_eregos();
void AddSC_instance_oculus();
void AddSC_oculus();
+void AddSC_boss_malygos(); // The Nexus: Eye of Eternity
+void AddSC_instance_eye_of_eternity();
void AddSC_boss_sartharion(); //Obsidian Sanctum
void AddSC_instance_obsidian_sanctum();
void AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning
@@ -1091,6 +1093,8 @@ void AddNorthrendScripts()
AddSC_boss_eregos();
AddSC_instance_oculus();
AddSC_oculus();
+ AddSC_boss_malygos(); // The Nexus: Eye of Eternity
+ AddSC_instance_eye_of_eternity();
AddSC_boss_sartharion(); //Obsidian Sanctum
AddSC_instance_obsidian_sanctum();
AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
index fa5d138a428..6c73120c0aa 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp
@@ -17,175 +17,1120 @@
/* Script Data Start
SDName: Boss malygos
-SDAuthor: LordVanMartin
-SD%Complete:
-SDComment:
-SDCategory:
Script Data End */
+// TO-DOs:
+// Implement a better pathing for Malygos.
+// Find sniffed spawn position for chest
+// Implement a better way to disappear the gameobjects
+// Implement achievements
+// Implement scaling for player's drakes (should be done with aura 66668, it is casted - but it is not working as it should)
+// Remove hack that re-adds targets to the aggro list after they enter to a vehicle when it works as expected
+// Improve whatever can be improved :)
+
#include "ScriptPCH.h"
+#include "eye_of_eternity.h"
+#include "ScriptedEscortAI.h"
-//Spells
-#define SPELL_ARCANE_BREATH_N 56272
-#define SPELL_ARCANE_BREATH_H 60072
-#define SPELL_ARCANE_PULSE 57432
-#define SPELL_ARCANE_STORM_1 57459
-#define SPELL_ARCANE_STORM_2 61693
-#define SPELL_ARCANE_STORM_3 61694
-#define SPELL_STATIC_FIELD 57430
-#define SPELL_SURGE_OF_POWER_1 56505
-#define SPELL_SURGE_OF_POWER_2 57407
-#define SPELL_SURGE_OF_POWER_3 60936
-#define SPELL_VORTEX 56105
-
-//Dragon "mounts" spells in Phase3
-//they use Rugelike energy
-#define SPELL_DMOUNT_FLAME_SPIKE 56091 //maybe not accurate
-#define SPELL_DMOUNT_ENGULF_IN_FLAMES 61621
-#define SPELL_DMOUNT_REVIVIFY 57090
-#define SPELL_DMOUNT_LIFE_BURST 57143
-#define SPELL_DMOUNT_FLAME_SHIELD 57108
-//#define SPELL_DMOUNT_UNKNOWN XYZ //Increases your drake's flight speed by 500%.
-
-//not in db
-//Yell
-//-->Other
-#define SAY_ANTI_MAGIC_SHELL -1616000
-#define SAY_BREATH_ATTACK -1616001
-#define SAY_HIGH_DAMAGE_MODE -1616002
-#define SAY_MAGIC_BLAST -1616003
-//--> Generic Spells
-#define SAY_GENERIC_SPELL_1 -1616004
-#define SAY_GENERIC_SPELL_2 -1616005
-#define SAY_GENERIC_SPELL_3 -1616006
-#define SAY_DEATH -1616007
-//--> Prefight
-#define SAY_PREFIGHT_1 -1616008
-#define SAY_PREFIGHT_2 -1616009
-#define SAY_PREFIGHT_3 -1616010
-#define SAY_PREFIGHT_4 -1616011
-#define SAY_PREFIGHT_5 -1616012
-//--> Phase1
-#define SAY_PHASE1_AGGRO -1616013
-#define SAY_PHASE1_END -1616014
-#define SAY_PHASE1_SLAY_1 -1616015
-#define SAY_PHASE1_SLAY_2 -1616016
-#define SAY_PHASE1_SLAY_3 -1616017
-
-//--> Phase2 at 50% HP,
-
-/*Malygos himself is not targetable during this phase, it will end when the adds he spawns are all killed. However, he does continue to play a part in the encounter.
-During this phase he drops anti-magic zones onto the ground the raid MUST stand inside of, it reduces magical damage taken by 50%. They shrink over time, so it's important that your raid moves to each new one he drops.
-Throughout the phase, he will deep breath doing ~4k damage per second, unless you are standing inside of the anti-magic zone.
-The way the fight works during this phase is there are NPCs riding around on disks in the room. There are two types of mobs, Lords and Scions.
-The Lords will move down onto the group, and need to be tanked (They will one-shot a non-tank). After they die, they drop a disk that a raid member can mount onto, which allows them to fly, to attack the Scions that do not come down to the ground.
-It is recommended to let melee take the first disks, then ranged. As those mobs die, they also drop disks, which allows the rest of your dps to get onto them.
-The Scions will continually cast Arcane Blast on random targets on the floor, which is mitigated by the anti-magic zones. While mounted on a disk, you will not take damage.
-After all of the NPCs riding on the disks die, the players on the disks need to dismount as Phase 3 is about to begin.*/
-
-//not in db
-#define SAY_PHASE2_AGGRO -1616018
-#define SAY_PHASE2_END -1616019
-#define SAY_PHASE2_SLAY_1 -1616020
-#define SAY_PHASE2_SLAY_2 -1616021
-#define SAY_PHASE2_SLAY_3 -1616022
-//--> Phase3 Malygos destroys the floor, encounter continues on dragon "mounts"
-#define SAY_PHASE3_INTRO -1616023
-#define SAY_PHASE3_AGGRO -1616024
-#define SAY_PHASE3_SLAY_1 -1616025
-#define SAY_PHASE3_SLAY_2 -1616026
-#define SAY_PHASE3_SLAY_3 -1616027
-#define SAY_PHASE3_BIG_ATTACK -1616028
-
-enum
+// not implemented
+enum Achievements
{
ACHIEV_TIMED_START_EVENT = 20387,
};
+enum Events
+{
+ // =========== PHASE ONE ===============
+ EVENT_ARCANE_BREATH = 1,
+ EVENT_ARCANE_STORM = 2,
+ EVENT_VORTEX = 3,
+ EVENT_POWER_SPARKS = 4,
+
+ // =========== PHASE TWO ===============
+ EVENT_SURGE_POWER = 5, // wowhead is wrong, Surge of Power is casted instead of Arcane Pulse (source sniffs!)
+ EVENT_SUMMON_ARCANE = 6,
+
+ // =========== PHASE TWO ===============
+ EVENT_SURGE_POWER_PHASE_3 = 7,
+ EVENT_STATIC_FIELD = 8,
+
+ // =============== YELLS ===============
+ EVENT_YELL_0 = 9,
+ EVENT_YELL_1 = 10,
+ EVENT_YELL_2 = 11,
+ EVENT_YELL_3 = 12,
+ EVENT_YELL_4 = 13,
+};
+
+enum Phases
+{
+ PHASE_ONE = 1,
+ PHASE_TWO = 2,
+ PHASE_THREE = 3
+};
+
+enum Spells
+{
+ SPELL_ARCANE_BREATH = 56272,
+ SPELL_ARCANE_STORM = 57459,
+ SPELL_BERSEKER = 60670,
+
+ SPELL_VORTEX_1 = 56237, // seems that frezze object animation
+ SPELL_VORTEX_2 = 55873, // visual effect
+ SPELL_VORTEX_3 = 56105, // this spell must handle all the script - casted by the boss and to himself
+ //SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle - defined in eye_of_eternity.h
+ //SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle - defined in eye_of_eternity.h
+ SPELL_VORTEX_6 = 73040, // teleport - (casted to all raid) | caster 30090 | target player
+
+ SPELL_PORTAL_VISUAL_CLOSED = 55949,
+ SPELL_SUMMON_POWER_PARK = 56142,
+ SPELL_POWER_SPARK_DEATH = 55852,
+ SPELL_POWER_SPARK_MALYGOS = 56152,
+
+ SPELL_SURGE_POWER = 56505, // used in phase 2
+ SPELL_SUMMON_ARCANE_BOMB = 56429,
+ SPELL_ARCANE_OVERLOAD = 56432,
+ SPELL_SUMMOM_RED_DRAGON = 56070,
+ SPELL_SURGE_POWER_PHASE_3 = 57407,
+ SPELL_STATIC_FIELD = 57430
+};
+
+enum Movements
+{
+ MOVE_VORTEX = 1,
+ MOVE_PHASE_TWO,
+ MOVE_DEEP_BREATH_ROTATION,
+ MOVE_INIT_PHASE_ONE,
+ MOVE_CENTER_PLATFORM
+};
+
+enum Seats
+{
+ SEAT_0 = 0,
+};
+
+enum Factions
+{
+ FACTION_FRIENDLY = 35,
+ FACTION_HOSTILE = 14
+};
+
+enum Actions
+{
+ ACTION_HOVER_DISK_START_WP_1,
+ ACTION_HOVER_DISK_START_WP_2
+};
+
+enum MalygosEvents
+{
+ DATA_SUMMON_DEATHS, // phase 2
+ DATA_PHASE
+};
+
+#define TEN_MINUTES 600000
+
+enum MalygosSays
+{
+ SAY_AGGRO_P_ONE,
+ SAY_KILLED_PLAYER_P_ONE,
+ SAY_END_P_ONE,
+ SAY_AGGRO_P_TWO,
+ SAY_ANTI_MAGIC_SHELL, // not sure when execute it
+ SAY_MAGIC_BLAST, // not sure when execute it
+ SAY_KILLED_PLAYER_P_TWO,
+ SAY_END_P_TWO,
+ SAY_INTRO_P_THREE,
+ SAY_AGGRO_P_THREE,
+ SAY_SURGE_POWER, // not sure when execute it
+ SAY_BUFF_SPARK,
+ SAY_KILLED_PLAYER_P_THREE,
+ SAY_SPELL_CASTING_P_THREE,
+ SAY_DEATH
+};
+
+#define MAX_HOVER_DISK_WAYPOINTS 18
+
+// Sniffed data
+const Position HoverDiskWaypoints[MAX_HOVER_DISK_WAYPOINTS] =
+{
+ {782.9821f,1296.652f,282.1114f},
+ {779.5459f,1287.228f,282.1393f},
+ {773.0028f,1279.52f,282.4164f},
+ {764.3626f,1274.476f,282.4731f},
+ {754.3961f,1272.639f,282.4171f},
+ {744.4422f,1274.412f,282.222f},
+ {735.575f,1279.742f,281.9674f},
+ {729.2788f,1287.187f,281.9943f},
+ {726.1191f,1296.688f,282.2997f},
+ {725.9396f,1306.531f,282.2448f},
+ {729.3045f,1316.122f,281.9108f},
+ {735.8322f,1323.633f,282.1887f},
+ {744.4616f,1328.999f,281.9948f},
+ {754.4739f,1330.666f,282.049f},
+ {764.074f,1329.053f,281.9949f},
+ {772.8409f,1323.951f,282.077f},
+ {779.5085f,1316.412f,281.9145f},
+ {782.8365f,1306.778f,282.3035f},
+};
+
+#define GROUND_Z 268
+
+// Source: Sniffs
+#define MALYGOS_MAX_WAYPOINTS 16
+const Position MalygosPhaseTwoWaypoints[MALYGOS_MAX_WAYPOINTS] =
+{
+ {812.7299f,1391.672f,283.2763f},
+ {848.2912f,1358.61f,283.2763f},
+ {853.9227f,1307.911f,283.2763f},
+ {847.1437f,1265.538f,283.2763f},
+ {839.9229f,1245.245f,283.2763f},
+ {827.3463f,1221.818f,283.2763f},
+ {803.2727f,1203.851f,283.2763f},
+ {772.9372f,1197.981f,283.2763f},
+ {732.1138f,1200.647f,283.2763f},
+ {693.8761f,1217.995f,283.2763f},
+ {664.5038f,1256.539f,283.2763f},
+ {650.1497f,1303.485f,283.2763f},
+ {662.9109f,1350.291f,283.2763f},
+ {677.6391f,1377.607f,283.2763f},
+ {704.8198f,1401.162f,283.2763f},
+ {755.2642f,1417.1f,283.2763f},
+};
+
+#define MAX_SUMMONS_PHASE_TWO 4
+
+#define MAX_MALYGOS_POS 2
+const Position MalygosPositions[MAX_MALYGOS_POS] =
+{
+ {754.544f,1301.71f,320.0f},
+ {754.39f, 1301.27f, 292.91f}
+};
+
class boss_malygos : public CreatureScript
{
public:
- boss_malygos() : CreatureScript("boss_malygos") { }
+ boss_malygos() : CreatureScript("boss_malygos") {}
- CreatureAI* GetAI(Creature* pCreature) const
+ CreatureAI* GetAI(Creature* creature) const
{
- return new boss_malygosAI (pCreature);
+ return new boss_malygosAI(creature);
}
- struct boss_malygosAI : public ScriptedAI
+ struct boss_malygosAI : public BossAI
{
- boss_malygosAI(Creature *c) : ScriptedAI(c)
+ boss_malygosAI(Creature* creature) : BossAI(creature, DATA_MALYGOS_EVENT)
{
- instance = me->GetInstanceScript();
+ // If we enter in combat when MovePoint generator is active, it overrwrites our homeposition
+ homePosition = creature->GetHomePosition();
}
- InstanceScript *instance;
+ void Reset()
+ {
- uint32 phase;
- uint32 enrage;
+ _Reset();
- void Reset()
+ bersekerTimer = 0;
+ currentPos = 0;
+
+ SetPhase(PHASE_ONE,true);
+
+ delayedMovementTimer = 8000;
+ delayedMovement = false;
+
+ summonDeaths = 0;
+
+ me->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_SELECTABLE);
+
+ cannotMove = true;
+ }
+
+ uint32 GetData(uint32 data)
{
- phase = 1;
- enrage = 615000; //Source Deadly Boss Mod
+ if (data == DATA_SUMMON_DEATHS)
+ return summonDeaths;
+ else if (data == DATA_PHASE)
+ return phase;
+
+ return 0;
+ }
+
+ void SetData(uint32 data, uint32 value)
+ {
+ if (data == DATA_SUMMON_DEATHS && phase == PHASE_TWO)
+ {
+ summonDeaths = value;
+
+ if (summonDeaths >= MAX_SUMMONS_PHASE_TWO)
+ StartPhaseThree();
+ }
+ }
+
+ void EnterEvadeMode()
+ {
+ me->SetHomePosition(homePosition);
+
+ me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+
+ BossAI::EnterEvadeMode();
if (instance)
- instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
+ instance->SetBossState(DATA_MALYGOS_EVENT, FAIL);
+ }
+
+ void SetPhase(uint8 _phase, bool setEvents = false)
+ {
+ events.Reset();
+
+ events.SetPhase(_phase);
+ phase = _phase;
+
+ if (setEvents)
+ SetPhaseEvents(_phase);
+ }
+
+ void StartPhaseThree()
+ {
+ if (!instance)
+ return;
+
+ SetPhase(PHASE_THREE,true);
+
+ // this despawns Hover Disks
+ summons.DespawnAll();
+ // players that used Hover Disk are no in the aggro list
+ me->SetInCombatWithZone();
+ std::list<HostileReference*> &m_threatlist = me->getThreatManager().getThreatList();
+ for (std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
+ {
+ if (Unit* target = (*itr)->getTarget())
+ {
+ if (target->GetTypeId() != TYPEID_PLAYER)
+ continue;
+
+ // The rest is handled in the AI of the vehicle.
+ target->CastSpell(target,SPELL_SUMMOM_RED_DRAGON,true);
+ }
+ }
+
+ if (GameObject* go = GameObject::GetGameObject(*me,instance->GetData64(DATA_PLATFORM)))
+ go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); // In sniffs it has this flag, but i don't know how is applied.
+
+ // pos sniffed
+ me->GetMotionMaster()->MoveIdle();
+ me->GetMotionMaster()->MovePoint(MOVE_CENTER_PLATFORM,MalygosPositions[0].GetPositionX(),MalygosPositions[0].GetPositionY(),MalygosPositions[0].GetPositionZ());
+ }
+
+ void SetPhaseEvents(uint8 _phase)
+ {
+ switch (_phase)
+ {
+ case PHASE_ONE:
+ events.ScheduleEvent(EVENT_ARCANE_BREATH,urand(15,20)*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_ARCANE_STORM,urand(5,10)*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_VORTEX,urand(30,40)*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_POWER_SPARKS,urand(30,35)*IN_MILLISECONDS,0,_phase);
+ break;
+ case PHASE_TWO:
+ events.ScheduleEvent(EVENT_YELL_0,0,0,_phase);
+ events.ScheduleEvent(EVENT_YELL_1,24*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_SURGE_POWER,urand(60,70)*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_SUMMON_ARCANE,urand(2,5)*IN_MILLISECONDS,0,_phase);
+ break;
+ case PHASE_THREE:
+ events.ScheduleEvent(EVENT_YELL_2,0,0,_phase);
+ events.ScheduleEvent(EVENT_YELL_3,8*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_YELL_4,16*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_SURGE_POWER_PHASE_3,(7,16)*IN_MILLISECONDS,0,_phase);
+ events.ScheduleEvent(EVENT_STATIC_FIELD,(20,30)*IN_MILLISECONDS,0,_phase);
+ break;
+ default:
+ break;
+ }
}
void EnterCombat(Unit* /*who*/)
{
- if (phase == 1)
+ _EnterCombat();
+
+ me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+ me->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_SELECTABLE);
+
+ Talk(SAY_AGGRO_P_ONE);
+
+ DoCast(SPELL_BERSEKER);
+ }
+
+ void KilledUnit(Unit* who)
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ switch (phase)
+ {
+ case PHASE_ONE:
+ Talk(SAY_KILLED_PLAYER_P_ONE);
+ break;
+ case PHASE_TWO:
+ Talk(SAY_KILLED_PLAYER_P_TWO);
+ break;
+ case PHASE_THREE:
+ Talk(SAY_KILLED_PLAYER_P_THREE);
+ break;
+ }
+ }
+
+ void SpellHit(Unit* caster, const SpellEntry* spell)
+ {
+ if (spell->Id == SPELL_POWER_SPARK_MALYGOS)
+ {
+ if (Creature* creature = caster->ToCreature())
+ creature->DespawnOrUnsummon();
+
+ Talk(SAY_BUFF_SPARK);
+ }
+ }
+
+ void MoveInLineOfSight(Unit* who)
+ {
+ if (!me->isInCombat())
+ return;
+
+ if (who->GetEntry() == NPC_POWER_SPARK)
{
- DoScriptText(SAY_PHASE1_AGGRO, me);
- if (instance)
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
+ // not sure about the distance | I think it is better check this here than in the UpdateAI function...
+ if (who->GetDistance(me) <= 2.5f)
+ who->CastSpell(me, SPELL_POWER_SPARK_MALYGOS, true);
+
}
+ }
+
+ void PrepareForVortex()
+ {
+ me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+
+ me->GetMotionMaster()->MovementExpired();
+ me->GetMotionMaster()->MovePoint(MOVE_VORTEX,MalygosPositions[1].GetPositionX(), MalygosPositions[1].GetPositionY(), MalygosPositions[1].GetPositionZ());
+ // continues in MovementInform function.
+ }
+
+ void ExecuteVortex()
+ {
+ DoCast(me,SPELL_VORTEX_1,true);
+ DoCast(me,SPELL_VORTEX_2,true);
- if (phase == 2)
- DoScriptText(SAY_PHASE1_AGGRO, me);
- if (phase == 3)
- DoScriptText(SAY_PHASE1_AGGRO, me);
+ // the vortex execution continues in the dummy effect of this spell (see its script)
+ DoCast(me,SPELL_VORTEX_3,true);
}
- void UpdateAI(const uint32 /*diff*/)
+ void MovementInform(uint32 type, uint32 id)
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ switch (id)
+ {
+ case MOVE_VORTEX:
+ me->GetMotionMaster()->MoveIdle();
+ ExecuteVortex();
+ break;
+ case MOVE_DEEP_BREATH_ROTATION:
+ currentPos = currentPos == MALYGOS_MAX_WAYPOINTS - 1 ? 0 : currentPos+1;
+ me->GetMotionMaster()->MovementExpired();
+ me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION,MalygosPhaseTwoWaypoints[currentPos]);
+ break;
+ case MOVE_INIT_PHASE_ONE:
+ me->SetInCombatWithZone();
+ break;
+ case MOVE_CENTER_PLATFORM:
+ cannotMove = false;
+ // malygos will move into center of platform and then he does not chase dragons, he just turns to his current target.
+ me->GetMotionMaster()->MoveIdle();
+ break;
+ }
+ }
+
+ void StartPhaseTwo()
+ {
+ SetPhase(PHASE_TWO,true);
+
+ me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+
+ me->GetMotionMaster()->MoveIdle();
+ me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION,MalygosPhaseTwoWaypoints[0]);
+
+ Creature* summon = me->SummonCreature(NPC_HOVER_DISK_CASTER,HoverDiskWaypoints[MAX_HOVER_DISK_WAYPOINTS-1]);
+ if (summon && summon->IsAIEnabled)
+ summon->AI()->DoAction(ACTION_HOVER_DISK_START_WP_2);
+ summon = me->SummonCreature(NPC_HOVER_DISK_CASTER,HoverDiskWaypoints[0]);
+ if (summon && summon->IsAIEnabled)
+ summon->AI()->DoAction(ACTION_HOVER_DISK_START_WP_1);
+
+ for (uint8 i = 0; i < 2; i++)
+ {
+ // not sure about its position.
+ summon = me->SummonCreature(NPC_HOVER_DISK_MELEE,HoverDiskWaypoints[0]);
+ if (summon)
+ summon->SetInCombatWithZone();
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
{
- //Return since we have no target
if (!UpdateVictim())
return;
- if (phase == 1 && HealthBelowPct(50)) {
- phase = 2;
- //spawn adds
- //set malygos unatackable untill all adds spawned dead
- //start phase3
+ events.Update(diff);
+
+ if (phase == PHASE_THREE)
+ {
+ if (!cannotMove)
+ {
+ // it can change if the player falls from the vehicle.
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
+ {
+ me->GetMotionMaster()->MovementExpired();
+ me->GetMotionMaster()->MoveIdle();
+ }
+ } else
+ {
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)
+ {
+ me->GetMotionMaster()->MovementExpired();
+ me->GetMotionMaster()->MovePoint(MOVE_CENTER_PLATFORM,MalygosPositions[0].GetPositionX(),MalygosPositions[0].GetPositionY(),MalygosPositions[0].GetPositionZ());
+ }
+ }
+ }
+
+ // we need a better way for pathing
+ if (delayedMovement)
+ {
+ if (delayedMovementTimer <= diff)
+ {
+ me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION,MalygosPhaseTwoWaypoints[currentPos]);
+ delayedMovementTimer = 8000;
+ delayedMovement = false;
+ } delayedMovementTimer -= diff;
+ }
+
+ // at 50 % health malygos switch to phase 2
+ if (me->GetHealthPct() <= 50.0f && phase == PHASE_ONE)
+ StartPhaseTwo();
+
+ // the boss is handling vortex
+ if (me->HasAura(SPELL_VORTEX_2))
+ return;
+
+ // We can't cast if we are casting already.
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_YELL_2:
+ Talk(SAY_END_P_TWO);
+ break;
+ case EVENT_YELL_3:
+ Talk(SAY_INTRO_P_THREE);
+ break;
+ case EVENT_YELL_4:
+ Talk(SAY_AGGRO_P_THREE);
+ break;
+ case EVENT_YELL_0:
+ Talk(SAY_END_P_ONE);
+ break;
+ case EVENT_YELL_1:
+ Talk(SAY_AGGRO_P_TWO);
+ break;
+ case EVENT_ARCANE_BREATH:
+ DoCast(me->getVictim(),SPELL_ARCANE_BREATH);
+ events.ScheduleEvent(EVENT_ARCANE_BREATH,urand(35,60)*IN_MILLISECONDS,0,PHASE_ONE);
+ break;
+ case EVENT_ARCANE_STORM:
+ DoCast(me->getVictim(),SPELL_ARCANE_STORM);
+ events.ScheduleEvent(EVENT_ARCANE_STORM,urand(5,10)*IN_MILLISECONDS,0,PHASE_ONE);
+ break;
+ case EVENT_VORTEX:
+ PrepareForVortex();
+ events.ScheduleEvent(EVENT_VORTEX,urand(60,80)*IN_MILLISECONDS,0,PHASE_ONE);
+ break;
+ case EVENT_POWER_SPARKS:
+ instance->SetData(DATA_POWER_SPARKS_HANDLING,0);
+ events.ScheduleEvent(EVENT_POWER_SPARKS,urand(30,35)*IN_MILLISECONDS,0,PHASE_ONE);
+ break;
+ case EVENT_SURGE_POWER:
+ me->GetMotionMaster()->MoveIdle();
+ delayedMovement = true;
+ DoCast(SPELL_SURGE_POWER);
+ events.ScheduleEvent(EVENT_SURGE_POWER,urand(60,70)*IN_MILLISECONDS,0,PHASE_TWO);
+ break;
+ case EVENT_SUMMON_ARCANE:
+ DoCast(SPELL_SUMMON_ARCANE_BOMB);
+ events.ScheduleEvent(EVENT_SUMMON_ARCANE,urand(12,15)*IN_MILLISECONDS,0,PHASE_TWO);
+ break;
+ case EVENT_SURGE_POWER_PHASE_3:
+ DoCast(GetTargetPhaseThree(),SPELL_SURGE_POWER_PHASE_3);
+ events.ScheduleEvent(EVENT_SURGE_POWER_PHASE_3,(7,16)*IN_MILLISECONDS,0,PHASE_THREE);
+ break;
+ case EVENT_STATIC_FIELD:
+ DoCast(GetTargetPhaseThree(),SPELL_STATIC_FIELD);
+ events.ScheduleEvent(EVENT_STATIC_FIELD,(20,30)*IN_MILLISECONDS,0,PHASE_THREE);
+ break;
+ default:
+ break;
+ }
}
DoMeleeAttackIfReady();
}
+ Unit* GetTargetPhaseThree()
+ {
+ Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0);
+
+ // we are a drake
+ if (target->GetVehicleKit())
+ return target;
+
+ // we are a player using a drake (or at least you should)
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (Unit* base = target->GetVehicleBase())
+ return base;
+ }
+
+ // is a player falling from a vehicle?
+ return NULL;
+ }
+
void JustDied(Unit* /*killer*/)
{
- DoScriptText(SAY_DEATH, me);
+ Talk(SAY_DEATH);
+ _JustDied();
+ }
+
+ private:
+ uint8 phase;
+ uint32 bersekerTimer;
+ uint8 currentPos; // used for phase 2 rotation...
+ bool delayedMovement; // used in phase2.
+ uint32 delayedMovementTimer; // used in phase 2
+ uint8 summonDeaths;
+ Position homePosition; // it can get bugged because core thinks we are pathing
+ bool mustTalk;
+ bool cannotMove;
+ };
+
+};
+
+class spell_malygos_vortex_dummy : public SpellScriptLoader
+{
+public:
+ spell_malygos_vortex_dummy() : SpellScriptLoader("spell_malygos_vortex_dummy") {}
+
+ class spell_malygos_vortex_dummy_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript)
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+
+ if (!caster)
+ return;
+
+ // each player will enter to the trigger vehicle (entry 30090) already spawned (each one can hold up to 5 players, it has 5 seats)
+ // the players enter to the vehicles casting SPELL_VORTEX_4 OR SPELL_VORTEX_5
+ if (InstanceScript* instance = caster->GetInstanceScript())
+ instance->SetData(DATA_VORTEX_HANDLING,0);
+
+ // the rest of the vortex execution continues when SPELL_VORTEX_2 is removed.
+ }
+
+ void Register()
+ {
+ OnEffect += SpellEffectFn(spell_malygos_vortex_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_malygos_vortex_dummy_SpellScript();
+ }
+};
+
+class spell_malygos_vortex_visual : public SpellScriptLoader
+{
+ public:
+ spell_malygos_vortex_visual() : SpellScriptLoader("spell_malygos_vortex_visual") { }
+
+ class spell_malygos_vortex_visual_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_malygos_vortex_visual_AuraScript);
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ std::list<HostileReference*> &m_threatlist = GetCaster()->getThreatManager().getThreatList();
+ for (std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
+ {
+ if (Unit* target = (*itr)->getTarget())
+ {
+ Player* targetPlayer = target->ToPlayer();
+
+ if (!targetPlayer || targetPlayer->isGameMaster())
+ continue;
+
+ if (InstanceScript* instance = GetCaster()->GetInstanceScript())
+ {
+ // teleport spell - i am not sure but might be it must be casted by each vehicle when its passenger leaves it
+ if (Creature* trigger = GetCaster()->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER)))
+ trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true);
+ }
+ }
+ }
+
+ if (Creature* malygos = GetCaster()->ToCreature())
+ {
+ // This is a hack, we have to re add players to the threat list because when they enter to the vehicles they are removed.
+ // Anyway even with this issue, the boss does not enter in evade mode - this prevents iterate an empty list in the next vortex execution.
+ malygos->SetInCombatWithZone();
+
+ malygos->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
+
+ malygos->GetMotionMaster()->MoveChase(GetCaster()->getVictim());
+ malygos->RemoveAura(SPELL_VORTEX_1);
+ }
+
+ }
+
+ void Register()
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_malygos_vortex_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_malygos_vortex_visual_AuraScript();
+ }
+};
+
+class npc_portal_eoe: public CreatureScript
+{
+public:
+ npc_portal_eoe() : CreatureScript("npc_portal_eoe") {}
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_portal_eoeAI(pCreature);
+ }
+
+ struct npc_portal_eoeAI : public ScriptedAI
+ {
+ npc_portal_eoeAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+ }
+
+ void Reset()
+ {
+ summonTimer = urand(5,7)*IN_MILLISECONDS;
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!me->HasAura(SPELL_PORTAL_VISUAL_CLOSED) &&
+ !me->HasAura(SPELL_PORTAL_OPENED))
+ DoCast(me,SPELL_PORTAL_VISUAL_CLOSED,true);
+
+ if (instance)
+ {
+ if (Creature* malygos = Unit::GetCreature(*me,instance->GetData64(DATA_MALYGOS)))
+ {
+ if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE)
+ {
+ me->RemoveAura(SPELL_PORTAL_OPENED);
+ DoCast(me,SPELL_PORTAL_VISUAL_CLOSED,true);
+ }
+ }
+ }
+
+ if (!me->HasAura(SPELL_PORTAL_OPENED))
+ return;
+
+ if (summonTimer <= diff)
+ {
+ DoCast(SPELL_SUMMON_POWER_PARK);
+ summonTimer = urand(5,7)*IN_MILLISECONDS;
+ } else summonTimer -= diff;
+ }
+
+ void JustSummoned(Creature* summon)
+ {
+ summon->SetInCombatWithZone();
+ }
+
+ private:
+ uint32 summonTimer;
+ InstanceScript* instance;
+ };
+};
+
+
+class npc_power_spark: public CreatureScript
+{
+public:
+ npc_power_spark() : CreatureScript("npc_power_spark") {}
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_power_sparkAI(creature);
+ }
+
+ struct npc_power_sparkAI : public ScriptedAI
+ {
+ npc_power_sparkAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+
+ MoveToMalygos();
+ }
+
+ void EnterEvadeMode()
+ {
+ me->DespawnOrUnsummon();
+ }
+
+ void MoveToMalygos()
+ {
+ me->GetMotionMaster()->MoveIdle();
+
+ if (instance)
+ {
+ if (Creature* malygos = Unit::GetCreature(*me,instance->GetData64(DATA_MALYGOS)))
+ me->GetMotionMaster()->MoveFollow(malygos,0.0f,0.0f);
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!instance)
+ return;
+
+ if (Creature* malygos = Unit::GetCreature(*me,instance->GetData64(DATA_MALYGOS)))
+ {
+ if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE)
+ {
+ me->DespawnOrUnsummon();
+ return;
+ }
+
+ if (malygos->HasAura(SPELL_VORTEX_1))
+ {
+ me->GetMotionMaster()->MoveIdle();
+ return;
+ }
+
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
+ me->GetMotionMaster()->MoveFollow(malygos,0.0f,0.0f);
+ }
+ }
+
+ void DamageTaken(Unit* /*done_by*/, uint32& damage)
+ {
+ if (damage > me->GetMaxHealth())
+ {
+ damage = 0;
+ DoCast(me,SPELL_POWER_SPARK_DEATH,true);
+ me->DespawnOrUnsummon(1000);
+ }
+ }
+
+ private:
+ InstanceScript* instance;
+ };
+};
+
+class npc_hover_disk : public CreatureScript
+{
+public:
+ npc_hover_disk() : CreatureScript("npc_hover_disk") { }
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_hover_diskAI(creature);
+ }
+
+ struct npc_hover_diskAI : public npc_escortAI
+ {
+ npc_hover_diskAI(Creature* creature) : npc_escortAI(creature)
+ {
+ if (me->GetEntry() == NPC_HOVER_DISK_CASTER)
+ me->SetReactState(REACT_PASSIVE);
+ else
+ me->SetInCombatWithZone();
+
+ instance = creature->GetInstanceScript();
+ }
+
+ void Reset()
+ {
+ if (Vehicle* veh = me->GetVehicleKit())
+ veh->Reset();
+ }
+
+ void PassengerBoarded(Unit* unit, int8 seat, bool apply)
+ {
+ if (apply)
+ {
+ if (unit->GetTypeId() == TYPEID_UNIT)
+ {
+ me->setFaction(FACTION_HOSTILE);
+ unit->ToCreature()->SetInCombatWithZone();
+ }
+ }
+ else
+ {
+ // Error found: This is not called if the passenger is a player
+
+ if (unit->GetTypeId() == TYPEID_UNIT)
+ {
+ // This will only be called if the passenger dies
+ if (instance)
+ {
+ if (Creature* malygos = Unit::GetCreature(*me,instance->GetData64(DATA_MALYGOS)))
+ malygos->AI()->SetData(DATA_SUMMON_DEATHS,malygos->AI()->GetData(DATA_SUMMON_DEATHS)+1);
+ }
+
+ me->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ me->GetMotionMaster()->MoveIdle();
+
+ if (me->GetEntry() == NPC_HOVER_DISK_MELEE)
+ {
+ // Hack: Fall ground function can fail (remember the platform is a gameobject), we will teleport the disk to the ground
+ if (me->GetPositionZ() > GROUND_Z)
+ me->NearTeleportTo(me->GetPositionX(),me->GetPositionY(),GROUND_Z,0);
+ me->SetHomePosition(me->GetPositionX(),me->GetPositionY(),me->GetPositionZ(),me->GetOrientation());
+ me->setFaction(FACTION_FRIENDLY);
+ me->AI()->EnterEvadeMode();
+ }
+ }
+ }
+
+ void EnterEvadeMode()
+ {
+ // we dont evade
}
- void KilledUnit(Unit * victim)
+ void DoAction(const int32 action)
{
- if (victim == me)
+ if (me->GetEntry() != NPC_HOVER_DISK_CASTER)
return;
- if (phase == 1)
- DoScriptText(RAND(SAY_PHASE1_SLAY_1,SAY_PHASE1_SLAY_2,SAY_PHASE1_SLAY_3), me);
- if (phase == 2)
- DoScriptText(RAND(SAY_PHASE2_SLAY_1,SAY_PHASE2_SLAY_2,SAY_PHASE2_SLAY_3), me);
- if (phase == 3)
- DoScriptText(RAND(SAY_PHASE3_SLAY_1,SAY_PHASE3_SLAY_2,SAY_PHASE3_SLAY_3), me);
+ switch (action)
+ {
+ case ACTION_HOVER_DISK_START_WP_1:
+ for (uint8 i = 0; i < MAX_HOVER_DISK_WAYPOINTS; i++)
+ AddWaypoint(i,HoverDiskWaypoints[i].GetPositionX(),HoverDiskWaypoints[i].GetPositionY(),HoverDiskWaypoints[i].GetPositionZ());
+ break;
+ case ACTION_HOVER_DISK_START_WP_2:
+ {
+ uint8 count = 0;
+ for (uint8 i = MAX_HOVER_DISK_WAYPOINTS-1; i > 0; i--)
+ {
+ AddWaypoint(count,HoverDiskWaypoints[i].GetPositionX(),HoverDiskWaypoints[i].GetPositionY(),HoverDiskWaypoints[i].GetPositionZ());
+ count++;
+ }
+ break;
+ }
+ default:
+ return;
+ }
+
+ Start(true,false,0,0,false,true);
+ }
+
+ void UpdateEscortAI(const uint32 /*diff*/)
+ {
+ // we dont do melee damage!
}
+
+ void WaypointReached(uint32 i)
+ {
+
+ }
+
+ private:
+ InstanceScript* instance;
};
+};
+
+// The reason of this AI is to make the creature able to enter in combat otherwise the spell casting of SPELL_ARCANE_OVERLOAD fails.
+class npc_arcane_overload : public CreatureScript
+{
+public:
+ npc_arcane_overload() : CreatureScript("npc_arcane_overload") {}
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_arcane_overloadAI (creature);
+ }
+
+ struct npc_arcane_overloadAI : public ScriptedAI
+ {
+ npc_arcane_overloadAI(Creature* creature) : ScriptedAI(creature) {}
+
+ void AttackStart(Unit* who)
+ {
+ DoStartNoMovement(who);
+ }
+
+ void Reset()
+ {
+ DoCast(me,SPELL_ARCANE_OVERLOAD,false);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ // we dont do melee damage!
+ }
+
+ };
+};
+
+// SmartAI does not work correctly for this (vehicles)
+class npc_wyrmrest_skytalon : public CreatureScript
+{
+public:
+ npc_wyrmrest_skytalon() : CreatureScript("npc_wyrmrest_skytalon") {}
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_wyrmrest_skytalonAI (creature);
+ }
+
+ struct npc_wyrmrest_skytalonAI : public NullCreatureAI
+ {
+ npc_wyrmrest_skytalonAI(Creature* creature) : NullCreatureAI(creature)
+ {
+ instance = creature->GetInstanceScript();
+
+ timer = 1000;
+ entered = false;
+ }
+
+ // we can't call this in reset function, it fails.
+ void MakePlayerEnter()
+ {
+ if (!instance)
+ return;
+
+ if (Creature* malygos = Unit::GetCreature(*me,instance->GetData64(DATA_MALYGOS)))
+ {
+ if (Unit* summoner = me->ToTempSummon()->GetSummoner())
+ {
+ summoner->CastSpell(me,SPELL_RIDE_RED_DRAGON,true);
+ if (Creature* malygos = Unit::GetCreature(*me,instance->GetData64(DATA_MALYGOS)))
+ {
+ float victim_threat = malygos->getThreatManager().getThreat(summoner);
+ malygos->getThreatManager().resetAllAggro();
+ malygos->AI()->AttackStart(me);
+ malygos->AddThreat(me, victim_threat);
+ }
+ }
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!entered)
+ {
+ if (timer <= diff)
+ {
+ MakePlayerEnter();
+ entered = true;
+ } else timer -= diff;
+ }
+ }
+
+ private:
+ InstanceScript* instance;
+ uint32 timer;
+ bool entered;
+ };
+};
+
+enum AlexstraszaYells
+{
+ SAY_ONE,
+ SAY_TWO,
+ SAY_THREE,
+ SAY_FOUR
+};
+
+class npc_alexstrasza_eoe : public CreatureScript
+{
+public:
+ npc_alexstrasza_eoe() : CreatureScript("npc_alexstrasza_eoe") { }
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_alexstrasza_eoeAI (creature);
+ }
+
+ struct npc_alexstrasza_eoeAI : public ScriptedAI
+ {
+ npc_alexstrasza_eoeAI(Creature* creature) : ScriptedAI(creature) {}
+
+ void Reset()
+ {
+ events.Reset();
+
+ events.ScheduleEvent(EVENT_YELL_1,0);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_YELL_1:
+ Talk(SAY_ONE);
+ events.ScheduleEvent(EVENT_YELL_2,4*IN_MILLISECONDS);
+ break;
+ case EVENT_YELL_2:
+ Talk(SAY_TWO);
+ events.ScheduleEvent(EVENT_YELL_3,4*IN_MILLISECONDS);
+ break;
+ case EVENT_YELL_3:
+ Talk(SAY_THREE);
+ events.ScheduleEvent(EVENT_YELL_4,7*IN_MILLISECONDS);
+ break;
+ case EVENT_YELL_4:
+ Talk(SAY_FOUR);
+ break;
+ }
+ }
+ }
+ private:
+ EventMap events;
+ };
};
void AddSC_boss_malygos()
{
new boss_malygos();
+ new npc_portal_eoe();
+ new npc_power_spark();
+ new npc_hover_disk();
+ new npc_arcane_overload();
+ new npc_wyrmrest_skytalon();
+ new spell_malygos_vortex_dummy();
+ new spell_malygos_vortex_visual();
+ new npc_alexstrasza_eoe();
}
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
index 04415f0af07..5bd66b9ffa4 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h
@@ -18,4 +18,55 @@
#ifndef DEF_EYE_OF_ETERNITY_H
#define DEF_EYE_OF_ETERNITY_H
+enum InstanceData
+{
+ DATA_MALYGOS_EVENT,
+ MAX_ENCOUNTER,
+
+ DATA_VORTEX_HANDLING,
+ DATA_POWER_SPARKS_HANDLING
+};
+
+enum InstanceData64
+{
+ DATA_TRIGGER,
+ DATA_MALYGOS,
+ DATA_PLATFORM
+};
+
+enum InstanceNpcs
+{
+ NPC_MALYGOS = 28859,
+ NPC_VORTEX_TRIGGER = 30090,
+ NPC_PORTAL_TRIGGER = 30118,
+ NPC_POWER_SPARK = 30084,
+ NPC_HOVER_DISK_MELEE = 30234,
+ NPC_HOVER_DISK_CASTER = 30248,
+ NPC_ARCANE_OVERLOAD = 30282,
+ NPC_WYRMREST_SKYTALON = 30161,
+ NPC_ALEXSTRASZA = 32295
+};
+
+enum InstanceGameObjects
+{
+ GO_NEXUS_RAID_PLATFORM = 193070,
+ GO_EXIT_PORTAL = 193908,
+ GO_FOCUSING_IRIS = 193958,
+ GO_ALEXSTRASZA_S_GIFT = 193905,
+ GO_ALEXSTRASZA_S_GIFT_2 = 193967
+};
+
+enum InstanceEvents
+{
+ EVENT_FOCUSING_IRIS = 20711
+};
+
+enum InstanceSpells
+{
+ SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle
+ SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle
+ SPELL_PORTAL_OPENED = 61236,
+ SPELL_RIDE_RED_DRAGON = 56071,
+};
+
#endif
diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
index 49d7997ddc5..a28b5258e4b 100644
--- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
+++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp
@@ -21,22 +21,275 @@
class instance_eye_of_eternity : public InstanceMapScript
{
public:
- instance_eye_of_eternity() : InstanceMapScript("instance_eye_of_eternity", 616) { }
+ instance_eye_of_eternity() : InstanceMapScript("instance_eye_of_eternity", 616) {}
- InstanceScript* GetInstanceScript(InstanceMap* pMap) const
+ InstanceScript* GetInstanceScript(InstanceMap* map) const
{
- return new instance_eye_of_eternity_InstanceMapScript(pMap);
+ return new instance_eye_of_eternity_InstanceMapScript(map);
}
struct instance_eye_of_eternity_InstanceMapScript : public InstanceScript
{
- instance_eye_of_eternity_InstanceMapScript(Map* pMap) : InstanceScript(pMap) {Initialize();};
- };
+ instance_eye_of_eternity_InstanceMapScript(Map* map) : InstanceScript(map)
+ {
+ SetBossNumber(MAX_ENCOUNTER);
+
+ vortexTriggers.clear();
+ portalTriggers.clear();
+
+ malygosGUID = 0;
+ lastPortalGUID = 0;
+ platformGUID = 0;
+ exitPortalGUID = 0;
+ };
+
+ bool SetBossState(uint32 type, EncounterState state)
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
+
+ if (type == DATA_MALYGOS_EVENT)
+ {
+ if (state == FAIL)
+ {
+ for (std::list<uint64>::const_iterator itr_trigger = portalTriggers.begin(); itr_trigger != portalTriggers.end(); ++itr_trigger)
+ {
+ if (Creature* trigger = instance->GetCreature(*itr_trigger))
+ {
+ // just in case
+ trigger->RemoveAllAuras();
+ trigger->AI()->Reset();
+ }
+ }
+
+ SpawnGameObject(GO_FOCUSING_IRIS,focusingIrisPosition);
+ SpawnGameObject(GO_EXIT_PORTAL,exitPortalPosition);
+
+ if (GameObject* platform = instance->GetGameObject(platformGUID))
+ platform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
+ } else if (state == DONE)
+ {
+ if (Creature* malygos = instance->GetCreature(malygosGUID))
+ malygos->SummonCreature(NPC_ALEXSTRASZA,829.0679f,1244.77f,279.7453f,2.32f);
+
+ SpawnGameObject(GO_EXIT_PORTAL,exitPortalPosition);
+
+ // we make the platform appear again because at the moment we don't support looting using a vehicle
+ if (GameObject* platform = instance->GetGameObject(platformGUID))
+ platform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED);
+
+ if (GameObject* chest = instance->GetGameObject(chestGUID))
+ chest->SetRespawnTime(chest->GetRespawnDelay());
+ }
+ }
+ return true;
+ }
+
+ // There is no other way afaik...
+ void SpawnGameObject(uint32 entry, Position& pos)
+ {
+ GameObject* go = new GameObject;
+ if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, instance,
+ PHASEMASK_NORMAL, pos.GetPositionX(),pos.GetPositionY(),pos.GetPositionZ(),pos.GetOrientation(),
+ 0,0,0,0,120,GO_STATE_READY))
+ {
+ delete go;
+ return;
+ }
+
+ instance->Add(go);
+ }
+
+ void OnGameObjectCreate(GameObject* go)
+ {
+ switch (go->GetEntry())
+ {
+ case GO_NEXUS_RAID_PLATFORM:
+ platformGUID = go->GetGUID();
+ break;
+ case GO_FOCUSING_IRIS:
+ go->GetPosition(&focusingIrisPosition);
+ break;
+ case GO_EXIT_PORTAL:
+ exitPortalGUID = go->GetGUID();
+ go->GetPosition(&exitPortalPosition);
+ break;
+ case GO_ALEXSTRASZA_S_GIFT:
+ case GO_ALEXSTRASZA_S_GIFT_2:
+ chestGUID = go->GetGUID();
+ break;
+ }
+ }
+
+ void OnCreatureCreate(Creature* creature)
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_VORTEX_TRIGGER:
+ vortexTriggers.push_back(creature->GetGUID());
+ break;
+ case NPC_MALYGOS:
+ malygosGUID = creature->GetGUID();
+ break;
+ case NPC_PORTAL_TRIGGER:
+ portalTriggers.push_back(creature->GetGUID());
+ break;
+ }
+ }
+
+ void ProcessEvent(GameObject* go, uint32 eventId)
+ {
+ if (eventId == EVENT_FOCUSING_IRIS)
+ {
+ go->Delete(); // this is not the best way.
+ if (Creature* malygos = instance->GetCreature(malygosGUID))
+ malygos->GetMotionMaster()->MovePoint(4,770.10f, 1275.33f, 267.23f); // MOVE_INIT_PHASE_ONE
+
+ if (GameObject* exitPortal = instance->GetGameObject(exitPortalGUID))
+ exitPortal->Delete();
+ }
+ }
+
+ void VortexHandling()
+ {
+ if (Creature* malygos = instance->GetCreature(malygosGUID))
+ {
+ std::list<HostileReference*> m_threatlist = malygos->getThreatManager().getThreatList();
+ for (std::list<uint64>::const_iterator itr_vortex = vortexTriggers.begin(); itr_vortex != vortexTriggers.end(); ++itr_vortex)
+ {
+ if (m_threatlist.empty())
+ return;
+
+ uint8 counter = 0;
+ if (Creature* trigger = instance->GetCreature(*itr_vortex))
+ {
+ // each trigger have to cast the spell to 5 players.
+ for (std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
+ {
+ if (counter >= 5)
+ break;
+
+ if (Unit* target = (*itr)->getTarget())
+ {
+ Player* player = target->ToPlayer();
+ if (!player || player->isGameMaster() || player->HasAura(SPELL_VORTEX_4))
+ continue;
+
+ player->CastSpell(trigger,SPELL_VORTEX_4,true);
+ counter++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void PowerSparksHandling()
+ {
+ bool next = (lastPortalGUID == portalTriggers.back() || !lastPortalGUID ? true : false);
+
+ for (std::list<uint64>::const_iterator itr_trigger = portalTriggers.begin(); itr_trigger != portalTriggers.end(); ++itr_trigger)
+ {
+ if (next)
+ {
+ if (Creature* trigger = instance->GetCreature(*itr_trigger))
+ {
+ lastPortalGUID = trigger->GetGUID();
+ trigger->CastSpell(trigger,SPELL_PORTAL_OPENED,true);
+ return;
+ }
+ }
+
+ if (*itr_trigger == lastPortalGUID)
+ next = true;
+ }
+ }
+
+ void SetData(uint32 data,uint32 /*value*/)
+ {
+ switch (data)
+ {
+ case DATA_VORTEX_HANDLING:
+ VortexHandling();
+ break;
+ case DATA_POWER_SPARKS_HANDLING:
+ PowerSparksHandling();
+ break;
+ }
+ }
+
+ uint64 GetData64(uint32 data)
+ {
+ switch (data)
+ {
+ case DATA_TRIGGER:
+ return vortexTriggers.front();
+ case DATA_MALYGOS:
+ return malygosGUID;
+ case DATA_PLATFORM:
+ return platformGUID;
+ }
+
+ return 0;
+ }
+
+ std::string GetSaveData()
+ {
+ OUT_SAVE_INST_DATA;
+
+ std::ostringstream saveStream;
+ saveStream << "E E " << GetBossSaveData();
+
+ OUT_SAVE_INST_DATA_COMPLETE;
+ return saveStream.str();
+ }
+
+ void Load(const char* str)
+ {
+ if (!str)
+ {
+ OUT_LOAD_INST_DATA_FAIL;
+ return;
+ }
+
+ OUT_LOAD_INST_DATA(str);
+
+ char dataHead1, dataHead2;
+
+ std::istringstream loadStream(str);
+ loadStream >> dataHead1 >> dataHead2;
+
+ if (dataHead1 == 'E' && dataHead2 == 'E')
+ {
+ for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
+ {
+ uint32 tmpState;
+ loadStream >> tmpState;
+ if (tmpState == IN_PROGRESS || tmpState > SPECIAL)
+ tmpState = NOT_STARTED;
+ SetBossState(i, EncounterState(tmpState));
+ }
+
+ } else OUT_LOAD_INST_DATA_FAIL;
+
+ OUT_LOAD_INST_DATA_COMPLETE;
+ }
+
+ private:
+ std::list<uint64> vortexTriggers;
+ std::list<uint64> portalTriggers;
+ uint64 malygosGUID;
+ uint64 lastPortalGUID;
+ uint64 platformGUID;
+ uint64 exitPortalGUID;
+ uint64 chestGUID;
+ Position focusingIrisPosition;
+ Position exitPortalPosition;
+ };
};
void AddSC_instance_eye_of_eternity()
{
- // doesn't exist in the database?
- //new instance_eye_of_eternity();
+ new instance_eye_of_eternity();
}