diff options
author | Manuel <manue.l@live.com.ar> | 2011-03-26 21:36:06 -0300 |
---|---|---|
committer | Manuel <manue.l@live.com.ar> | 2011-03-26 21:36:06 -0300 |
commit | 21a2c56af32f006664d3e982e34b181848b49635 (patch) | |
tree | 801a21ca615c9e8e8890f914cad8460ad0c588f3 /src | |
parent | 75bf08c08144892ff6c7351d2602af2046a47db7 (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')
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(); } |