aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp800
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp12
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h7
3 files changed, 400 insertions, 419 deletions
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp
index de46497d2b2..aa958610c93 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_xt002.cpp
@@ -20,11 +20,14 @@
Add achievments
Boombot explosion only hurt allies to the npc at the moment
Boombot explosion visual
- Test the enrage timer
- Fix gravity bomb - tractor beam.
- Fix void zone spell
- If the boss is to close to a scrap pile -> no summon
- make the life sparks visible...
+ Fix gravity bomb - tractor beam. /? Need test
+ Fix void zone spell /? Need test
+ If the boss is to close to a scrap pile -> no summon
+ make the life sparks visible... /? Need test
+ Phase transition kneel/stand up animation
+ Tympanic Tantrum needs its range reduced
+ Proper scripts for adds (scrapbots should enter vehicle)
+ Codestyle
*/
#include "ScriptMgr.h"
@@ -37,6 +40,9 @@ enum Spells
SPELL_SEARING_LIGHT_10 = 63018,
SPELL_SEARING_LIGHT_25 = 65121,
+ SPELL_SUMMON_LIFE_SPARK = 64210,
+ SPELL_SUMMON_VOID_ZONE = 64203,
+
SPELL_GRAVITY_BOMB_10 = 63024,
SPELL_GRAVITY_BOMB_25 = 64234,
SPELL_GRAVITY_BOMB_AURA_10 = 63025,
@@ -45,7 +51,22 @@ enum Spells
SPELL_HEARTBREAK_10 = 65737,
SPELL_HEARTBREAK_25 = 64193,
+ // Cast by 33337 at Heartbreak:
+ SPELL_RECHARGE_PUMMELER = 62831, // Summons 33344
+ SPELL_RECHARGE_SCRAPBOT = 62828, // Summons 33343
+ SPELL_RECHARGE_BOOMBOT = 62835, // Summons 33346
+
+ // Cast by 33329 on 33337 (visual?)
+ SPELL_ENERGY_ORB = 62790, // Triggers 62826 - needs spellscript for periodic tick to cast one of the random spells above
+
+ SPELL_HEART_HEAL_TO_FULL = 17683,
+ SPELL_HEART_OVERLOAD = 62789,
+
+ SPELL_HEART_LIGHTNING_TETHER = 64799, // Cast on self?
+ SPELL_HEART_RIDE_VEHICLE = 63313,
SPELL_ENRAGE = 26662,
+ SPELL_STAND = 37752,
+ SPELL_SUBMERGE = 37751,
//------------------VOID ZONE--------------------
SPELL_VOID_ZONE_10 = 64203,
@@ -58,26 +79,42 @@ enum Spells
//----------------XT-002 HEART-------------------
SPELL_EXPOSED_HEART = 63849,
+ // Channeled
//---------------XM-024 PUMMELLER----------------
SPELL_ARCING_SMASH = 8374,
SPELL_TRAMPLE = 5568,
SPELL_UPPERCUT = 10966,
+ // Scrabot:
+ SPELL_SCRAPBOT_RIDE_VEHICLE = 47020,
+ SPELL_SUICIDE = 7,
+
//------------------BOOMBOT-----------------------
SPELL_BOOM = 62834,
};
+enum Events
+{
+ EVENT_TYMPANIC_TANTRUM = 1,
+ EVENT_SEARING_LIGHT,
+ EVENT_GRAVITY_BOMB,
+ EVENT_HEART_PHASE,
+ EVENT_ENERGY_ORB,
+ EVENT_DISPOSE_HEART,
+ EVENT_ENRAGE,
+};
+
enum Timers
{
TIMER_TYMPANIC_TANTRUM_MIN = 32000,
TIMER_TYMPANIC_TANTRUM_MAX = 36000,
TIMER_SEARING_LIGHT = 20000,
- TIMER_SPAWN_LIFE_SPARK = 9000,
TIMER_GRAVITY_BOMB = 20000,
TIMER_HEART_PHASE = 30000,
+ TIMER_ENERGY_ORB_MIN = 9000,
+ TIMER_ENERGY_ORB_MAX = 10000,
TIMER_ENRAGE = 600000,
- TIMER_GRAVITY_BOMB_AURA = 8900,
TIMER_VOID_ZONE = 3000,
@@ -131,33 +168,15 @@ enum
ACHIEV_TIMED_START_EVENT = 21027,
};
-//#define GRAVITY_BOMB_DMG_MIN_10 11700
-//#define GRAVITY_BOMB_DMG_MAX_10 12300
-//#define GRAVITY_BOMB_DMG_MIN_25 14625
-//#define GRAVITY_BOMB_DMG_MAX_25 15375
-//#define GRAVITY_BOMB_RADIUS 12
-
-//#define VOID_ZONE_DMG_10 5000
-//#define VOID_ZONE_DMG_25 7500
-//#define VOID_ZONE_RADIUS
-
-/************************************************
------------------SPAWN LOCATIONS-----------------
-************************************************/
-//Shared Z-level
-#define SPAWN_Z 412
-//Lower right
-#define LR_X 796
-#define LR_Y -94
-//Lower left
-#define LL_X 796
-#define LL_Y 57
-//Upper right
-#define UR_X 890
-#define UR_Y -82
-//Upper left
-#define UL_X 894
-#define UL_Y 62
+const Position SpawnPos[4] =
+{
+ {888.69f, 25.63f, 409.81f, 1.58f},
+ {896.74f, 68.08f, 412.24f, 4.03f},
+ {895.88f, -93.45f, 441.95f, 2.21f},
+ {787.33f, -92.33f, 412.01f, 0.83f}
+};
+
+#define HEART_VEHICLE_SEAT 0
/*-------------------------------------------------------
*
@@ -166,357 +185,236 @@ enum
*///----------------------------------------------------
class boss_xt002 : public CreatureScript
{
-public:
- boss_xt002() : CreatureScript("boss_xt002") { }
+ public:
+ boss_xt002() : CreatureScript("boss_xt002") { }
- CreatureAI* GetAI(Creature* pCreature) const
- {
- return GetUlduarAI<boss_xt002_AI>(pCreature);
- }
-
- struct boss_xt002_AI : public BossAI
- {
- boss_xt002_AI(Creature *pCreature) : BossAI(pCreature, BOSS_XT002)
+ CreatureAI* GetAI(Creature* pCreature) const
{
+ return GetUlduarAI<boss_xt002_AI>(pCreature);
}
- uint32 uiSearingLightTimer;
- uint32 uiSpawnLifeSparkTimer;
- uint32 uiGravityBombTimer;
- uint32 uiGravityBombAuraTimer;
- uint32 uiTympanicTantrumTimer;
- uint32 uiHeartPhaseTimer;
- uint32 uiSpawnAddTimer;
- uint32 uiEnrageTimer;
-
- bool searing_light_active;
- uint64 uiSearingLightTarget;
+ struct boss_xt002_AI : public BossAI
+ {
+ boss_xt002_AI(Creature *pCreature) : BossAI(pCreature, BOSS_XT002)
+ {
+ }
- bool gravity_bomb_active;
- uint64 uiGravityBombTarget;
+ uint8 _phase;
+ uint8 _heartExposed;
- uint8 phase;
- uint8 heart_exposed;
- bool enraged;
+ uint32 transferHealth;
+ bool enterHardMode;
+ bool hardMode;
- uint32 transferHealth;
- bool enterHardMode;
- bool hardMode;
+ void Reset()
+ {
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE);
- void Reset()
- {
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE);
-
- //Makes XT-002 to cast a light bomb 10 seconds after aggro.
- uiSearingLightTimer = TIMER_SEARING_LIGHT/2;
- uiSpawnLifeSparkTimer = TIMER_SPAWN_LIFE_SPARK;
- uiGravityBombTimer = TIMER_GRAVITY_BOMB;
- uiGravityBombAuraTimer = TIMER_GRAVITY_BOMB_AURA;
- uiHeartPhaseTimer = TIMER_HEART_PHASE;
- uiSpawnAddTimer = TIMER_SPAWN_ADD;
- uiEnrageTimer = TIMER_ENRAGE;
-
- //Tantrum is casted a bit slower the first time.
- uiTympanicTantrumTimer = urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX) * 2;
-
- searing_light_active = false;
- gravity_bomb_active = false;
- enraged = false;
- hardMode = false;
- enterHardMode = false;
-
- phase = 1;
- heart_exposed = 0;
-
- if (instance)
- instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- }
+ hardMode = false;
+ enterHardMode = false;
- void EnterCombat(Unit* /*who*/)
- {
- DoScriptText(SAY_AGGRO, me);
- _EnterCombat();
+ _phase = 1;
+ _heartExposed = 0;
- if (instance)
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- }
+ if (instance)
+ instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
+ }
- void DoAction(const int32 action)
- {
- switch (action)
+ void EnterCombat(Unit* /*who*/)
{
- case ACTION_ENTER_HARD_MODE:
- if (!hardMode)
- {
- hardMode = true;
+ DoScriptText(SAY_AGGRO, me);
+ _EnterCombat();
- // Enter hard mode
- enterHardMode = true;
+ events.ScheduleEvent(EVENT_ENRAGE, TIMER_ENRAGE);
+ events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB);
+ events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT);
+ //Tantrum is casted a bit slower the first time.
+ events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX) * 2);
- // set max health
- me->SetFullHealth();
-
- // Get his heartbreak buff
- me->CastSpell(me, RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25), true);
- }
- break;
+ if (instance)
+ instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
}
- }
- void SetData(uint32 id, uint32 value)
- {
- switch(id)
+ void DoAction(const int32 action)
{
- case DATA_TRANSFERED_HEALTH:
- transferHealth = value;
- break;
- }
- }
+ switch (action)
+ {
+ case ACTION_ENTER_HARD_MODE:
+ if (!hardMode)
+ {
+ hardMode = true;
- void KilledUnit(Unit* /*victim*/)
- {
- DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me);
- }
+ // Enter hard mode
+ enterHardMode = true;
- void JustDied(Unit * /*victim*/)
- {
- DoScriptText(SAY_DEATH, me);
- _JustDied();
- }
+ // set max health
+ me->SetFullHealth();
- void UpdateAI(const uint32 diff)
- {
- if (!UpdateVictim())
- return;
+ // Get his heartbreak buff
+ me->CastSpell(me, RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25), true);
- if (enterHardMode)
- {
- SetPhaseOne();
- enterHardMode = false;
+ me->AddLootMode(LOOT_MODE_HARD_MODE_1);
+ }
+ break;
+ }
}
- // Handles spell casting. These spells only occur during phase 1 and hard mode
- if (phase == 1 || hardMode)
+ void SetData(uint32 id, uint32 value)
{
- if (uiSearingLightTimer <= diff)
+ switch(id)
{
- if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0))
- {
- DoCast(pTarget, RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25));
- uiSearingLightTarget = pTarget->GetGUID();
- }
- uiSpawnLifeSparkTimer = TIMER_SPAWN_LIFE_SPARK;
- if (hardMode)
- searing_light_active = true;
- uiSearingLightTimer = TIMER_SEARING_LIGHT;
- } else uiSearingLightTimer -= diff;
+ case DATA_TRANSFERED_HEALTH:
+ transferHealth = value;
+ break;
+ }
+ }
- if (uiGravityBombTimer <= diff)
- {
- if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0))
- {
- DoCast(pTarget, RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25));
- uiGravityBombTarget = pTarget->GetGUID();
- }
- uiGravityBombTimer = TIMER_GRAVITY_BOMB;
- gravity_bomb_active = true;
- } else uiGravityBombTimer -= diff;
+ void KilledUnit(Unit* /*victim*/)
+ {
+ DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me);
+ }
- if (uiTympanicTantrumTimer <= diff)
- {
- DoScriptText(SAY_TYMPANIC_TANTRUM, me);
- DoCast(SPELL_TYMPANIC_TANTRUM);
- uiTympanicTantrumTimer = urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX);
- } else uiTympanicTantrumTimer -= diff;
+ void JustDied(Unit * /*victim*/)
+ {
+ DoScriptText(SAY_DEATH, me);
+ _JustDied();
}
- if (!hardMode)
+ void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/)
{
- if (phase == 1)
- {
- if (HealthBelowPct(75) && heart_exposed == 0)
- {
- exposeHeart();
- }
- else if (HealthBelowPct(50) && heart_exposed == 1)
- {
- exposeHeart();
- }
- else if (HealthBelowPct(25) && heart_exposed == 2)
- {
- exposeHeart();
- }
+ if (!hardMode && _phase == 1 && !HealthAbovePct(100 - 25 * (_heartExposed+1)))
+ ExposeHeart();
+ }
- DoMeleeAttackIfReady();
- }
- else
- {
- //Stop moving
- me->StopMoving();
+ void UpdateAI(const uint32 diff)
+ {
+ if (_phase == 1 && !UpdateVictim())
+ return;
- //Start summoning adds
- if (uiSpawnAddTimer <= diff)
- {
- DoScriptText(SAY_SUMMON, me);
+ events.Update(diff);
- // Spawn Pummeller
- switch (rand() % 4)
- {
- case 0: me->SummonCreature(NPC_XM024_PUMMELLER, LR_X, LR_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 1: me->SummonCreature(NPC_XM024_PUMMELLER, LL_X, LL_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 2: me->SummonCreature(NPC_XM024_PUMMELLER, UR_X, UR_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 3: me->SummonCreature(NPC_XM024_PUMMELLER, UL_X, UL_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- }
+ if (enterHardMode)
+ {
+ SetPhaseOne();
+ enterHardMode = false;
+ }
- // Spawn 5 Bombs
- for (int8 n = 0; n < 5; n++)
- {
- //Some randomes are added so they wont spawn in a pile
- switch(rand() % 4)
- {
- case 0: me->SummonCreature(NPC_XS013_SCRAPBOT, float(irand(LR_X - 3, LR_X + 3)), float(irand(LR_Y - 3, LR_Y + 3)), SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 1: me->SummonCreature(NPC_XS013_SCRAPBOT, float(irand(LL_X - 3, LL_X + 3)), float(irand(LL_Y - 3, LL_Y + 3)), SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 2: me->SummonCreature(NPC_XS013_SCRAPBOT, float(irand(UR_X - 3, UR_X + 3)), float(irand(UR_Y - 3, UR_Y + 3)), SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 3: me->SummonCreature(NPC_XS013_SCRAPBOT, float(irand(UL_X - 3, UL_X + 3)), float(irand(UL_Y - 3, UL_Y + 3)), SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- }
- }
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
- //Spawn 5 Scrapbots
- switch (rand() % 4)
+ // Handles spell casting. These spells only occur during phase 1 and hard mode
+ if (_phase == 1)
+ {
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
{
- case 0: me->SummonCreature(NPC_XE321_BOOMBOT, LR_X, LR_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 1: me->SummonCreature(NPC_XE321_BOOMBOT, LL_X, LL_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 2: me->SummonCreature(NPC_XE321_BOOMBOT, UR_X, UR_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
- case 3: me->SummonCreature(NPC_XE321_BOOMBOT, UL_X, UL_Y, SPAWN_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); break;
+ case EVENT_SEARING_LIGHT:
+ if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ DoCast(pTarget, RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25));
+
+ events.RepeatEvent(TIMER_SEARING_LIGHT);
+ break;
+ case EVENT_GRAVITY_BOMB:
+ if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ DoCast(pTarget, RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25));
+
+ events.RepeatEvent(TIMER_GRAVITY_BOMB);
+ break;
+ case EVENT_TYMPANIC_TANTRUM:
+ DoScriptText(SAY_TYMPANIC_TANTRUM, me);
+ DoCast(SPELL_TYMPANIC_TANTRUM);
+ events.RepeatEvent(urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX));
+ break;
+ case EVENT_ENRAGE:
+ DoScriptText(SAY_BERSERK, me);
+ DoCast(me, SPELL_ENRAGE);
+ break;
}
-
- uiSpawnAddTimer = TIMER_SPAWN_ADD;
- } else uiSpawnAddTimer -= diff;
-
- // Is the phase over?
- if (uiHeartPhaseTimer <= diff)
- {
- DoScriptText(SAY_HEART_CLOSED, me);
- SetPhaseOne();
}
- else
- uiHeartPhaseTimer -= diff;
+ DoMeleeAttackIfReady();
}
- }
- else
- {
- // Adding life sparks when searing light debuff runs out if hard mode
- if (searing_light_active)
+ else if (_phase == 2)
{
- if (uiSpawnLifeSparkTimer <= diff)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (Unit *pSearingLightTarget = me->GetUnit(*me, uiSearingLightTarget))
- pSearingLightTarget->SummonCreature(NPC_LIFE_SPARK, pSearingLightTarget->GetPositionX(), pSearingLightTarget->GetPositionY(), pSearingLightTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
- uiSpawnLifeSparkTimer = TIMER_SPAWN_LIFE_SPARK;
- searing_light_active = false;
- } else uiSpawnLifeSparkTimer -= diff;
+ switch (eventId)
+ case EVENT_DISPOSE_HEART:
+ SetPhaseOne();
+ break;
+ }
}
-
- DoMeleeAttackIfReady();
}
- if (gravity_bomb_active)
+ void ExposeHeart()
{
- if (uiGravityBombAuraTimer <= diff)
- {
- if (Unit *pGravityBombTarget = me->GetUnit(*me, uiGravityBombTarget))
- {
- pGravityBombTarget->RemoveAurasDueToSpell(RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25));
- if (hardMode)
- {
- //Remains spawned for 3 minutes
- pGravityBombTarget->SummonCreature(NPC_VOID_ZONE, pGravityBombTarget->GetPositionX(), pGravityBombTarget->GetPositionY(), pGravityBombTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000);
- }
- }
+ //Make untargetable
+ //me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_6 | UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_UNK_15 | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
- gravity_bomb_active = false;
- uiGravityBombAuraTimer = TIMER_GRAVITY_BOMB_AURA;
- //gravityBomb();
- } else uiGravityBombAuraTimer -= diff;
- }
+ //DoCast(SPELL_SUBMERGE); -- Need proper kneel dummy
+ me->SetReactState(REACT_PASSIVE);
+ me->AddUnitState(UNIT_STAT_STUNNED);
- //Enrage stuff
- if (!enraged)
- {
- if (uiEnrageTimer <= diff)
+ Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : NULL;
+ if (heart)
{
- DoScriptText(SAY_BERSERK, me);
- DoCast(me, SPELL_ENRAGE);
- enraged = true;
- } else uiEnrageTimer -= diff;
- }
- }
+ heart->CastSpell(heart, SPELL_HEART_OVERLOAD, false);
+ heart->CastSpell(me, SPELL_HEART_LIGHTNING_TETHER, false);
+ heart->CastSpell(heart, SPELL_HEART_HEAL_TO_FULL, true);
+ heart->CastSpell(heart, SPELL_EXPOSED_HEART, false); // Channeled
+
+ //heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_UNK_15 | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_29);
+ heart->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+
+ }
- void exposeHeart()
- {
- //Make untargetable
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ // Start "end of phase 2 timer"
+ events.ScheduleEvent(EVENT_DISPOSE_HEART, TIMER_HEART_PHASE);
+
+ // Phase 2 has officially started
+ _phase = 2;
+ _heartExposed++;
- //Summon the heart npc
- me->SummonCreature(NPC_XT002_HEART, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 7, 0, TEMPSUMMON_TIMED_DESPAWN, TIMER_HEART_PHASE);
+ DoScriptText(SAY_HEART_OPENED, me);
+ }
- // Start "end of phase 2 timer"
- uiHeartPhaseTimer = TIMER_HEART_PHASE;
+ void SetPhaseOne()
+ {
+ DoScriptText(SAY_HEART_CLOSED, me);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
- //Phase 2 has offically started
- phase = 2;
- heart_exposed++;
+ //DoCast(SPELL_STAND);
+ me->SetReactState(REACT_AGGRESSIVE);
+ //me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->ClearUnitState(UNIT_STAT_STUNNED);
- //Reset the add spawning timer
- uiSpawnAddTimer = TIMER_SPAWN_ADD;
+ _phase = 1;
- DoScriptText(SAY_HEART_OPENED, me);
- }
+ events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2);
+ events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB);
+ events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX));
- void SetPhaseOne()
- {
- uiSearingLightTimer = TIMER_SEARING_LIGHT / 2;
- uiGravityBombTimer = TIMER_GRAVITY_BOMB;
- uiTympanicTantrumTimer = urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX);
- uiSpawnAddTimer = TIMER_SPAWN_ADD;
+ Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : NULL;
+ if (!heart)
+ return;
- if (!hardMode)
- me->ModifyHealth(-((int32)transferHealth));
+ heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- phase = 1;
- }
+ if (!hardMode)
+ {
+ if (!transferHealth)
+ transferHealth = (heart->GetMaxHealth() - heart->GetHealth());
- // TODO: put in comment and kept for reference. The spell should be fixed properly in spell system, if necessary.
- ////Have to do this the custom way since the original spell messes up player movement
- //void gravityBomb()
- //{
- // uint32 maxDamage = RAID_MODE(GRAVITY_BOMB_DMG_MAX_10, GRAVITY_BOMB_DMG_MAX_25);
- // uint32 minDamage = RAID_MODE(GRAVITY_BOMB_DMG_MIN_10, GRAVITY_BOMB_DMG_MIN_25);
- // uint16 range = GRAVITY_BOMB_RADIUS;
- // Map* pMap = me->GetMap();
- // if (pMap && pMap->IsDungeon())
- // {
- // Map::PlayerList const &PlayerList = pMap->GetPlayers();
- // for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
- // {
- // //If a player is within the range of the spell
- // if (i->getSource() && i->getSource()->GetDistance2d(pGravityBombTarget) <= range)
- // {
- // //Deal damage to the victim
- // int32 damage = urand(minDamage, maxDamage);
- // i->getSource()->ModifyHealth(-damage);
- // me->SendSpellNonMeleeDamageLog(i->getSource(), SPELL_GRAVITY_BOMB_AURA_10, damage, SPELL_SCHOOL_MASK_SHADOW, 0, 0, false, 0);
-
- // //Replacing the tractor beam effect
- // i->getSource()->JumpTo(pGravityBombTarget, 5);
- // }
- // }
- // }
- //}
- };
+ me->ModifyHealth(-((int32)transferHealth));
+ }
+ }
+ };
};
+
/*-------------------------------------------------------
*
* XT-002 HEART
@@ -537,36 +435,25 @@ public:
mob_xt002_heartAI(Creature* pCreature) : ScriptedAI(pCreature)
{
m_pInstance = pCreature->GetInstanceScript();
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- DoCast(me, SPELL_EXPOSED_HEART);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_PASSIVE);
}
InstanceScript* m_pInstance;
-
- void JustDied(Unit * /*victim*/)
- {
- if (m_pInstance)
- if (Creature* pXT002 = me->GetCreature(*me, m_pInstance->GetData64(BOSS_XT002)))
- if (pXT002->AI())
- pXT002->AI()->DoAction(ACTION_ENTER_HARD_MODE);
-
- //removes the aura
- me->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART);
- }
+ uint32 _damageTaken;
void DamageTaken(Unit * /*pDone*/, uint32 &damage)
{
- if (Creature* pXT002 = me->GetCreature(*me, m_pInstance->GetData64(BOSS_XT002)))
- if (pXT002->AI())
- {
- uint32 health = me->GetHealth();
- if (health <= damage)
- health = 0;
- else
- health -= damage;
- pXT002->AI()->SetData(DATA_TRANSFERED_HEALTH, me->GetMaxHealth() - health);
- }
+ Creature* XT002 = me->GetCreature(*me, m_pInstance->GetData64(BOSS_XT002));
+ if (!XT002 || !XT002->AI())
+ return;
+
+ if (damage >= me->GetHealth())
+ {
+ XT002->AI()->SetData(DATA_TRANSFERED_HEALTH, me->GetMaxHealth());
+ XT002->AI()->DoAction(ACTION_ENTER_HARD_MODE);
+ damage = 0;
+ }
}
};
@@ -601,7 +488,7 @@ public:
me->SetReactState(REACT_PASSIVE);
if (Creature* pXT002 = me->GetCreature(*me, m_pInstance->GetData64(BOSS_XT002)))
- me->GetMotionMaster()->MoveChase(pXT002);
+ me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f);
}
void UpdateAI(const uint32 /*diff*/)
@@ -719,12 +606,7 @@ public:
me->SetReactState(REACT_PASSIVE);
if (Creature* pXT002 = me->GetCreature(*me, m_pInstance->GetData64(BOSS_XT002)))
- me->GetMotionMaster()->MoveChase(pXT002);
- }
-
- void JustDied(Unit * /*killer*/)
- {
- DoCast(SPELL_BOOM);
+ me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f);
}
void UpdateAI(const uint32 /*diff*/)
@@ -745,68 +627,6 @@ public:
};
-/*-------------------------------------------------------
- *
- * VOID ZONE
- *
- *///----------------------------------------------------
-class mob_void_zone : public CreatureScript
-{
-public:
- mob_void_zone() : CreatureScript("mob_void_zone") { }
-
- CreatureAI* GetAI(Creature* pCreature) const
- {
- return new mob_void_zoneAI(pCreature);
- }
-
- struct mob_void_zoneAI : public ScriptedAI
- {
- mob_void_zoneAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- m_pInstance = pCreature->GetInstanceScript();
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
- }
-
- InstanceScript* m_pInstance;
- uint32 uiVoidZoneTimer;
-
- void Reset()
- {
- uiVoidZoneTimer = TIMER_VOID_ZONE;
- }
-
- void UpdateAI(const uint32 diff)
- {
- if (uiVoidZoneTimer <= diff)
- {
- //voidZone();
- uiVoidZoneTimer = TIMER_VOID_ZONE;
- } else uiVoidZoneTimer -= diff;
- }
-
- // TODO: put in comment and kept for reference. The spell should be fixed properly in spell system, if necessary.
- //void voidZone()
- //{
- // Map* pMap = me->GetMap();
- // if (pMap && pMap->IsDungeon())
- // {
- // Map::PlayerList const &PlayerList = pMap->GetPlayers();
- // for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
- // {
- // // If a player is within the range of the spell
- // if (i->getSource() && i->getSource()->GetDistance2d(me) <= 16)
- // {
- // // Deal damage to the victim
- // int32 damage = RAID_MODE(VOID_ZONE_DMG_10, VOID_ZONE_DMG_25);
- // me->DealDamage(i->getSource(), damage, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_SHADOW);
- // }
- // }
- // }
- //}
- };
-
-};
/*-------------------------------------------------------
*
@@ -858,13 +678,155 @@ public:
};
+class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader
+{
+ public:
+ spell_xt002_searing_light_spawn_life_spark() : SpellScriptLoader("spell_xt002_searing_light_spawn_life_spark") { }
+
+ class spell_xt002_searing_light_spawn_life_spark_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark_AuraScript);
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellStore.LookupEntry(SPELL_SUMMON_LIFE_SPARK))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (Player* plr = GetOwner()->ToPlayer())
+ if (Unit* xt002 = GetCaster())
+ if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode
+ plr->CastSpell(plr, SPELL_SUMMON_LIFE_SPARK, true);
+ }
+
+ void Register()
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_xt002_searing_light_spawn_life_spark_AuraScript();
+ }
+};
+
+class spell_xt002_gravity_bomb_spawn_void_zone : public SpellScriptLoader
+{
+ public:
+ spell_xt002_gravity_bomb_spawn_void_zone() : SpellScriptLoader("spell_xt002_gravity_bomb_spawn_void_zone") { }
+
+ class spell_xt002_gravity_bomb_spawn_void_zone_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_xt002_gravity_bomb_spawn_void_zone_AuraScript);
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellStore.LookupEntry(SPELL_SUMMON_VOID_ZONE))
+ return false;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (Player* plr = GetOwner()->ToPlayer())
+ if (Unit* xt002 = GetCaster())
+ if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode
+ plr->CastSpell(plr, SPELL_SUMMON_VOID_ZONE, true);
+ }
+
+ void Register()
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_spawn_void_zone_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_xt002_gravity_bomb_spawn_void_zone_AuraScript();
+ }
+};
+
+class spell_xt002_heart_overload_periodic : public SpellScriptLoader
+{
+ public:
+ spell_xt002_heart_overload_periodic() : SpellScriptLoader("spell_xt002_heart_overload_periodic") { }
+
+ class spell_xt002_heart_overload_periodic_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_xt002_heart_overload_periodic_SpellScript);
+
+ bool Validate(SpellEntry const* /*spell*/)
+ {
+ if (!sSpellStore.LookupEntry(SPELL_ENERGY_ORB))
+ return false;
+
+ if (!sSpellStore.LookupEntry(SPELL_RECHARGE_BOOMBOT))
+ return false;
+
+ if (!sSpellStore.LookupEntry(SPELL_RECHARGE_PUMMELER))
+ return false;
+
+ if (!sSpellStore.LookupEntry(SPELL_RECHARGE_SCRAPBOT))
+ return false;
+
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ if (InstanceScript* instance = GetCaster()->GetInstanceScript())
+ {
+ if (Unit* toyPile = ObjectAccessor::GetUnit(*caster, instance->GetData64(DATA_TOY_PILE_0 + urand(0, 3))))
+ {
+ caster->CastSpell(toyPile, SPELL_ENERGY_ORB, true);
+
+ // This should probably be incorporated in a dummy effect handler, but I've had trouble getting the correct target
+ // Weighed randomization (approximation)
+ uint32 const spells[] = { SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT,
+ SPELL_RECHARGE_PUMMELER, SPELL_RECHARGE_BOOMBOT };
+
+ for (uint8 i = 0; i < 5; ++i)
+ {
+ uint8 a = urand(0, 4);
+ uint32 spellId = spells[a];
+ toyPile->CastSpell(toyPile, spellId, true);
+ }
+ }
+ }
+
+ DoScriptText(SAY_SUMMON, caster->GetVehicleBase());
+ }
+ }
+
+ void Register()
+ {
+ OnEffect += SpellEffectFn(spell_xt002_heart_overload_periodic_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_xt002_heart_overload_periodic_SpellScript();
+ }
+};
+
void AddSC_boss_xt002()
{
new mob_xt002_heart();
new mob_scrapbot();
new mob_pummeller();
new mob_boombot();
- new mob_void_zone();
+
new mob_life_spark();
new boss_xt002();
+
+ new spell_xt002_searing_light_spawn_life_spark();
+ new spell_xt002_gravity_bomb_spawn_void_zone();
+ new spell_xt002_heart_overload_periodic();
}
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
index acccdcfcf26..9208842eae0 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
@@ -51,6 +51,7 @@ public:
uint64 RazorHarpoonGUIDs[4];
uint64 ExpeditionCommanderGUID;
uint64 XT002GUID;
+ uint64 XTToyPileGUIDs[4];
uint64 AssemblyGUIDs[3];
uint64 KologarnGUID;
uint64 LeftArmGUID;
@@ -117,6 +118,7 @@ public:
HodirRareCacheData = 0;
memset(Encounter, 0, sizeof(Encounter));
+ memset(XTToyPileGUIDs, 0, sizeof(XTToyPileGUIDs));
memset(AssemblyGUIDs, 0, sizeof(AssemblyGUIDs));
memset(RazorHarpoonGUIDs, 0, sizeof(RazorHarpoonGUIDs));
memset(KeeperGUIDs, 0, sizeof(KeeperGUIDs));
@@ -169,6 +171,11 @@ public:
case NPC_XT002:
XT002GUID = creature->GetGUID();
break;
+ case NPC_XT_TOY_PILE:
+ for (uint8 i = 0; i < 4; ++i)
+ if (!XTToyPileGUIDs[i])
+ XTToyPileGUIDs[i] = creature->GetGUID();
+ break;
// Assembly of Iron
case NPC_STEELBREAKER:
@@ -497,6 +504,11 @@ public:
return RazorscaleController;
case BOSS_XT002:
return XT002GUID;
+ case DATA_TOY_PILE_0:
+ case DATA_TOY_PILE_1:
+ case DATA_TOY_PILE_2:
+ case DATA_TOY_PILE_3:
+ return XTToyPileGUIDs[data - DATA_TOY_PILE_0];
case BOSS_KOLOGARN:
return KologarnGUID;
case DATA_LEFT_ARM:
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
index 2ddcea08ae6..6af8ad534b5 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
@@ -51,6 +51,12 @@ enum UlduarBosses
DATA_EXPEDITION_COMMANDER,
DATA_RAZORSCALE_CONTROL,
+ // XT-002
+ DATA_TOY_PILE_0,
+ DATA_TOY_PILE_1,
+ DATA_TOY_PILE_2,
+ DATA_TOY_PILE_3,
+
// Kologarn
DATA_LEFT_ARM,
DATA_RIGHT_ARM,
@@ -68,6 +74,7 @@ enum UlduarNPCs
NPC_STEELFORGED_DEFFENDER = 33236,
NPC_EXPEDITION_COMMANDER = 33210,
NPC_XT002 = 33293,
+ NPC_XT_TOY_PILE = 33337,
NPC_STEELBREAKER = 32867,
NPC_MOLGEIM = 32927,
NPC_BRUNDIR = 32857,