aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortreeston <treeston.mmoc@gmail.com>2016-03-23 20:17:17 +0100
committertreeston <treeston.mmoc@gmail.com>2016-03-23 20:17:17 +0100
commitf37682b7edd0d711e1120cbdd9d627fb5b9dbde1 (patch)
treece7725df07befb526c776010521de3e59dfa4770
parenta463a704f269da6db5bec604f043c9c484335ef3 (diff)
parentf4f7e6324d6c99335bf3479f212edea1e5572f88 (diff)
Merge branch '3.3.5-naxxcleanup' into 3.3.5. (PR #16524)
-rw-r--r--sql/updates/world/2016_03_23_00_world.sql164
-rw-r--r--src/server/game/Spells/Spell.cpp4
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp1
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp29
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp18
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp42
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp28
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp14
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp104
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp94
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp22
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_noth.cpp40
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp12
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp22
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp501
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp114
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp149
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h14
19 files changed, 841 insertions, 532 deletions
diff --git a/sql/updates/world/2016_03_23_00_world.sql b/sql/updates/world/2016_03_23_00_world.sql
new file mode 100644
index 00000000000..9195b652288
--- /dev/null
+++ b/sql/updates/world/2016_03_23_00_world.sql
@@ -0,0 +1,164 @@
+-- Naxxramas instance cleanup
+SET @OGUID = 5517; -- gameobject GUID (1 object) used for everything except heigan
+
+-- ======== --
+-- Faerlina --
+-- ======== --
+-- Move probability of SAY_SLAY to DB
+UPDATE `creature_text` SET `probability`=16 WHERE `entry`=15953 and `groupid`=2;
+
+-- ================== --
+-- Heigan the Unclean --
+-- ================== --
+-- Completely re-do eruption fissure spawns
+SET @OGUID2 = 84980; -- gameobject GUID (76 objects); needs to match the constant in boss_heigan.cpp
+DELETE FROM `gameobject` WHERE `id` between 181510 and 181552;
+INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`animprogress`,`state`,`VerifiedBuild`) VALUES
+ (@OGUID2+0,181510,533,3,1,2787.255000,-3654.130000,274.316700,3.534301,0.000000,0.000000,-0.980784,0.195095,0,0,1,15354),
+ (@OGUID2+1,181526,533,3,1,2781.556000,-3670.999000,274.351800,3.153633,0.000000,0.000000,-0.999982,0.006020,0,0,1,15354),
+ (@OGUID2+2,181511,533,3,1,2782.403000,-3660.402000,274.314800,2.110888,0.000000,0.000000,0.870119,0.492841,0,0,1,15354),
+ (@OGUID2+3,181517,533,3,1,2793.238000,-3664.132000,274.316700,0.635802,0.000000,0.000000,0.312573,0.949894,0,0,1,15354),
+ (@OGUID2+4,181518,533,3,1,2802.508000,-3664.726000,274.316700,0.635802,0.000000,0.000000,0.312573,0.949894,0,0,1,15354),
+ (@OGUID2+5,181523,533,3,1,2795.809000,-3677.562000,274.072800,2.853153,0.000000,0.000000,0.989618,0.143721,0,0,1,15354),
+ (@OGUID2+6,181519,533,3,1,2811.998000,-3671.979000,274.072800,5.809874,0.000000,0.000000,-0.234453,0.972127,0,0,1,15354),
+ (@OGUID2+7,181524,533,3,1,2792.327000,-3684.134000,274.316700,4.976158,0.000000,0.000000,-0.607980,0.793952,0,0,1,15354),
+ (@OGUID2+8,181520,533,3,1,2810.557000,-3680.581000,274.316700,3.186728,0.000000,0.000000,-0.999745,0.022566,0,0,1,15354),
+ (@OGUID2+9,181521,533,3,1,2800.146000,-3682.706000,274.351800,1.038823,0.000000,0.000000,0.496369,0.868111,0,0,1,15354),
+ (@OGUID2+10,181523,533,3,1,2795.809000,-3677.562000,274.072800,2.853153,0.000000,0.000000,0.989618,0.143721,0,0,1,15354),
+ (@OGUID2+11,181524,533,3,1,2792.327000,-3684.134000,274.316700,4.976158,0.000000,0.000000,-0.607980,0.793952,0,0,1,15354),
+ (@OGUID2+12,181520,533,3,1,2810.557000,-3680.581000,274.316700,3.186728,0.000000,0.000000,-0.999745,0.022566,0,0,1,15354),
+ (@OGUID2+13,181521,533,3,1,2800.146000,-3682.706000,274.351800,1.038823,0.000000,0.000000,0.496369,0.868111,0,0,1,15354),
+ (@OGUID2+14,181522,533,3,1,2805.961000,-3691.666000,274.316700,4.434372,0.000000,0.000000,-0.798264,0.602308,0,0,1,15354),
+
+ (@OGUID2+15,181515,533,3,1,2755.239000,-3649.898000,274.316700,3.396841,0.000000,0.000000,-0.991867,0.127278,0,0,1,15354),
+ (@OGUID2+16,181516,533,3,1,2763.548000,-3654.044000,274.316700,3.399228,0.000000,0.000000,-0.991715,0.128462,0,0,1,15354),
+ (@OGUID2+17,181531,533,3,1,2749.335000,-3662.211000,274.351800,3.636871,0.000000,0.000000,-0.969494,0.245116,0,0,1,15354),
+ (@OGUID2+18,181514,533,3,1,2757.844000,-3659.562000,274.316700,1.971156,0.000000,0.000000,0.833592,0.552381,0,0,1,15354),
+ (@OGUID2+19,181512,533,3,1,2778.426000,-3651.314000,274.316700,3.540596,0.000000,0.000000,-0.980166,0.198181,0,0,1,15354),
+ (@OGUID2+20,181516,533,3,1,2763.548000,-3654.044000,274.316700,3.399228,0.000000,0.000000,-0.991715,0.128462,0,0,1,15354),
+ (@OGUID2+21,181530,533,3,1,2758.163000,-3667.129000,274.351800,3.138830,0.000000,0.000000,0.999999,0.001381,0,0,1,15354),
+ (@OGUID2+22,181514,533,3,1,2757.844000,-3659.562000,274.316700,1.971156,0.000000,0.000000,0.833592,0.552381,0,0,1,15354),
+ (@OGUID2+23,181512,533,3,1,2778.426000,-3651.314000,274.316700,3.540596,0.000000,0.000000,-0.980166,0.198181,0,0,1,15354),
+ (@OGUID2+24,181529,533,3,1,2763.326000,-3680.528000,274.351800,3.146377,0.000000,0.000000,-0.999997,0.002392,0,0,1,15354),
+ (@OGUID2+25,181513,533,3,1,2774.297000,-3660.655000,274.316700,6.099252,0.000000,0.000000,-0.091837,0.995774,0,0,1,15354),
+ (@OGUID2+26,181528,533,3,1,2769.250000,-3671.420000,274.422200,5.859179,0.000000,0.000000,-0.210419,0.977611,0,0,1,15354),
+ (@OGUID2+27,181527,533,3,1,2777.413000,-3677.635000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354),
+ (@OGUID2+28,181527,533,3,1,2777.413000,-3677.635000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354),
+ (@OGUID2+29,181529,533,3,1,2763.326000,-3680.528000,274.351800,3.146377,0.000000,0.000000,-0.999997,0.002392,0,0,1,15354),
+ (@OGUID2+30,181525,533,3,1,2783.359000,-3688.357000,274.385100,3.161319,0.000000,0.000000,-0.999951,0.009863,0,0,1,15354),
+ (@OGUID2+31,181528,533,3,1,2769.250000,-3671.420000,274.422200,5.859179,0.000000,0.000000,-0.210419,0.977611,0,0,1,15354),
+ (@OGUID2+32,181528,533,3,1,2769.250000,-3671.420000,274.422200,5.859179,0.000000,0.000000,-0.210419,0.977611,0,0,1,15354),
+ (@OGUID2+33,181529,533,3,1,2763.326000,-3680.528000,274.351800,3.146377,0.000000,0.000000,-0.999997,0.002392,0,0,1,15354),
+ (@OGUID2+34,181516,533,3,1,2763.548000,-3654.044000,274.316700,3.399228,0.000000,0.000000,-0.991715,0.128462,0,0,1,15354),
+ (@OGUID2+35,181530,533,3,1,2758.163000,-3667.129000,274.351800,3.138830,0.000000,0.000000,0.999999,0.001381,0,0,1,15354),
+ (@OGUID2+36,181514,533,3,1,2757.844000,-3659.562000,274.316700,1.971156,0.000000,0.000000,0.833592,0.552381,0,0,1,15354),
+ (@OGUID2+37,181515,533,3,1,2755.239000,-3649.898000,274.316700,3.396841,0.000000,0.000000,-0.991867,0.127278,0,0,1,15354),
+ (@OGUID2+38,181531,533,3,1,2749.335000,-3662.211000,274.351800,3.636871,0.000000,0.000000,-0.969494,0.245116,0,0,1,15354),
+ (@OGUID2+39,181512,533,3,1,2778.426000,-3651.314000,274.316700,3.540596,0.000000,0.000000,-0.980166,0.198181,0,0,1,15354),
+
+ (@OGUID2+40,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354),
+ (@OGUID2+41,181534,533,3,1,2737.166000,-3675.165000,274.316700,4.369651,0.000000,0.000000,-0.817333,0.576165,0,0,1,15354),
+ (@OGUID2+42,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354),
+ (@OGUID2+43,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354),
+ (@OGUID2+44,181534,533,3,1,2737.166000,-3675.165000,274.316700,4.369651,0.000000,0.000000,-0.817333,0.576165,0,0,1,15354),
+ (@OGUID2+45,181536,533,3,1,2740.491000,-3692.128000,274.387000,0.792787,0.000000,0.000000,0.386094,0.922459,0,0,1,15354),
+ (@OGUID2+46,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354),
+ (@OGUID2+47,181535,533,3,1,2747.132000,-3684.353000,274.351800,3.132432,0.000000,0.000000,0.999989,0.004580,0,0,1,15354),
+ (@OGUID2+48,181541,533,3,1,2760.581000,-3688.306000,274.387000,0.412781,0.000000,0.000000,0.204928,0.978777,0,0,1,15354),
+ (@OGUID2+49,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354),
+ (@OGUID2+50,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354),
+ (@OGUID2+51,181544,533,3,1,2774.958000,-3701.132000,274.316700,0.523547,0.000000,0.000000,0.258794,0.965933,0,0,1,15354),
+ (@OGUID2+52,181543,533,3,1,2772.080000,-3692.152000,274.351800,5.018846,0.000000,0.000000,-0.590897,0.806747,0,0,1,15354),
+ (@OGUID2+53,181543,533,3,1,2772.080000,-3692.152000,274.351800,5.018846,0.000000,0.000000,-0.590897,0.806747,0,0,1,15354),
+ (@OGUID2+54,181544,533,3,1,2774.958000,-3701.132000,274.316700,0.523547,0.000000,0.000000,0.258794,0.965933,0,0,1,15354),
+ (@OGUID2+55,181542,533,3,1,2764.288000,-3698.094000,274.422200,5.490798,0.000000,0.000000,-0.385910,0.922536,0,0,1,15354),
+ (@OGUID2+56,181541,533,3,1,2760.581000,-3688.306000,274.387000,0.412781,0.000000,0.000000,0.204928,0.978777,0,0,1,15354),
+ (@OGUID2+57,181533,533,3,1,2754.007000,-3673.770000,274.387000,0.791340,0.000000,0.000000,0.385427,0.922739,0,0,1,15354),
+ (@OGUID2+58,181540,533,3,1,2752.924000,-3693.020000,274.316700,4.099892,0.000000,0.000000,-0.887387,0.461025,0,0,1,15354),
+ (@OGUID2+59,181536,533,3,1,2740.491000,-3692.128000,274.387000,0.792787,0.000000,0.000000,0.386094,0.922459,0,0,1,15354),
+ (@OGUID2+60,181532,533,3,1,2743.089000,-3671.320000,274.316700,2.464252,0.000000,0.000000,0.943197,0.332233,0,0,1,15354),
+ (@OGUID2+61,181534,533,3,1,2737.166000,-3675.165000,274.316700,4.369651,0.000000,0.000000,-0.817333,0.576165,0,0,1,15354),
+ (@OGUID2+62,181535,533,3,1,2747.132000,-3684.353000,274.351800,3.132432,0.000000,0.000000,0.999989,0.004580,0,0,1,15354),
+
+ (@OGUID2+63,181552,533,3,1,2784.168000,-3724.730000,274.385100,1.050844,0.000000,0.000000,0.501578,0.865112,0,0,1,15354),
+ (@OGUID2+64,181552,533,3,1,2784.168000,-3724.730000,274.385100,1.050844,0.000000,0.000000,0.501578,0.865112,0,0,1,15354),
+ (@OGUID2+65,181545,533,3,1,2772.289000,-3711.435000,274.422200,6.022432,0.000000,0.000000,-0.130008,0.991513,0,0,1,15354),
+ (@OGUID2+66,181549,533,3,1,2776.160000,-3721.793000,274.387000,3.937367,0.000000,0.000000,-0.921882,0.387472,0,0,1,15354),
+ (@OGUID2+67,181551,533,3,1,2774.989000,-3731.793000,274.387000,3.927917,0.000000,0.000000,-0.923702,0.383111,0,0,1,15354),
+ (@OGUID2+68,181548,533,3,1,2765.765000,-3718.734000,274.316700,4.807982,0.000000,0.000000,-0.672515,0.740084,0,0,1,15354),
+ (@OGUID2+69,181546,533,3,1,2761.821000,-3711.915000,274.314800,3.961473,0.000000,0.000000,-0.917145,0.398554,0,0,1,15354),
+ (@OGUID2+70,181550,533,3,1,2765.327000,-3728.606000,274.314800,6.217947,0.000000,0.000000,-0.032614,0.999468,0,0,1,15354),
+ (@OGUID2+71,181547,533,3,1,2754.189000,-3718.121000,274.316700,5.370356,0.000000,0.000000,-0.440733,0.897638,0,0,1,15354),
+ (@OGUID2+72,181538,533,3,1,2752.927000,-3706.516000,274.316700,1.047839,0.000000,0.000000,0.500278,0.865865,0,0,1,15354),
+ (@OGUID2+73,181537,533,3,1,2738.396000,-3703.130000,274.385100,5.746106,0.000000,0.000000,-0.265324,0.964159,0,0,1,15354),
+ (@OGUID2+74,181539,533,3,1,2746.133000,-3700.192000,274.316700,5.493282,0.000000,0.000000,-0.384764,0.923015,0,0,1,15354),
+ (@OGUID2+75,181549,533,3,1,2776.160000,-3721.793000,274.387000,3.937367,0.000000,0.000000,-0.921882,0.387472,0,0,1,15354);
+
+
+
+-- ======= --
+-- Loatheb --
+-- ======= --
+-- Get rid of the superfluous aurascript for a dummy that's just there to make him talk
+DELETE FROM `spell_script_names` WHERE `scriptname`="spell_loatheb_necrotic_aura_warning";
+
+-- ======== --
+-- Thaddius --
+-- ======== --
+-- Move UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE (thaddius' base state) to creature_template instead of applying it in script
+UPDATE `creature_template` SET `unit_flags`=33554688 WHERE `entry`=15928;
+-- Move inactive aura to creature_template_addon
+DELETE FROM `creature_template_addon` WHERE entry = 15928;
+INSERT INTO `creature_template_addon` (`entry`,`auras`) VALUES (15928,"28160");
+
+-- ==================== --
+-- Instructor Razuvious --
+-- ==================== --
+-- Razuvious has been informed that Rubik's Cubes become noticably easier to solve if you buy six-colored ones.
+-- Thus, he will no longer take out his frustration on raid groups by throwing unsolved two-colored variants at them.
+UPDATE `creature_equip_template` SET `itemid3`=29010 WHERE `creatureid`=16061;
+DELETE FROM `spell_custom_attr` WHERE `entry`=55550;
+INSERT INTO `spell_custom_attr` (`entry`,`attributes`) VALUES
+(55550,524288);
+-- Also, give his understudies actual weaponry. The poor sods.
+DELETE FROM `creature_equip_template` WHERE `CreatureID`=16803;
+INSERT INTO `creature_equip_template` (`CreatureID`,`ItemID1`,`ItemID2`,`VerifiedBuild`) VALUES
+(16803,2180,23356,"15354");
+
+-- ================= --
+-- The Four Horsemen --
+-- ================= --
+-- Wanna hear something fun?
+-- On the current core, you can shackle, daze, stun (and some others) Baron Rivendare.
+-- Yes, only Baron Rivendare. The other Horsemen are fine. Why? I have no idea.
+-- Fixing that.
+UPDATE `creature_template` SET `mechanic_immune_mask`=617299803 WHERE `entry` in (16063,16064,16065,30549);
+
+-- ========= --
+-- Sapphiron --
+-- ========= --
+DELETE FROM `spell_script_names` WHERE `spell_id` in (24780,28522,28524,28560);
+INSERT INTO `spell_script_names` (`spell_id`,`scriptname`) VALUES
+(24780,"spell_sapphiron_change_blizzard_target"), -- Periodic aura on the Blizzard npc that handles target switches
+(28522,"spell_sapphiron_icebolt"), -- AuraScript for spawning ice block GO once the player has stopped moving
+(28524,"spell_sapphiron_frost_breath"), -- We can't get rid of the LoS emulation "hack" on frost breath targeting (yet!), but at least moving it to a spellscript...
+(28560,"spell_sapphiron_summon_blizzard"); -- Blizzard is now properly summoned! Yay!
+-- DB target position for the anti-cheese frost explosion
+DELETE FROM `spell_target_position` WHERE `ID`=29318;
+INSERT INTO `spell_target_position` (`ID`,`EffectIndex`,`MapID`,`PositionX`,`PositionY`,`PositionZ`,`VerifiedBuild`) VALUES
+(29318,0,533,3493.45,-5375.38,138.168,"15595");
+-- Wing Buffet trigger NPC
+UPDATE `creature_template` SET `unit_flags`=33554944,`unit_flags2`=2048,`flags_extra`=128,`spell1`=29328,`BaseAttackTime`=1000,`ScriptName`="trigger_periodic" WHERE `entry`=17025;
+-- Blizzard bunny NPC
+UPDATE `creature_template` SET `speed_run`=0.42857142,`BaseAttackTime`=3000,`InhabitType`=1 WHERE `entry`=16474;
+DELETE FROM `creature_template_addon` WHERE `entry`=16474;
+INSERT INTO `creature_template_addon` (`entry`,`auras`) VALUES (16474,"24780");
+-- Spawn GO is now spawned by DB
+DELETE FROM `gameobject` WHERE `guid` between @OGUID+0 and @OGUID+0;
+INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`phaseMask`,`position_x`,`position_y`,`position_z`,`orientation`,`rotation0`,`rotation1`,`rotation2`,`rotation3`,`spawntimesecs`,`VerifiedBuild`) VALUES
+(@OGUID+0, 181356, 533, 3, 1, 3522.565, -5236.76, 137.6257, 4.485497, 0, 0, -0.782608, 0.6225148,0,0);
+UPDATE `gameobject_template` SET `ScriptName`="go_sapphiron_birth" WHERE `entry`=181356;
+-- Turn off interactivity on ice blocks
+UPDATE `gameobject_template` SET `type`=5,`data2`=0 WHERE `entry`=181247;
+-- Text cleanup
+UPDATE `creature_text` SET `language`=0, `emote`=0, `textrange`=3 WHERE `entry`=15989;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 06e416d77f2..b2fb2766fb0 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -3811,7 +3811,7 @@ void Spell::SendSpellStart()
if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_PENDING;
- if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA))
castFlags |= CAST_FLAG_AMMO;
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
@@ -3864,7 +3864,7 @@ void Spell::SendSpellGo()
if ((IsTriggered() && !m_spellInfo->IsAutoRepeatRangedSpell()) || m_triggeredByAuraSpell)
castFlags |= CAST_FLAG_PENDING;
- if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO))
+ if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA))
castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index ba658c885fa..34208f268bd 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -187,6 +187,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000,
+ SPELL_ATTR0_CU_NEEDS_AMMO_DATA = 0x00080000,
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
};
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 8bb0e401a6c..635a545bd5b 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3056,6 +3056,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 48246: // Ball of Flame
case 36327: // Shoot Arcane Explosion Arrow
case 55479: // Force Obedience
+ case 28560: // Summon Blizzard (Sapphiron)
spellInfo->MaxAffectedTargets = 1;
break;
case 36384: // Skartax Purple Beam
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
index e8c4216b00e..60c60640c04 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
@@ -162,13 +162,13 @@ public:
summons.DoZoneInCombat();
events.SetPhase(PHASE_NORMAL);
- events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
- events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL);
- events.ScheduleEvent(EVENT_LOCUST, urand(80,120) * IN_MILLISECONDS, 0, PHASE_NORMAL);
- events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_IMPALE, randtime(Seconds(10), Seconds(20)), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_SCARABS, randtime(Seconds(20), Seconds(30)), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_LOCUST, Minutes(1)+randtime(Seconds(40), Seconds(60)), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
if (!Is25ManRaid())
- events.ScheduleEvent(EVENT_SPAWN_GUARD, urand(15, 20) * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SPAWN_GUARD, randtime(Seconds(15), Seconds(20)));
}
void UpdateAI(uint32 diff) override
@@ -189,11 +189,9 @@ public:
else
EnterEvadeMode();
- events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
+ events.Repeat(randtime(Seconds(10), Seconds(20)));
break;
case EVENT_SCARABS:
- events.ScheduleEvent(EVENT_SCARABS, urand(40 * IN_MILLISECONDS, 60 * IN_MILLISECONDS), 0, PHASE_NORMAL);
-
if (!guardCorpses.empty())
{
if (ObjectGuid target = Trinity::Containers::SelectRandomContainerElement(guardCorpses))
@@ -204,27 +202,28 @@ public:
creatureTarget->DespawnOrUnsummon();
}
}
+ events.Repeat(randtime(Seconds(40), Seconds(60)));
break;
case EVENT_LOCUST:
Talk(EMOTE_LOCUST);
+ events.SetPhase(PHASE_SWARM);
DoCast(me, SPELL_LOCUST_SWARM);
- events.ScheduleEvent(EVENT_SPAWN_GUARD, 3 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(19, 23) * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_LOCUST, 90000);
- events.SetPhase(PHASE_SWARM);
+ events.ScheduleEvent(EVENT_SPAWN_GUARD, Seconds(3));
+ events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(Seconds(19), Seconds(23)));
+ events.Repeat(Minutes(1)+Seconds(30));
break;
case EVENT_LOCUST_ENDS:
- events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
- events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL);
events.SetPhase(PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_IMPALE, randtime(Seconds(10), Seconds(20)), 0, PHASE_NORMAL);
+ events.ScheduleEvent(EVENT_SCARABS, randtime(Seconds(20), Seconds(30)), 0, PHASE_NORMAL);
break;
case EVENT_SPAWN_GUARD:
me->SummonCreatureGroup(GROUP_SINGLE_SPAWN);
break;
case EVENT_BERSERK:
DoCast(me, SPELL_BERSERK, true);
- events.ScheduleEvent(EVENT_BERSERK, 600000);
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
break;
}
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
index 39c41c935bf..8a7bdd293ba 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp
@@ -100,9 +100,9 @@ class boss_faerlina : public CreatureScript
_EnterCombat();
Talk(SAY_AGGRO);
summons.DoZoneInCombat();
- events.ScheduleEvent(EVENT_POISON, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
- events.ScheduleEvent(EVENT_FIRE, urand(6 * IN_MILLISECONDS, 18 * IN_MILLISECONDS));
- events.ScheduleEvent(EVENT_FRENZY, urand(60 * IN_MILLISECONDS, 80 * IN_MILLISECONDS));
+ events.ScheduleEvent(EVENT_POISON, randtime(Seconds(10), Seconds(15)));
+ events.ScheduleEvent(EVENT_FIRE, randtime(Seconds(6), Seconds(18)));
+ events.ScheduleEvent(EVENT_FRENZY, Minutes(1)+randtime(Seconds(0), Seconds(20)));
}
void Reset() override
@@ -111,9 +111,9 @@ class boss_faerlina : public CreatureScript
_frenzyDispels = 0;
}
- void KilledUnit(Unit* /*victim*/) override
+ void KilledUnit(Unit* victim) override
{
- if (!urand(0, 2))
+ if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
@@ -158,21 +158,21 @@ class boss_faerlina : public CreatureScript
case EVENT_POISON:
if (!me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER))
DoCastAOE(SPELL_POISON_BOLT_VOLLEY);
- events.ScheduleEvent(EVENT_POISON, urand(8000, 15000));
+ events.Repeat(randtime(Seconds(8), Seconds(15)));
break;
case EVENT_FIRE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_RAIN_OF_FIRE);
- events.ScheduleEvent(EVENT_FIRE, urand(6000, 18000));
+ events.Repeat(randtime(Seconds(6), Seconds(18)));
break;
case EVENT_FRENZY:
if (Aura* widowsEmbrace = me->GetAura(SPELL_WIDOWS_EMBRACE_HELPER))
- events.ScheduleEvent(EVENT_FRENZY, widowsEmbrace->GetDuration()+1 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_FRENZY, Milliseconds(widowsEmbrace->GetDuration()+1));
else
{
DoCast(SPELL_FRENZY);
Talk(EMOTE_FRENZY);
- events.ScheduleEvent(EVENT_FRENZY, urand(60 * IN_MILLISECONDS, 80 * IN_MILLISECONDS));
+ events.Repeat(Minutes(1) + randtime(Seconds(0), Seconds(20)));
}
break;
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp
index a7a89f44d81..0de1c4785b8 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp
@@ -285,7 +285,7 @@ struct boss_four_horsemen_baseAI : public BossAI
void EnterCombat(Unit* /*who*/) override
{
- if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED) // another horseman already did it
+ if (instance->GetBossState(BOSS_HORSEMEN) == IN_PROGRESS || instance->GetBossState(BOSS_HORSEMEN) == DONE) // another horseman already did it
return;
Talk(SAY_AGGRO);
BeginEncounter();
@@ -411,9 +411,9 @@ class boss_four_horsemen_baron : public CreatureScript
else
AttackStart(threat.getHostilTarget());
- events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(3,7));
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
+ events.ScheduleEvent(EVENT_MARK, Seconds(24));
+ events.ScheduleEvent(EVENT_UNHOLYSHADOW, randtime(Seconds(3), Seconds(7)));
}
void _UpdateAI(uint32 diff) override
@@ -431,11 +431,11 @@ class boss_four_horsemen_baron : public CreatureScript
break;
case EVENT_MARK:
DoCastAOE(SPELL_BARON_MARK, true);
- events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS);
+ events.Repeat(Seconds(12));
break;
case EVENT_UNHOLYSHADOW:
DoCastVictim(SPELL_UNHOLY_SHADOW);
- events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(10,30));
+ events.Repeat(randtime(Seconds(10), Seconds(30)));
break;
}
}
@@ -484,9 +484,9 @@ class boss_four_horsemen_thane : public CreatureScript
else
AttackStart(threat.getHostilTarget());
- events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_METEOR, urandms(10,15));
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
+ events.ScheduleEvent(EVENT_MARK, Seconds(24));
+ events.ScheduleEvent(EVENT_METEOR, randtime(Seconds(10), Seconds(25)));
}
void _UpdateAI(uint32 diff) override
{
@@ -503,7 +503,7 @@ class boss_four_horsemen_thane : public CreatureScript
break;
case EVENT_MARK:
DoCastAOE(SPELL_THANE_MARK, true);
- events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS);
+ events.Repeat(Seconds(12));
break;
case EVENT_METEOR:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true))
@@ -511,7 +511,7 @@ class boss_four_horsemen_thane : public CreatureScript
DoCast(target, SPELL_METEOR);
_shouldSay = true;
}
- events.ScheduleEvent(EVENT_METEOR, urandms(13,17));
+ events.Repeat(randtime(Seconds(13), Seconds(17)));
break;
}
}
@@ -550,9 +550,9 @@ class boss_four_horsemen_lady : public CreatureScript
boss_four_horsemen_ladyAI(Creature* creature) : boss_four_horsemen_baseAI(creature, LADY, ladyPath) { }
void BeginFighting() override
{
- events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_VOIDZONE, urandms(5,10));
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
+ events.ScheduleEvent(EVENT_MARK, Seconds(24));
+ events.ScheduleEvent(EVENT_VOIDZONE, randtime(Seconds(5), Seconds(10)));
}
void _UpdateAI(uint32 diff) override
@@ -578,7 +578,7 @@ class boss_four_horsemen_lady : public CreatureScript
break;
case EVENT_MARK:
DoCastAOE(SPELL_LADY_MARK, true);
- events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS);
+ events.Repeat(Seconds(15));
break;
case EVENT_VOIDZONE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
@@ -586,7 +586,7 @@ class boss_four_horsemen_lady : public CreatureScript
DoCast(target, SPELL_VOID_ZONE, true);
Talk(SAY_SPECIAL);
}
- events.ScheduleEvent(EVENT_VOIDZONE, urandms(12, 18));
+ events.Repeat(randtime(Seconds(12), Seconds(18)));
break;
}
}
@@ -620,9 +620,9 @@ class boss_four_horsemen_sir : public CreatureScript
boss_four_horsemen_sirAI(Creature* creature) : boss_four_horsemen_baseAI(creature, SIR, sirPath), _shouldSay(true) { }
void BeginFighting() override
{
- events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_HOLYWRATH, urandms(13,18));
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
+ events.ScheduleEvent(EVENT_MARK, Seconds(24));
+ events.ScheduleEvent(EVENT_HOLYWRATH, randtime(Seconds(13), Seconds(18)));
}
void _UpdateAI(uint32 diff) override
@@ -648,7 +648,7 @@ class boss_four_horsemen_sir : public CreatureScript
break;
case EVENT_MARK:
DoCastAOE(SPELL_SIR_MARK, true);
- events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS);
+ events.Repeat(Seconds(15));
break;
case EVENT_HOLYWRATH:
if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 45.0f, true))
@@ -656,7 +656,7 @@ class boss_four_horsemen_sir : public CreatureScript
DoCast(target, SPELL_HOLY_WRATH, true);
_shouldSay = true;
}
- events.ScheduleEvent(EVENT_HOLYWRATH, urandms(10,18));
+ events.Repeat(randtime(Seconds(10), Seconds(18)));
break;
}
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
index cf083900e8b..30c05c9dca9 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp
@@ -324,13 +324,13 @@ class boss_gothik : public CreatureScript
{
_EnterCombat();
events.SetPhase(PHASE_ONE);
- events.ScheduleEvent(EVENT_SUMMON, 25 * IN_MILLISECONDS, 0, PHASE_ONE);
- events.ScheduleEvent(EVENT_DOORS_UNLOCK, 205 * IN_MILLISECONDS, 0, PHASE_ONE);
- events.ScheduleEvent(EVENT_PHASE_TWO, 270 * IN_MILLISECONDS, 0, PHASE_ONE);
+ events.ScheduleEvent(EVENT_SUMMON, Seconds(25), 0, PHASE_ONE);
+ events.ScheduleEvent(EVENT_DOORS_UNLOCK, Minutes(3) + Seconds(25), 0, PHASE_ONE);
+ events.ScheduleEvent(EVENT_PHASE_TWO, Minutes(4) + Seconds(30), 0, PHASE_ONE);
Talk(SAY_INTRO_1);
- events.ScheduleEvent(EVENT_INTRO_2, 4 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_INTRO_3, 9 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_INTRO_4, 14 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_INTRO_2, Seconds(4));
+ events.ScheduleEvent(EVENT_INTRO_3, Seconds(9));
+ events.ScheduleEvent(EVENT_INTRO_4, Seconds(14));
instance->SetData(DATA_GOTHIK_GATE, GO_STATE_READY);
_gateIsOpen = false;
}
@@ -480,7 +480,7 @@ class boss_gothik : public CreatureScript
}
if (uint8 timeToNext = RAID_MODE(waves10, waves25)[_waveCount].second)
- events.ScheduleEvent(EVENT_SUMMON, timeToNext * IN_MILLISECONDS, 0, PHASE_ONE);
+ events.Repeat(Seconds(timeToNext));
++_waveCount;
break;
@@ -497,9 +497,9 @@ class boss_gothik : public CreatureScript
break;
case EVENT_PHASE_TWO:
events.SetPhase(PHASE_TWO);
- events.ScheduleEvent(EVENT_TELEPORT, 20 * IN_MILLISECONDS, 0, PHASE_TWO);
- events.ScheduleEvent(EVENT_HARVEST, 15 * IN_MILLISECONDS, 0, PHASE_TWO);
- events.ScheduleEvent(EVENT_RESUME_ATTACK, 2 * IN_MILLISECONDS, 0, PHASE_TWO);
+ events.ScheduleEvent(EVENT_TELEPORT, Seconds(20), 0, PHASE_TWO);
+ events.ScheduleEvent(EVENT_HARVEST, Seconds(15), 0, PHASE_TWO);
+ events.ScheduleEvent(EVENT_RESUME_ATTACK, Seconds(2), 0, PHASE_TWO);
Talk(SAY_PHASE_TWO);
Talk(EMOTE_PHASE_TWO);
me->SetReactState(REACT_PASSIVE);
@@ -518,23 +518,23 @@ class boss_gothik : public CreatureScript
_lastTeleportDead = !_lastTeleportDead;
events.CancelEvent(EVENT_BOLT);
- events.ScheduleEvent(EVENT_TELEPORT, 20 * IN_MILLISECONDS, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_RESUME_ATTACK, 2 * IN_MILLISECONDS, 0, PHASE_TWO);
+ events.Repeat(Seconds(20));
}
break;
case EVENT_HARVEST:
DoCastAOE(SPELL_HARVEST_SOUL, true); // triggered allows this to go "through" shadow bolt
- events.ScheduleEvent(EVENT_HARVEST, 15 * IN_MILLISECONDS, 0, PHASE_TWO);
+ events.Repeat(Seconds(15));
break;
case EVENT_RESUME_ATTACK:
me->SetReactState(REACT_AGGRESSIVE);
- events.ScheduleEvent(EVENT_BOLT, 0, 0, PHASE_TWO);
+ events.ScheduleEvent(EVENT_BOLT, Seconds(0), 0, PHASE_TWO);
// return to the start of this method so victim side etc is re-evaluated
return UpdateAI(0u); // tail recursion for efficiency
case EVENT_BOLT:
DoCastVictim(SPELL_SHADOW_BOLT);
- events.ScheduleEvent(EVENT_BOLT, 1 * IN_MILLISECONDS, 0, PHASE_TWO);
+ events.Repeat(Seconds(2));
break;
case EVENT_INTRO_2:
Talk(SAY_INTRO_2);
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
index a1d8f6e5e02..cf38d659d40 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp
@@ -57,10 +57,10 @@ class boss_grobbulus : public CreatureScript
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- events.ScheduleEvent(EVENT_CLOUD, 15000);
- events.ScheduleEvent(EVENT_INJECT, 20000);
- events.ScheduleEvent(EVENT_SPRAY, urand(15000, 30000)); // not sure
- events.ScheduleEvent(EVENT_BERSERK, 12 * 60000);
+ events.ScheduleEvent(EVENT_CLOUD, Seconds(15));
+ events.ScheduleEvent(EVENT_INJECT, Seconds(20));
+ events.ScheduleEvent(EVENT_SPRAY, randtime(Seconds(15), Seconds(30))); // not sure
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(12));
}
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
@@ -82,19 +82,19 @@ class boss_grobbulus : public CreatureScript
{
case EVENT_CLOUD:
DoCastAOE(SPELL_POISON_CLOUD);
- events.ScheduleEvent(EVENT_CLOUD, 15000);
+ events.Repeat(Seconds(15));
return;
case EVENT_BERSERK:
DoCastAOE(SPELL_BERSERK, true);
return;
case EVENT_SPRAY:
DoCastAOE(SPELL_SLIME_SPRAY);
- events.ScheduleEvent(EVENT_SPRAY, urand(15000, 30000));
+ events.Repeat(randtime(Seconds(15), Seconds(30)));
return;
case EVENT_INJECT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_MUTATING_INJECTION))
DoCast(target, SPELL_MUTATING_INJECTION);
- events.ScheduleEvent(EVENT_INJECT, 8000 + uint32(120 * me->GetHealthPct()));
+ events.Repeat(Seconds(8) + Milliseconds(uint32(std::round(120 * me->GetHealthPct()))));
return;
default:
break;
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
index 9b9619fe5b9..41d718d188d 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
@@ -27,6 +27,7 @@ enum Spells
SPELL_SPELL_DISRUPTION = 29310,
SPELL_PLAGUE_CLOUD = 29350,
SPELL_TELEPORT_SELF = 30211,
+ SPELL_ERUPTION = 29371
};
enum Yells
@@ -60,6 +61,15 @@ enum Misc
DATA_SAFETY_DANCE = 19962139
};
+static const uint32 firstEruptionDBGUID = 84980;
+static const uint8 numSections = 4;
+static const uint8 numEruptions[numSections] = { // count of sequential GO DBGUIDs in the respective section of the room
+ 15,
+ 25,
+ 23,
+ 13
+};
+
class boss_heigan : public CreatureScript
{
public:
@@ -72,7 +82,7 @@ public:
struct boss_heiganAI : public BossAI
{
- boss_heiganAI(Creature* creature) : BossAI(creature, BOSS_HEIGAN), eruptSection(0), eruptDirection(false), safetyDance(false) { }
+ boss_heiganAI(Creature* creature) : BossAI(creature, BOSS_HEIGAN), _safeSection(0), _danceDirection(false), _safetyDance(false) { }
void Reset() override
{
@@ -82,15 +92,16 @@ public:
void KilledUnit(Unit* who) override
{
- Talk(SAY_SLAY);
-
if (who->GetTypeId() == TYPEID_PLAYER)
- safetyDance = false;
+ {
+ Talk(SAY_SLAY);
+ _safetyDance = false;
+ }
}
uint32 GetData(uint32 type) const override
{
- return (type == DATA_SAFETY_DANCE && safetyDance) ? 1u : 0u;
+ return (type == DATA_SAFETY_DANCE && _safetyDance) ? 1u : 0u;
}
void JustDied(Unit* /*killer*/) override
@@ -104,13 +115,27 @@ public:
_EnterCombat();
Talk(SAY_AGGRO);
- eruptSection = 3;
- events.ScheduleEvent(EVENT_DISRUPT, urand(15 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_FIGHT);
- events.ScheduleEvent(EVENT_FEVER, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_FIGHT);
- events.ScheduleEvent(EVENT_DANCE, 90 * IN_MILLISECONDS, 0, PHASE_FIGHT);
- events.ScheduleEvent(EVENT_ERUPT, 15 * IN_MILLISECONDS, 0, PHASE_FIGHT);
+ _safeSection = 0;
+ events.ScheduleEvent(EVENT_DISRUPT, randtime(Seconds(15), Seconds(20)), 0, PHASE_FIGHT);
+ events.ScheduleEvent(EVENT_FEVER, randtime(Seconds(10), Seconds(20)), 0, PHASE_FIGHT);
+ events.ScheduleEvent(EVENT_DANCE, Minutes(1) + Seconds(30), 0, PHASE_FIGHT);
+ events.ScheduleEvent(EVENT_ERUPT, Seconds(15), 0, PHASE_FIGHT);
+
+ _safetyDance = true;
- safetyDance = true;
+ // figure out the current GUIDs of our eruption tiles and which segment they belong in
+ std::unordered_multimap<uint32, GameObject*> const& mapGOs = me->GetMap()->GetGameObjectBySpawnIdStore();
+ uint32 spawnId = firstEruptionDBGUID;
+ for (uint8 section = 0; section < numSections; ++section)
+ {
+ _eruptTiles[section].clear();
+ for (uint8 i = 0; i < numEruptions[section]; ++i)
+ {
+ std::pair<std::unordered_multimap<uint32, GameObject*>::const_iterator, std::unordered_multimap<uint32, GameObject*>::const_iterator> tileIt = mapGOs.equal_range(spawnId++);
+ for (std::unordered_multimap<uint32, GameObject*>::const_iterator it = tileIt.first; it != tileIt.second; ++it)
+ _eruptTiles[section].push_back(it->second->GetGUID());
+ }
+ }
}
void UpdateAI(uint32 diff) override
@@ -126,52 +151,56 @@ public:
{
case EVENT_DISRUPT:
DoCastAOE(SPELL_SPELL_DISRUPTION);
- events.ScheduleEvent(EVENT_DISRUPT, 11 * IN_MILLISECONDS);
+ events.Repeat(Seconds(11));
break;
case EVENT_FEVER:
DoCastAOE(SPELL_DECREPIT_FEVER);
- events.ScheduleEvent(EVENT_FEVER, urand(20 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
+ events.Repeat(randtime(Seconds(20), Seconds(25)));
break;
case EVENT_DANCE:
events.SetPhase(PHASE_DANCE);
Talk(SAY_TAUNT);
Talk(EMOTE_DANCE);
- eruptSection = 3;
+ _safeSection = 0;
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->StopMoving();
DoCast(SPELL_TELEPORT_SELF);
DoCastAOE(SPELL_PLAGUE_CLOUD);
- events.ScheduleEvent(EVENT_DANCE_END, 45 * IN_MILLISECONDS, 0, PHASE_DANCE);
- events.ScheduleEvent(EVENT_ERUPT, 10 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_DANCE_END, Seconds(45), 0, PHASE_DANCE);
+ events.ScheduleEvent(EVENT_ERUPT, Seconds(10));
break;
case EVENT_DANCE_END:
events.SetPhase(PHASE_FIGHT);
Talk(EMOTE_DANCE_END);
- eruptSection = 3;
- events.ScheduleEvent(EVENT_DISRUPT, urand(10, 25) * IN_MILLISECONDS, 0, PHASE_FIGHT);
- events.ScheduleEvent(EVENT_FEVER, urand(15, 20) * IN_MILLISECONDS, 0, PHASE_FIGHT);
- events.ScheduleEvent(EVENT_DANCE, 90 * IN_MILLISECONDS, 0, PHASE_FIGHT);
- events.ScheduleEvent(EVENT_ERUPT, 15 * IN_MILLISECONDS, 0, PHASE_FIGHT);
+ _safeSection = 0;
+ events.ScheduleEvent(EVENT_DISRUPT, randtime(Seconds(10), Seconds(25)), 0, PHASE_FIGHT);
+ events.ScheduleEvent(EVENT_FEVER, randtime(Seconds(15), Seconds(20)), 0, PHASE_FIGHT);
+ events.ScheduleEvent(EVENT_DANCE, Minutes(1) + Seconds(30), 0, PHASE_FIGHT);
+ events.ScheduleEvent(EVENT_ERUPT, Seconds(15), 0, PHASE_FIGHT);
me->CastStop();
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
break;
case EVENT_ERUPT:
- instance->SetData(DATA_HEIGAN_ERUPT, eruptSection);
TeleportCheaters();
-
- if (eruptSection == 0)
- eruptDirection = true;
- else if (eruptSection == 3)
- eruptDirection = false;
-
- eruptDirection ? ++eruptSection : --eruptSection;
-
- if (events.IsInPhase(PHASE_DANCE))
- events.ScheduleEvent(EVENT_ERUPT, 3 * IN_MILLISECONDS, 0, PHASE_DANCE);
- else
- events.ScheduleEvent(EVENT_ERUPT, 10 * IN_MILLISECONDS, 0, PHASE_FIGHT);
+ for (uint8 section = 0; section < numSections; ++section)
+ if (section != _safeSection)
+ for (ObjectGuid tileGUID : _eruptTiles[section])
+ if (GameObject* tile = ObjectAccessor::GetGameObject(*me, tileGUID))
+ {
+ tile->SendCustomAnim(0);
+ tile->CastSpell(nullptr, SPELL_ERUPTION);
+ }
+
+ if (_safeSection == 0)
+ _danceDirection = true;
+ else if (_safeSection == numSections-1)
+ _danceDirection = false;
+
+ _danceDirection ? ++_safeSection : --_safeSection;
+
+ events.Repeat(events.IsInPhase(PHASE_DANCE) ? Seconds(3) : Seconds(10));
break;
}
}
@@ -180,10 +209,11 @@ public:
}
private:
- uint32 eruptSection;
- bool eruptDirection;
+ std::vector<ObjectGuid> _eruptTiles[numSections]; // populated on encounter start
- bool safetyDance; // is achievement still possible? (= no player deaths yet)
+ uint32 _safeSection; // 0 is next to the entrance
+ bool _danceDirection; // true is counter-clockwise, false is clock-wise
+ bool _safetyDance; // is achievement still possible? (= no player deaths yet)
};
};
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
index 086d21120e8..c6c9c76bed4 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp
@@ -24,7 +24,6 @@
enum Spells
{
SPELL_NECROTIC_AURA = 55593,
- SPELL_WARN_NECROTIC_AURA = 59481,
SPELL_SUMMON_SPORE = 29234,
SPELL_DEATHBLOOM = 29865,
SPELL_INEVITABLE_DOOM = 29204,
@@ -42,11 +41,12 @@ enum Texts
enum Events
{
- EVENT_NECROTIC_AURA = 1,
- EVENT_DEATHBLOOM = 2,
- EVENT_INEVITABLE_DOOM = 3,
- EVENT_SPORE = 4,
- EVENT_NECROTIC_AURA_FADING = 5,
+ EVENT_NECROTIC_AURA = 1,
+ EVENT_DEATHBLOOM,
+ EVENT_INEVITABLE_DOOM,
+ EVENT_SPORE,
+ EVENT_NECROTIC_AURA_FADING,
+ EVENT_NECROTIC_AURA_FADED
};
enum Achievement
@@ -82,10 +82,10 @@ class boss_loatheb : public CreatureScript
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- events.ScheduleEvent(EVENT_NECROTIC_AURA, 17 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_DEATHBLOOM, 5 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_SPORE, RAID_MODE(36,18) * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 2 * MINUTE * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_NECROTIC_AURA, Seconds(17));
+ events.ScheduleEvent(EVENT_DEATHBLOOM, Seconds(5));
+ events.ScheduleEvent(EVENT_SPORE, Seconds(18));
+ events.ScheduleEvent(EVENT_INEVITABLE_DOOM, Minutes(2));
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
@@ -94,13 +94,6 @@ class boss_loatheb : public CreatureScript
summon->CastSpell(summon,SPELL_FUNGAL_CREEP,true);
}
- void SummonedCreatureDespawn(Creature* summon) override
- {
- summons.Despawn(summon);
- if (summon->IsAlive())
- summon->CastSpell(summon,SPELL_FUNGAL_CREEP,true);
- }
-
uint32 GetData(uint32 id) const override
{
return (_sporeLoserData && id == DATA_ACHIEVEMENT_SPORE_LOSER) ? 1u : 0u;
@@ -119,34 +112,33 @@ class boss_loatheb : public CreatureScript
{
case EVENT_NECROTIC_AURA:
DoCastAOE(SPELL_NECROTIC_AURA);
- DoCast(me, SPELL_WARN_NECROTIC_AURA);
- events.ScheduleEvent(EVENT_NECROTIC_AURA, 20 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14 * IN_MILLISECONDS);
+ Talk(SAY_NECROTIC_AURA_APPLIED);
+ events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, Seconds(14));
+ events.ScheduleEvent(EVENT_NECROTIC_AURA_FADED, Seconds(17));
+ events.Repeat(Seconds(20));
break;
case EVENT_DEATHBLOOM:
DoCastAOE(SPELL_DEATHBLOOM);
- events.ScheduleEvent(EVENT_DEATHBLOOM, 30 * IN_MILLISECONDS);
+ events.Repeat(Seconds(30));
break;
case EVENT_INEVITABLE_DOOM:
_doomCounter++;
DoCastAOE(SPELL_INEVITABLE_DOOM);
if (_doomCounter > 6)
- {
- if (_doomCounter & 1) // odd
- events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 14 * IN_MILLISECONDS);
- else
- events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 17 * IN_MILLISECONDS);
- }
+ events.Repeat((_doomCounter & 1) ? Seconds(14) : Seconds(17));
else
- events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 30 * IN_MILLISECONDS);
+ events.Repeat(30);
break;
case EVENT_SPORE:
DoCast(me, SPELL_SUMMON_SPORE, false);
- events.ScheduleEvent(EVENT_SPORE, RAID_MODE(36,18) * IN_MILLISECONDS);
+ events.Repeat(RAID_MODE(Seconds(36), Seconds(15)));
break;
case EVENT_NECROTIC_AURA_FADING:
Talk(SAY_NECROTIC_AURA_FADING);
break;
+ case EVENT_NECROTIC_AURA_FADED:
+ Talk(SAY_NECROTIC_AURA_REMOVED);
+ break;
default:
break;
}
@@ -177,49 +169,6 @@ class achievement_spore_loser : public AchievementCriteriaScript
}
};
-typedef boss_loatheb::boss_loathebAI LoathebAI;
-
-class spell_loatheb_necrotic_aura_warning : public SpellScriptLoader
-{
- public:
- spell_loatheb_necrotic_aura_warning() : SpellScriptLoader("spell_loatheb_necrotic_aura_warning") { }
-
- class spell_loatheb_necrotic_aura_warning_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_loatheb_necrotic_aura_warning_AuraScript);
-
- bool Validate(SpellInfo const* /*spell*/) override
- {
- if (!sSpellStore.LookupEntry(SPELL_WARN_NECROTIC_AURA))
- return false;
- return true;
- }
-
- void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (GetTarget()->IsAIEnabled)
- ENSURE_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_APPLIED);
- }
-
- void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (GetTarget()->IsAIEnabled)
- ENSURE_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_REMOVED);
- }
-
- void Register() override
- {
- AfterEffectApply += AuraEffectApplyFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
- AfterEffectRemove += AuraEffectRemoveFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_loatheb_necrotic_aura_warning_AuraScript();
- }
-};
-
class spell_loatheb_deathbloom : public SpellScriptLoader
{
public:
@@ -260,6 +209,5 @@ void AddSC_boss_loatheb()
{
new boss_loatheb();
new achievement_spore_loser();
- new spell_loatheb_necrotic_aura_warning();
new spell_loatheb_deathbloom();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
index 9d8f1365afb..9502193884a 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp
@@ -73,6 +73,8 @@ struct WebTargetSelector : public std::unary_function<Unit*, bool>
WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
bool operator()(Unit const* target) const
{
+ if (target->GetTypeId() != TYPEID_PLAYER) // never web nonplayers (pets, guardians, etc.)
+ return false;
if (_maexxna->GetVictim() == target) // never target tank
return false;
if (target->HasAura(SPELL_WEB_WRAP)) // never target targets that are already webbed
@@ -101,11 +103,11 @@ public:
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
- events.ScheduleEvent(EVENT_WRAP, 20 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_SPRAY, 40 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_SHOCK, urandms(5, 10));
- events.ScheduleEvent(EVENT_POISON, urandms(10, 15));
- events.ScheduleEvent(EVENT_SUMMON, 30 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_WRAP, Seconds(20));
+ events.ScheduleEvent(EVENT_SPRAY, Seconds(40));
+ events.ScheduleEvent(EVENT_SHOCK, randtime(Seconds(5), Seconds(10)));
+ events.ScheduleEvent(EVENT_POISON, randtime(Seconds(10), Seconds(15)));
+ events.ScheduleEvent(EVENT_SUMMON, Seconds(30));
}
void Reset() override
@@ -153,28 +155,28 @@ public:
}
}
}
- events.ScheduleEvent(EVENT_WRAP, 40000);
+ events.Repeat(Seconds(40));
break;
}
case EVENT_SPRAY:
Talk(EMOTE_WEB_SPRAY);
DoCastAOE(SPELL_WEB_SPRAY);
- events.ScheduleEvent(EVENT_SPRAY, 40000);
+ events.Repeat(Seconds(40));
break;
case EVENT_SHOCK:
DoCastAOE(SPELL_POISON_SHOCK);
- events.ScheduleEvent(EVENT_SHOCK, urandms(10, 20));
+ events.Repeat(randtime(Seconds(10), Seconds(20)));
break;
case EVENT_POISON:
DoCastVictim(SPELL_NECROTIC_POISON);
- events.ScheduleEvent(EVENT_POISON, urandms(10, 20));
+ events.Repeat(randtime(Seconds(10), Seconds(20)));
break;
case EVENT_SUMMON:
Talk(EMOTE_SPIDERS);
uint8 amount = urand(8, 10);
for (uint8 i = 0; i < amount; ++i)
DoSummon(NPC_SPIDERLING, me, 4.0f, 5 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
- events.ScheduleEvent(EVENT_SUMMON, 40000);
+ events.Repeat(Seconds(40));
break;
}
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
index 8ee3936dee3..2108b4ce102 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp
@@ -131,25 +131,25 @@ public:
Reset();
else
{
- uint8 secondsGround;
+ uint8 timeGround;
switch (balconyCount)
{
case 0:
- secondsGround = 90;
+ timeGround = 90;
break;
case 1:
- secondsGround = 110;
+ timeGround = 110;
break;
case 2:
default:
- secondsGround = 180;
+ timeGround = 180;
}
- events.ScheduleEvent(EVENT_GROUND_ATTACKABLE, 2 * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_BALCONY, secondsGround * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_CURSE, urand(10,25) * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_WARRIOR, urand(20,30) * IN_MILLISECONDS, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_GROUND_ATTACKABLE, Seconds(2), 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_BALCONY, Seconds(timeGround), 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_CURSE, randtime(Seconds(10), Seconds(25)), 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_WARRIOR, randtime(Seconds(20), Seconds(30)), 0, PHASE_GROUND);
if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
- events.ScheduleEvent(EVENT_BLINK, urand(20,30) * IN_MILLISECONDS, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_BLINK, randtime(Seconds(20), Seconds(30)), 0, PHASE_GROUND);
}
}
@@ -220,7 +220,7 @@ public:
case EVENT_CURSE:
{
DoCastAOE(SPELL_CURSE);
- events.ScheduleEvent(EVENT_CURSE, urand(50, 70) * IN_MILLISECONDS, 0, PHASE_GROUND);
+ events.Repeat(randtime(Seconds(50), Seconds(70)));
break;
}
case EVENT_WARRIOR:
@@ -229,7 +229,7 @@ public:
CastSummon(RAID_MODE(2, 3), 0, 0);
- events.ScheduleEvent(EVENT_WARRIOR, 40 * IN_MILLISECONDS, 0, PHASE_GROUND);
+ events.Repeat(Seconds(40));
break;
case EVENT_BLINK:
DoCastAOE(SPELL_CRIPPLE, true);
@@ -237,7 +237,7 @@ public:
DoResetThreat();
justBlinked = true;
- events.ScheduleEvent(EVENT_BLINK, 40000, 0, PHASE_GROUND);
+ events.Repeat(Seconds(40));
break;
case EVENT_BALCONY:
events.SetPhase(PHASE_BALCONY);
@@ -247,24 +247,24 @@ public:
me->StopMoving();
me->RemoveAllAuras();
- events.ScheduleEvent(EVENT_BALCONY_TELEPORT, 3 * IN_MILLISECONDS, 0, PHASE_BALCONY);
- events.ScheduleEvent(EVENT_WAVE, urand(5 * IN_MILLISECONDS, 8 * IN_MILLISECONDS), 0, PHASE_BALCONY);
+ events.ScheduleEvent(EVENT_BALCONY_TELEPORT, Seconds(3), 0, PHASE_BALCONY);
+ events.ScheduleEvent(EVENT_WAVE, randtime(Seconds(5), Seconds(8)), 0, PHASE_BALCONY);
- uint8 secondsBalcony;
+ uint8 timeBalcony;
switch (balconyCount)
{
case 0:
- secondsBalcony = 70;
+ timeBalcony = 70;
break;
case 1:
- secondsBalcony = 97;
+ timeBalcony = 97;
break;
case 2:
default:
- secondsBalcony = 120;
+ timeBalcony = 120;
break;
}
- events.ScheduleEvent(EVENT_GROUND, secondsBalcony * IN_MILLISECONDS, 0, PHASE_BALCONY);
+ events.ScheduleEvent(EVENT_GROUND, Seconds(timeBalcony), 0, PHASE_BALCONY);
break;
case EVENT_BALCONY_TELEPORT:
Talk(EMOTE_TELEPORT_1);
@@ -287,7 +287,7 @@ public:
CastSummon(0, RAID_MODE(5, 10), RAID_MODE(5, 10));
break;
}
- events.ScheduleEvent(EVENT_WAVE, urand(30, 45) * IN_MILLISECONDS, 0, PHASE_BALCONY);
+ events.Repeat(randtime(Seconds(30), Seconds(45)));
break;
case EVENT_GROUND:
++balconyCount;
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
index b8ce402a939..cfa6e2e9f30 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp
@@ -97,8 +97,8 @@ public:
_EnterCombat();
Enraged = false;
Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_HATEFUL, Seconds(1));
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(6));
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT);
}
@@ -167,17 +167,17 @@ public:
if (thirdThreatTarget)
me->getThreatManager().addThreat(thirdThreatTarget, HATEFUL_THREAT_AMT); // this will only ever be used in 25m
- events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS);
+ events.Repeat(Seconds(1));
break;
}
case EVENT_BERSERK:
DoCast(me, SPELL_BERSERK, true);
Talk(EMOTE_BERSERK);
- events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_SLIME, Seconds(2));
break;
case EVENT_SLIME:
- DoCastVictim(SPELL_SLIME_BOLT, true);
- events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS);
+ DoCastAOE(SPELL_SLIME_BOLT, true);
+ events.Repeat(Seconds(2));
break;
}
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
index 1d12f64a949..548f8086eb8 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp
@@ -104,6 +104,9 @@ public:
void JustDied(Unit* /*killer*/) override
{
+ for (ObjectGuid summonGuid : summons)
+ if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
+ summon->RemoveCharmAuras();
Talk(SAY_DEATH);
DoCastAOE(SPELL_HOPELESS, true);
@@ -117,10 +120,10 @@ public:
me->StopMoving();
summons.DoZoneInCombat();
Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_ATTACK, 7 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_STRIKE, 21 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_KNIFE, 10 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_ATTACK, Seconds(7));
+ events.ScheduleEvent(EVENT_STRIKE, Seconds(21));
+ events.ScheduleEvent(EVENT_SHOUT, Seconds(16));
+ events.ScheduleEvent(EVENT_KNIFE, Seconds(10));
}
void UpdateAI(uint32 diff) override
@@ -141,16 +144,16 @@ public:
break;
case EVENT_STRIKE:
DoCastVictim(SPELL_UNBALANCING_STRIKE);
- events.ScheduleEvent(EVENT_STRIKE, 6 * IN_MILLISECONDS);
+ events.Repeat(Seconds(6));
return;
case EVENT_SHOUT:
DoCastAOE(SPELL_DISRUPTING_SHOUT);
- events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
+ events.Repeat(Seconds(16));
return;
case EVENT_KNIFE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f))
DoCast(target, SPELL_JAGGED_KNIFE);
- events.ScheduleEvent(EVENT_KNIFE, urandms(10,15));
+ events.Repeat(randtime(Seconds(10), Seconds(15)));
return;
}
}
@@ -174,7 +177,10 @@ class npc_dk_understudy : public CreatureScript
struct npc_dk_understudyAI : public ScriptedAI
{
- npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0) { }
+ npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0)
+ {
+ creature->LoadEquipment(1);
+ }
void EnterCombat(Unit* /*who*/) override
{
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
index 68b9e252150..4596b17bc23 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp
@@ -16,7 +16,9 @@
*/
#include "ScriptMgr.h"
+#include "GameObjectAI.h"
#include "ScriptedCreature.h"
+#include "SpellScript.h"
#include "Player.h"
#include "SpellInfo.h"
#include "naxxramas.h"
@@ -31,25 +33,24 @@ enum Yells
enum Spells
{
- SPELL_FROST_AURA = 28531,
- SPELL_CLEAVE = 19983,
- SPELL_TAIL_SWEEP = 55697,
- SPELL_SUMMON_BLIZZARD = 28560,
- SPELL_LIFE_DRAIN = 28542,
- SPELL_ICEBOLT = 28522,
- SPELL_FROST_BREATH = 29318,
- SPELL_FROST_EXPLOSION = 28524,
- SPELL_FROST_MISSILE = 30101,
- SPELL_BERSERK = 26662,
- SPELL_DIES = 29357,
- SPELL_CHILL = 28547,
- SPELL_CHECK_RESISTS = 60539,
+ SPELL_FROST_AURA = 28531,
+ SPELL_CLEAVE = 19983,
+ SPELL_TAIL_SWEEP = 55697,
+ SPELL_SUMMON_BLIZZARD = 28560,
+ SPELL_LIFE_DRAIN = 28542,
+ SPELL_ICEBOLT = 28522,
+ SPELL_FROST_BREATH_ANTICHEAT = 29318, // damage effect ignoring LoS on the entrance platform to prevent cheese
+ SPELL_FROST_BREATH = 28524, // damage effect below sapphiron
+ SPELL_FROST_MISSILE = 30101, // visual only
+ SPELL_BERSERK = 26662,
+ SPELL_DIES = 29357,
+ SPELL_CHECK_RESISTS = 60539,
+ SPELL_SAPPHIRON_WING_BUFFET = 29328
};
enum Phases
{
- PHASE_NULL = 0,
- PHASE_BIRTH,
+ PHASE_BIRTH = 1,
PHASE_GROUND,
PHASE_FLIGHT
};
@@ -72,9 +73,15 @@ enum Events
EVENT_CHECK_RESISTS
};
+enum Actions
+{
+ ACTION_BIRTH = 1
+};
+
enum Misc
{
NPC_BLIZZARD = 16474,
+ NPC_WING_BUFFET = 17025,
GO_ICEBLOCK = 181247,
// The Hundred Club
@@ -92,77 +99,74 @@ class boss_sapphiron : public CreatureScript
struct boss_sapphironAI : public BossAI
{
boss_sapphironAI(Creature* creature) :
- BossAI(creature, BOSS_SAPPHIRON), _iceboltCount(0), _map(me->GetMap())
+ BossAI(creature, BOSS_SAPPHIRON)
{
Initialize();
}
void Initialize()
{
- _phase = PHASE_NULL;
-
+ _delayedDrain = false;
_canTheHundredClub = true;
}
void InitializeAI() override
{
+ if (instance->GetBossState(BOSS_SAPPHIRON) == DONE)
+ return;
+
_canTheHundredClub = true;
- float x, y, z;
- me->GetPosition(x, y, z);
- me->SummonGameObject(GO_BIRTH, x, y, z, 0, 0, 0, 0, 0, 0);
- me->SetVisible(false);
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_PASSIVE);
+ if (!instance->GetData(DATA_HAD_SAPPHIRON_BIRTH))
+ {
+ me->SetVisible(false);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_PASSIVE);
+ }
BossAI::InitializeAI();
}
void Reset() override
{
- _Reset();
-
- if (_phase == PHASE_FLIGHT)
+ if (events.IsInPhase(PHASE_FLIGHT))
{
- ClearIceBlock();
+ instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ICEBOLT);
me->SetReactState(REACT_AGGRESSIVE);
if (me->IsHovering())
{
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
me->SetHover(false);
}
- me->SetDisableGravity(false);
}
+ _Reset();
Initialize();
}
+ void DamageTaken(Unit* /*who*/, uint32& damage) override
+ {
+ if (damage < me->GetHealth() || !events.IsInPhase(PHASE_FLIGHT))
+ return;
+ damage = me->GetHealth()-1; // don't die during air phase
+ }
+
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
me->CastSpell(me, SPELL_FROST_AURA, true);
- DoCast(me, SPELL_CHECK_RESISTS);
- events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_BERSERK, 15 * MINUTE * IN_MILLISECONDS);
- EnterPhaseGround();
+ events.SetPhase(PHASE_GROUND);
+ events.ScheduleEvent(EVENT_CHECK_RESISTS, Seconds(0));
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(15));
+ EnterPhaseGround(true);
}
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
{
switch(spell->Id)
{
- case SPELL_ICEBOLT:
- {
- IceBlockMap::iterator itr = _iceblocks.find(target->GetGUID());
- if (itr != _iceblocks.end() && !itr->second)
- {
- if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25))
- itr->second = iceblock->GetGUID();
- }
- break;
- }
case SPELL_CHECK_RESISTS:
if (target && target->GetResistance(SPELL_SCHOOL_FROST) > MAX_FROST_RESISTANCE)
_canTheHundredClub = false;
@@ -179,41 +183,37 @@ class boss_sapphiron : public CreatureScript
void MovementInform(uint32 /*type*/, uint32 id) override
{
if (id == 1)
- events.ScheduleEvent(EVENT_LIFTOFF, 0);
+ events.ScheduleEvent(EVENT_LIFTOFF, Seconds(0), 0, PHASE_FLIGHT);
}
void DoAction(int32 param) override
{
- if (param == DATA_SAPPHIRON_BIRTH)
+ if (param == ACTION_BIRTH)
{
- _phase = PHASE_BIRTH;
- events.ScheduleEvent(EVENT_BIRTH, 23 * IN_MILLISECONDS);
+ events.SetPhase(PHASE_BIRTH);
+ events.ScheduleEvent(EVENT_BIRTH, Seconds(23));
}
}
- void EnterPhaseGround()
+ void EnterPhaseGround(bool initial)
{
- _phase = PHASE_GROUND;
me->SetReactState(REACT_AGGRESSIVE);
- events.SetPhase(PHASE_GROUND);
- events.ScheduleEvent(EVENT_CLEAVE, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_TAIL, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_DRAIN, 24 * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_BLIZZARD, urand(5, 10) * IN_MILLISECONDS, 0, PHASE_GROUND);
- events.ScheduleEvent(EVENT_FLIGHT, 45 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(5), Seconds(15)), 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_TAIL, randtime(Seconds(7), Seconds(10)), 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_BLIZZARD, randtime(Seconds(5), Seconds(10)), 0, PHASE_GROUND);
+ if (initial)
+ {
+ events.ScheduleEvent(EVENT_DRAIN, randtime(Seconds(22), Seconds(28)));
+ events.ScheduleEvent(EVENT_FLIGHT, Seconds(48) + Milliseconds(500), 0, PHASE_GROUND);
+ }
+ else
+ events.ScheduleEvent(EVENT_FLIGHT, Minutes(1), 0, PHASE_GROUND);
}
- void ClearIceBlock()
+ inline void CastDrain()
{
- for (IceBlockMap::const_iterator itr = _iceblocks.begin(); itr != _iceblocks.end(); ++itr)
- {
- if (Player* player = ObjectAccessor::GetPlayer(*me, itr->first))
- player->RemoveAura(SPELL_ICEBOLT);
-
- if (GameObject* go = ObjectAccessor::GetGameObject(*me, itr->second))
- go->Delete();
- }
- _iceblocks.clear();
+ DoCastAOE(SPELL_LIFE_DRAIN);
+ events.ScheduleEvent(EVENT_DRAIN, randtime(Seconds(22), Seconds(28)));
}
uint32 GetData(uint32 data) const override
@@ -226,15 +226,12 @@ class boss_sapphiron : public CreatureScript
void UpdateAI(uint32 diff) override
{
- if (!_phase)
- return;
-
events.Update(diff);
- if (_phase != PHASE_BIRTH && !UpdateVictim())
+ if (!events.IsInPhase(PHASE_BIRTH) && !UpdateVictim())
return;
- if (_phase == PHASE_GROUND)
+ if (events.IsInPhase(PHASE_GROUND))
{
while (uint32 eventId = events.ExecuteEvent())
{
@@ -242,7 +239,10 @@ class boss_sapphiron : public CreatureScript
{
case EVENT_CHECK_RESISTS:
DoCast(me, SPELL_CHECK_RESISTS);
- events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS);
+ events.Repeat(Seconds(30));
+ return;
+ case EVENT_GROUND:
+ EnterPhaseGround(false);
return;
case EVENT_BERSERK:
Talk(EMOTE_ENRAGE);
@@ -250,27 +250,26 @@ class boss_sapphiron : public CreatureScript
return;
case EVENT_CLEAVE:
DoCastVictim(SPELL_CLEAVE);
- events.ScheduleEvent(EVENT_CLEAVE, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(5), Seconds(15)), 0, PHASE_GROUND);
return;
case EVENT_TAIL:
DoCastAOE(SPELL_TAIL_SWEEP);
- events.ScheduleEvent(EVENT_TAIL, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_TAIL, randtime(Seconds(7), Seconds(10)), 0, PHASE_GROUND);
return;
case EVENT_DRAIN:
- DoCastAOE(SPELL_LIFE_DRAIN);
- events.ScheduleEvent(EVENT_DRAIN, 24 * IN_MILLISECONDS, 0, PHASE_GROUND);
+ if (events.IsInPhase(PHASE_FLIGHT))
+ _delayedDrain = true;
+ else
+ CastDrain();
return;
case EVENT_BLIZZARD:
- {
- if (Creature* summon = DoSummon(NPC_BLIZZARD, me, 0.0f, urand(25, 30) * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN))
- summon->GetMotionMaster()->MoveRandom(40);
- events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(20, 7) * IN_MILLISECONDS, 0, PHASE_GROUND);
+ DoCastAOE(SPELL_SUMMON_BLIZZARD);
+ events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(Seconds(20), Seconds(7)), 0, PHASE_GROUND);
break;
- }
case EVENT_FLIGHT:
if (HealthAbovePct(10))
{
- _phase = PHASE_FLIGHT;
+ _delayedDrain = false;
events.SetPhase(PHASE_FLIGHT);
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
@@ -293,61 +292,69 @@ class boss_sapphiron : public CreatureScript
{
case EVENT_CHECK_RESISTS:
DoCast(me, SPELL_CHECK_RESISTS);
- events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS);
+ events.Repeat(Seconds(30));
return;
case EVENT_LIFTOFF:
+ {
Talk(EMOTE_AIR_PHASE);
- me->SetDisableGravity(true);
+ if (Creature* buffet = DoSummon(NPC_WING_BUFFET, me, 0.0f, 0, TEMPSUMMON_MANUAL_DESPAWN))
+ _buffet = buffet->GetGUID();
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
me->SetHover(true);
- events.ScheduleEvent(EVENT_ICEBOLT, 1500);
- _iceboltCount = RAID_MODE(2, 3);
+ events.ScheduleEvent(EVENT_ICEBOLT, Seconds(7), 0, PHASE_FLIGHT);
+
+ _iceboltTargets.clear();
+ std::list<Unit*> targets;
+ SelectTargetList(targets, RAID_MODE(2, 3), SELECT_TARGET_RANDOM, 200.0f, true);
+ for (Unit* target : targets)
+ if (target)
+ _iceboltTargets.push_back(target->GetGUID());
return;
+ }
case EVENT_ICEBOLT:
{
- std::vector<Unit*> targets;
- std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin();
- for (; i != me->getThreatManager().getThreatList().end(); ++i)
- if ((*i)->getTarget()->GetTypeId() == TYPEID_PLAYER && !(*i)->getTarget()->HasAura(SPELL_ICEBOLT))
- targets.push_back((*i)->getTarget());
-
- if (targets.empty())
- _iceboltCount = 0;
- else
+ if (_iceboltTargets.empty())
{
- std::vector<Unit*>::const_iterator itr = targets.begin();
- advance(itr, rand32() % targets.size());
- _iceblocks.insert(std::make_pair((*itr)->GetGUID(), ObjectGuid::Empty));
- DoCast(*itr, SPELL_ICEBOLT);
- --_iceboltCount;
+ events.ScheduleEvent(EVENT_BREATH, Seconds(2), 0, PHASE_FLIGHT);
+ return;
}
-
- if (_iceboltCount)
- events.ScheduleEvent(EVENT_ICEBOLT, 1 * IN_MILLISECONDS);
+ ObjectGuid target = _iceboltTargets.back();
+ if (Player* pTarget = ObjectAccessor::GetPlayer(*me, target))
+ if (pTarget->IsAlive())
+ DoCast(pTarget, SPELL_ICEBOLT);
+ _iceboltTargets.pop_back();
+
+ if (_iceboltTargets.empty())
+ events.ScheduleEvent(EVENT_BREATH, Seconds(2), 0, PHASE_FLIGHT);
else
- events.ScheduleEvent(EVENT_BREATH, 1 * IN_MILLISECONDS);
+ events.Repeat(Seconds(3));
return;
}
case EVENT_BREATH:
{
Talk(EMOTE_BREATH);
DoCastAOE(SPELL_FROST_MISSILE);
- events.ScheduleEvent(EVENT_EXPLOSION, 8 * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_EXPLOSION, Seconds(8), 0, PHASE_FLIGHT);
return;
}
case EVENT_EXPLOSION:
- CastExplosion();
- ClearIceBlock();
- events.ScheduleEvent(EVENT_LAND, 3 * IN_MILLISECONDS);
+ DoCastAOE(SPELL_FROST_BREATH);
+ DoCastAOE(SPELL_FROST_BREATH_ANTICHEAT);
+ events.ScheduleEvent(EVENT_LAND, Seconds(3) + Milliseconds(500), 0, PHASE_FLIGHT);
return;
case EVENT_LAND:
+ if (_delayedDrain)
+ CastDrain();
+ if (Creature* cBuffet = ObjectAccessor::GetCreature(*me, _buffet))
+ {
+ cBuffet->DespawnOrUnsummon(1 * IN_MILLISECONDS);
+ _buffet.Clear();
+ }
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
Talk(EMOTE_GROUND_PHASE);
me->SetHover(false);
- me->SetDisableGravity(false);
- events.ScheduleEvent(EVENT_GROUND, 1500);
- return;
- case EVENT_GROUND:
- EnterPhaseGround();
+ events.SetPhase(PHASE_GROUND);
+ events.ScheduleEvent(EVENT_GROUND, Seconds(3) + Milliseconds(500), 0, PHASE_GROUND);
return;
case EVENT_BIRTH:
me->SetVisible(true);
@@ -359,56 +366,261 @@ class boss_sapphiron : public CreatureScript
}
}
- void CastExplosion()
+ private:
+ std::vector<ObjectGuid> _iceboltTargets;
+ ObjectGuid _buffet;
+ bool _delayedDrain;
+ bool _canTheHundredClub;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new boss_sapphironAI(creature);
+ }
+};
+
+class go_sapphiron_birth : public GameObjectScript
+{
+ public:
+ go_sapphiron_birth() : GameObjectScript("go_sapphiron_birth") { }
+
+ struct go_sapphiron_birthAI : public GameObjectAI
+ {
+ go_sapphiron_birthAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { }
+
+ void OnStateChanged(uint32 state, Unit* who) override
+ {
+ if (state == GO_ACTIVATED)
+ {
+ if (who)
+ {
+ if (Creature* sapphiron = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_SAPPHIRON)))
+ sapphiron->AI()->DoAction(ACTION_BIRTH);
+ instance->SetData(DATA_HAD_SAPPHIRON_BIRTH, 1u);
+ }
+ }
+ else if (state == GO_JUST_DEACTIVATED)
+ { // prevent ourselves from going back to _READY and resetting the client anim
+ go->SetRespawnTime(0);
+ go->Delete();
+ }
+ }
+
+ InstanceScript* instance;
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return GetInstanceAI<go_sapphiron_birthAI>(go);
+ }
+};
+
+
+class spell_sapphiron_change_blizzard_target : public SpellScriptLoader
+{
+ public:
+ spell_sapphiron_change_blizzard_target() : SpellScriptLoader("spell_sapphiron_change_blizzard_target") { }
+
+ class spell_sapphiron_change_blizzard_target_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sapphiron_change_blizzard_target_AuraScript);
+
+ void HandlePeriodic(AuraEffect const* /*eff*/)
+ {
+ TempSummon* me = GetTarget()->ToTempSummon();
+ if (Creature* owner = me ? me->GetSummonerCreatureBase() : nullptr)
+ {
+ Unit* newTarget = owner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true);
+ if (!newTarget)
+ newTarget = owner->getAttackerForHelper();
+ if (newTarget)
+ me->GetMotionMaster()->MoveFollow(newTarget, 0.1f, 0.0f);
+ else
+ {
+ me->StopMoving();
+ me->GetMotionMaster()->Clear();
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_sapphiron_change_blizzard_target_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sapphiron_change_blizzard_target_AuraScript();
+ }
+};
+
+class spell_sapphiron_icebolt : public SpellScriptLoader
+{
+ public:
+ spell_sapphiron_icebolt() : SpellScriptLoader("spell_sapphiron_icebolt") { }
+
+ class spell_sapphiron_icebolt_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sapphiron_icebolt_AuraScript);
+
+ void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->ApplySpellImmune(SPELL_ICEBOLT, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, true);
+ }
+
+ void HandleRemove(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (_block)
+ if (GameObject* oBlock = ObjectAccessor::GetGameObject(*GetTarget(), _block))
+ oBlock->Delete();
+ GetTarget()->ApplySpellImmune(SPELL_ICEBOLT, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, false);
+ }
+
+ void HandlePeriodic(AuraEffect const* /*eff*/)
+ {
+ if (_block)
+ return;
+ if (GetTarget()->isMoving())
+ return;
+ float x, y, z;
+ GetTarget()->GetPosition(x, y, z);
+ if (GameObject* block = GetTarget()->SummonGameObject(GO_ICEBLOCK, x, y, z, 0, 0, 0, 0, 0, 25))
+ _block = block->GetGUID();
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_sapphiron_icebolt_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_sapphiron_icebolt_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_sapphiron_icebolt_AuraScript::HandlePeriodic, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+
+ ObjectGuid _block;
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_sapphiron_icebolt_AuraScript();
+ }
+};
+
+// @hack Hello, developer from the future! How has your day been?
+// Anyway, this is, as you can undoubtedly see, a hack to emulate line of sight checks on a spell that abides line of sight anyway.
+// In the current core, line of sight is not properly checked for people standing behind an ice block. This is not a good thing and kills people.
+// Thus, we have this hack to check for ice block LoS in a "safe" way. Kind of. It's inaccurate, but in a good way (tends to save people when it shouldn't in edge cases).
+// If LoS handling is better in whatever the current revision is when you read this, please get rid of the hack. Thanks!
+class spell_sapphiron_frost_breath : public SpellScriptLoader
+{
+ public:
+ spell_sapphiron_frost_breath() : SpellScriptLoader("spell_sapphiron_frost_breath") { }
+
+ class spell_sapphiron_frost_breath_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sapphiron_frost_breath_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return !!sSpellMgr->GetSpellInfo(SPELL_FROST_BREATH);
+ }
+
+ void HandleTargets(std::list<WorldObject*>& targetList)
{
- DoZoneInCombat(); // make sure everyone is in threatlist
- std::vector<Unit*> targets;
- std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin();
- for (; i != me->getThreatManager().getThreatList().end(); ++i)
+ std::list<GameObject*> blocks;
+ if (GetCaster())
+ GetCaster()->GetGameObjectListWithEntryInGrid(blocks, GO_ICEBLOCK, 200.0f);
+
+ std::vector<Unit*> toRemove;
+ toRemove.reserve(3);
+ std::list<WorldObject*>::iterator it = targetList.begin();
+ while (it != targetList.end())
{
- Unit* target = (*i)->getTarget();
- if (target->GetTypeId() != TYPEID_PLAYER)
+ Unit* target = (*it)->ToUnit();
+ if (!target)
+ {
+ it = targetList.erase(it);
continue;
+ }
if (target->HasAura(SPELL_ICEBOLT))
{
- target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true);
- targets.push_back(target);
+ it = targetList.erase(it);
+ toRemove.push_back(target);
+ continue;
+ }
+
+ bool found = false;
+ for (GameObject* block : blocks)
+ if (block->IsInBetween(GetCaster(), target, 2.0f) && GetCaster()->GetExactDist2d(block) + 5 >= GetCaster()->GetExactDist2d(target))
+ {
+ found = true;
+ break;
+ }
+ if (found)
+ {
+ it = targetList.erase(it);
continue;
}
+ ++it;
+ }
+
+ for (Unit* block : toRemove)
+ block->RemoveAura(SPELL_ICEBOLT);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_breath_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
+ }
+ };
- for (IceBlockMap::const_iterator itr = _iceblocks.begin(); itr != _iceblocks.end(); ++itr)
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_sapphiron_frost_breath_SpellScript();
+ }
+};
+
+class spell_sapphiron_summon_blizzard : public SpellScriptLoader
+{
+ public:
+ spell_sapphiron_summon_blizzard() : SpellScriptLoader("spell_sapphiron_summon_blizzard") { }
+
+ class spell_sapphiron_summon_blizzard_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sapphiron_summon_blizzard_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ return !!sSpellMgr->GetSpellInfo(SPELL_SUMMON_BLIZZARD);
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ if (Creature* blizzard = GetCaster()->SummonCreature(NPC_BLIZZARD, *target, TEMPSUMMON_TIMED_DESPAWN, urandms(25, 30)))
{
- if (GameObject* go = ObjectAccessor::GetGameObject(*me, itr->second))
+ blizzard->CastSpell(nullptr, blizzard->m_spells[0], TRIGGERED_NONE);
+ if (Creature* creatureCaster = GetCaster()->ToCreature())
{
- if (go->IsInBetween(me, target, 2.0f)
- && me->GetExactDist2d(target->GetPositionX(), target->GetPositionY()) - me->GetExactDist2d(go->GetPositionX(), go->GetPositionY()) < 5.0f)
+ if (Unit* newTarget = creatureCaster->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
{
- target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true);
- targets.push_back(target);
- break;
+ blizzard->GetMotionMaster()->MoveFollow(newTarget, 0.1f, 0.0f);
+ return;
}
}
+ blizzard->GetMotionMaster()->MoveFollow(target, 0.1f, 0.0f);
}
- }
-
- me->CastSpell(me, SPELL_FROST_EXPLOSION, true);
-
- for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
- (*itr)->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, false);
}
- private:
- Phases _phase;
- uint32 _iceboltCount;
- IceBlockMap _iceblocks;
- bool _canTheHundredClub;
- Map* _map;
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_sapphiron_summon_blizzard_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
};
- CreatureAI* GetAI(Creature* creature) const override
+ SpellScript* GetSpellScript() const override
{
- return new boss_sapphironAI(creature);
+ return new spell_sapphiron_summon_blizzard_SpellScript();
}
};
@@ -426,5 +638,10 @@ class achievement_the_hundred_club : public AchievementCriteriaScript
void AddSC_boss_sapphiron()
{
new boss_sapphiron();
+ new go_sapphiron_birth();
+ new spell_sapphiron_change_blizzard_target();
+ new spell_sapphiron_icebolt();
+ new spell_sapphiron_frost_breath();
+ new spell_sapphiron_summon_blizzard();
new achievement_the_hundred_club();
}
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
index 66a00b2b634..2cf3a4664dd 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
@@ -109,6 +109,10 @@ enum PetSpells
SPELL_MAGNETIC_PULL = 54517,
SPELL_MAGNETIC_PULL_EFFECT = 28337,
+ // @hack feugen/stalagg use this in P1 after gripping tanks to prevent mmaps from pathing them off the platform once they approach the ramp
+ // developer from the future, if you read this and mmaps in the room has been fixed, then get rid of the hackfix, please
+ SPELL_ROOT_SELF = 75215,
+
SPELL_TESLA_SHOCK = 28099
};
@@ -166,7 +170,9 @@ public:
struct boss_thaddiusAI : public BossAI
{
public:
- boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningEnabled(false), shockingEligibility(true)
+ boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningUnlocked(false), ballLightningEnabled(false), shockingEligibility(true) {}
+
+ void InitializeAI() override
{
if (instance->GetBossState(BOSS_THADDIUS) != DONE)
{
@@ -184,12 +190,33 @@ public:
Talk(SAY_SLAY);
}
- void Reset() override
+ void Reset() override { }
+
+ void EnterEvadeMode(EvadeReason why) override
{
+ if (!ballLightningEnabled && why == EVADE_REASON_NO_HOSTILES)
+ {
+ ballLightningEnabled = true;
+ return; // try again
+ }
if (events.IsInPhase(PHASE_TRANSITION) || (events.IsInPhase(PHASE_THADDIUS) && me->IsAlive()))
BeginResetEncounter();
}
+ bool CanAIAttack(Unit const* who) const override
+ {
+ if (ballLightningEnabled || me->IsWithinMeleeRange(who))
+ return BossAI::CanAIAttack(who);
+ else
+ return false;
+ }
+
+ void JustRespawned() override
+ {
+ if (events.IsInPhase(PHASE_RESETTING))
+ ResetEncounter();
+ }
+
void JustDied(Unit* /*killer*/) override
{
_JustDied();
@@ -217,7 +244,10 @@ public:
case ACTION_FEUGEN_AGGRO:
case ACTION_STALAGG_AGGRO:
if (events.IsInPhase(PHASE_RESETTING))
- return BeginResetEncounter();
+ {
+ BeginResetEncounter();
+ return;
+ }
if (!events.IsInPhase(PHASE_NOT_ENGAGED))
return;
events.SetPhase(PHASE_PETS);
@@ -225,10 +255,14 @@ public:
shockingEligibility = true;
if (!instance->CheckRequiredBosses(BOSS_THADDIUS))
- return BeginResetEncounter();
+ {
+ BeginResetEncounter();
+ return;
+ }
instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS);
me->setActive(true);
+ DoZoneInCombat();
if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
stalagg->setActive(true);
if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
@@ -239,7 +273,7 @@ public:
feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX);
feugenAlive = false;
if (stalaggAlive)
- events.ScheduleEvent(EVENT_REVIVE_FEUGEN, 5 * IN_MILLISECONDS, 0, PHASE_PETS);
+ events.ScheduleEvent(EVENT_REVIVE_FEUGEN, Seconds(5), 0, PHASE_PETS);
else
Transition();
@@ -249,7 +283,7 @@ public:
stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX);
stalaggAlive = false;
if (feugenAlive)
- events.ScheduleEvent(EVENT_REVIVE_STALAGG, 5 * IN_MILLISECONDS, 0, PHASE_PETS);
+ events.ScheduleEvent(EVENT_REVIVE_STALAGG, Seconds(5), 0, PHASE_PETS);
else
Transition();
@@ -274,9 +308,9 @@ public:
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- events.ScheduleEvent(EVENT_TRANSITION_1, 10 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
- events.ScheduleEvent(EVENT_TRANSITION_2, 12 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
- events.ScheduleEvent(EVENT_TRANSITION_3, 14 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_1, Seconds(10), 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_2, Seconds(12), 0, PHASE_TRANSITION);
+ events.ScheduleEvent(EVENT_TRANSITION_3, Seconds(14), 0, PHASE_TRANSITION);
}
void BeginResetEncounter(bool initial = false)
@@ -286,16 +320,12 @@ public:
if (events.IsInPhase(PHASE_RESETTING))
return;
- if (initial) // signal shorter spawn timer to instance script
- instance->SetBossState(BOSS_THADDIUS, SPECIAL);
- instance->ProcessEvent(me, EVENT_THADDIUS_BEGIN_RESET);
- instance->SetBossState(BOSS_THADDIUS, NOT_STARTED);
-
// remove polarity shift debuffs on reset
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY);
me->DespawnOrUnsummon();
+ me->SetRespawnTime(initial ? 5 : 30);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
events.SetPhase(PHASE_RESETTING);
@@ -312,11 +342,9 @@ public:
feugenAlive = true;
stalaggAlive = true;
- me->Respawn(true);
_Reset();
events.SetPhase(PHASE_NOT_ENGAGED);
-
- me->CastSpell(me, SPELL_THADDIUS_INACTIVE_VISUAL, true);
+ me->SetReactState(REACT_PASSIVE);
if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
feugen->AI()->DoAction(ACTION_RESET_ENCOUNTER);
@@ -361,16 +389,20 @@ public:
break;
case EVENT_TRANSITION_3: // thaddius becomes active
me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
- ballLightningEnabled = false;
+ ballLightningUnlocked = false;
me->RemoveAura(SPELL_THADDIUS_INACTIVE_VISUAL);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
+ me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat();
if (Unit* closest = SelectTarget(SELECT_TARGET_NEAREST, 0, 500.0f))
AttackStart(closest);
else // if there is no nearest target, then there is no target, meaning we should reset
- return BeginResetEncounter();
+ {
+ BeginResetEncounter();
+ return;
+ }
if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
feugen->AI()->DoAction(ACTION_TRANSITION_3);
@@ -381,20 +413,20 @@ public:
Talk(SAY_AGGRO);
- events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, 5 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_SHIFT, 10 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, 0, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, Seconds(5), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT, Seconds(10), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_CHAIN, randtime(Seconds(10), Seconds(20)), 0, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_BERSERK, Minutes(6), 0, PHASE_THADDIUS);
break;
case EVENT_ENABLE_BALL_LIGHTNING:
- ballLightningEnabled = true;
+ ballLightningUnlocked = true;
break;
case EVENT_SHIFT:
me->CastStop(); // shift overrides all other spells
DoCastAOE(SPELL_POLARITY_SHIFT);
- events.ScheduleEvent(EVENT_SHIFT_TALK, 3 * IN_MILLISECONDS, PHASE_THADDIUS);
- events.ScheduleEvent(EVENT_SHIFT, 30 * IN_MILLISECONDS, PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT_TALK, Seconds(3), PHASE_THADDIUS);
+ events.ScheduleEvent(EVENT_SHIFT, Seconds(30), PHASE_THADDIUS);
break;
case EVENT_SHIFT_TALK:
Talk(SAY_ELECT);
@@ -402,12 +434,12 @@ public:
break;
case EVENT_CHAIN:
if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
- events.ScheduleEvent(EVENT_CHAIN, 3 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
+ events.Repeat(Seconds(3));
else
{
me->CastStop();
DoCastVictim(SPELL_CHAIN_LIGHTNING);
- events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, PHASE_THADDIUS);
+ events.Repeat(randtime(Seconds(10), Seconds(20)));
}
break;
case EVENT_BERSERK:
@@ -418,22 +450,24 @@ public:
break;
}
}
-
- if (events.IsInPhase(PHASE_THADDIUS))
+ if (events.IsInPhase(PHASE_THADDIUS) && !me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady())
{
if (me->IsWithinMeleeRange(me->GetVictim()))
+ {
+ ballLightningEnabled = false;
DoMeleeAttackIfReady();
- else
- if (ballLightningEnabled)
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- DoCast(target, SPELL_BALL_LIGHTNING);
+ }
+ else if (ballLightningUnlocked)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(target, SPELL_BALL_LIGHTNING);
}
}
private:
bool stalaggAlive;
bool feugenAlive;
- bool ballLightningEnabled;
+ bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice
+ bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range
bool shockingEligibility;
};
@@ -652,7 +686,7 @@ public:
else
{
DoCast(me, SPELL_STALAGG_POWERSURGE);
- powerSurgeTimer = urand(25, 30) * IN_MILLISECONDS;
+ powerSurgeTimer = urandms(25, 30);
}
}
else
@@ -836,7 +870,7 @@ public:
Talk(SAY_FEUGEN_AGGRO);
if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
- thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO);
+ thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO);
if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
if (!stalagg->IsInCombat())
@@ -1094,7 +1128,7 @@ class spell_thaddius_polarity_charge : public SpellScriptLoader
SpellScript* GetSpellScript() const override
{
- return new spell_thaddius_polarity_charge_SpellScript;
+ return new spell_thaddius_polarity_charge_SpellScript();
}
};
@@ -1212,6 +1246,10 @@ class spell_thaddius_magnetic_pull : public SpellScriptLoader
feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true);
+ // @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair
+ feugen->AddAura(SPELL_ROOT_SELF, feugen);
+ stalagg->AddAura(SPELL_ROOT_SELF, stalagg);
+
// and make both attack their respective new tanks
if (feugen->GetAI())
feugen->GetAI()->AttackStart(stalaggTank);
diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
index 77657d71ffc..02b82d255cd 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -100,36 +100,6 @@ ObjectData const objectData[] =
{ 0, 0, }
};
-// from P2 teleport spell stored target
-float const HeiganPos[2] = { 2793.86f, -3707.38f };
-float const HeiganEruptionSlope[3] =
-{
- (-3703.303223f - HeiganPos[1]) / (2777.494141f - HeiganPos[0]), // between right center and far right
- (-3696.948242f - HeiganPos[1]) / (2785.624268f - HeiganPos[0]), // between left and right halves
- (-3691.880615f - HeiganPos[1]) / (2790.280029f - HeiganPos[0]) // between far left and left center
-};
-
-// 0 H x
-// 1 ^
-// 2 |
-// 3 y<--o
-inline uint32 GetEruptionSection(float x, float y)
-{
- y -= HeiganPos[1];
- if (y < 1.0f)
- return 0;
-
- x -= HeiganPos[0];
- if (x > -1.0f)
- return 3;
-
- float slope = y/x;
- for (uint32 i = 0; i < 3; ++i)
- if (slope > HeiganEruptionSlope[i])
- return i;
- return 3;
-}
-
class instance_naxxramas : public InstanceMapScript
{
public:
@@ -149,6 +119,7 @@ class instance_naxxramas : public InstanceMapScript
hadAnubRekhanGreet = false;
hadFaerlinaGreet = false;
hadThaddiusGreet = false;
+ hadSapphironBirth = false;
CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT;
playerDied = 0;
@@ -208,28 +179,8 @@ class instance_naxxramas : public InstanceMapScript
}
}
- void ProcessEvent(WorldObject* /*source*/, uint32 eventId) override
- {
- switch (eventId)
- {
- case EVENT_THADDIUS_BEGIN_RESET:
- if (GetBossState(BOSS_THADDIUS) == SPECIAL) // this is the initial spawn, we want a shorter spawn time
- events.ScheduleEvent(EVENT_THADDIUS_RESET, 5 * IN_MILLISECONDS);
- else
- events.ScheduleEvent(EVENT_THADDIUS_RESET, 30 * IN_MILLISECONDS);
- break;
- }
- }
-
void OnGameObjectCreate(GameObject* go) override
{
- if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287)
- {
- uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY());
- HeiganEruptionGUID[section].insert(go->GetGUID());
- return;
- }
-
switch (go->GetEntry())
{
case GO_GOTHIK_GATE:
@@ -273,37 +224,18 @@ class instance_naxxramas : public InstanceMapScript
if (GetBossState(BOSS_HORSEMEN) == DONE)
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
break;
- default:
- break;
- }
-
- InstanceScript::OnGameObjectCreate(go);
- }
-
- void OnGameObjectRemove(GameObject* go) override
- {
- if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287)
- {
- uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY());
- HeiganEruptionGUID[section].erase(go->GetGUID());
- return;
- }
-
- switch (go->GetEntry())
- {
case GO_BIRTH:
- if (SapphironGUID)
+ if (hadSapphironBirth || GetBossState(BOSS_SAPPHIRON) == DONE)
{
- if (Creature* sapphiron = instance->GetCreature(SapphironGUID))
- sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH);
- return;
+ hadSapphironBirth = true;
+ go->Delete();
}
break;
default:
break;
}
- InstanceScript::OnGameObjectRemove(go);
+ InstanceScript::OnGameObjectCreate(go);
}
void OnUnitDeath(Unit* unit) override
@@ -328,9 +260,6 @@ class instance_naxxramas : public InstanceMapScript
{
switch (id)
{
- case DATA_HEIGAN_ERUPT:
- HeiganErupt(value);
- break;
case DATA_GOTHIK_GATE:
if (GameObject* gate = instance->GetGameObject(GothikGateGUID))
gate->SetGoState(GOState(value));
@@ -347,6 +276,9 @@ class instance_naxxramas : public InstanceMapScript
case DATA_HAD_THADDIUS_GREET:
hadThaddiusGreet = (value == 1u);
break;
+ case DATA_HAD_SAPPHIRON_BIRTH:
+ hadSapphironBirth = (value == 1u);
+ break;
default:
break;
}
@@ -364,6 +296,8 @@ class instance_naxxramas : public InstanceMapScript
return hadFaerlinaGreet ? 1u : 0u;
case DATA_HAD_THADDIUS_GREET:
return hadThaddiusGreet ? 1u : 0u;
+ case DATA_HAD_SAPPHIRON_BIRTH:
+ return hadSapphironBirth ? 1u : 0u;
default:
break;
}
@@ -399,6 +333,8 @@ class instance_naxxramas : public InstanceMapScript
return StalaggGUID;
case DATA_THADDIUS:
return ThaddiusGUID;
+ case DATA_SAPPHIRON:
+ return SapphironGUID;
case DATA_KELTHUZAD:
return KelthuzadGUID;
case DATA_KELTHUZAD_PORTAL01:
@@ -431,7 +367,7 @@ class instance_naxxramas : public InstanceMapScript
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_ARACHNID))
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
- events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
+ events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
}
break;
case BOSS_LOATHEB:
@@ -440,7 +376,7 @@ class instance_naxxramas : public InstanceMapScript
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_PLAGUE))
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
- events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
+ events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
}
break;
case BOSS_THADDIUS:
@@ -449,12 +385,12 @@ class instance_naxxramas : public InstanceMapScript
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_CONSTRUCT))
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
- events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
+ events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
}
break;
case BOSS_GOTHIK:
if (state == DONE)
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, 10000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, Seconds(10));
break;
case BOSS_HORSEMEN:
if (state == DONE)
@@ -468,12 +404,12 @@ class instance_naxxramas : public InstanceMapScript
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_MILITARY))
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
- events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
+ events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
}
break;
case BOSS_SAPPHIRON:
if (state == DONE)
- events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, Seconds(6));
break;
default:
break;
@@ -493,37 +429,37 @@ class instance_naxxramas : public InstanceMapScript
case EVENT_DIALOGUE_GOTHIK_KORTHAZZ:
if (Creature* korthazz = instance->GetCreature(ThaneGUID))
korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, 5000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, Seconds(5));
break;
case EVENT_DIALOGUE_GOTHIK_ZELIEK:
if (Creature* zeliek = instance->GetCreature(SirGUID))
zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, Seconds(6));
break;
case EVENT_DIALOGUE_GOTHIK_BLAUMEUX:
if (Creature* blaumeux = instance->GetCreature(LadyGUID))
blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, Seconds(6));
break;
case EVENT_DIALOGUE_GOTHIK_RIVENDARE:
if (Creature* rivendare = instance->GetCreature(BaronGUID))
rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, Seconds(6));
break;
case EVENT_DIALOGUE_GOTHIK_BLAUMEUX2:
if (Creature* blaumeux = instance->GetCreature(LadyGUID))
blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, Seconds(6));
break;
case EVENT_DIALOGUE_GOTHIK_ZELIEK2:
if (Creature* zeliek = instance->GetCreature(SirGUID))
zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, Seconds(6));
break;
case EVENT_DIALOGUE_GOTHIK_KORTHAZZ2:
if (Creature* korthazz = instance->GetCreature(ThaneGUID))
korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
- events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, Seconds(6));
break;
case EVENT_DIALOGUE_GOTHIK_RIVENDARE2:
if (Creature* rivendare = instance->GetCreature(BaronGUID))
@@ -540,62 +476,39 @@ class instance_naxxramas : public InstanceMapScript
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD);
HandleGameObject(KelthuzadDoorGUID, false);
- events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, Seconds(6));
break;
case EVENT_DIALOGUE_SAPPHIRON_LICHKING:
if (Creature* lichKing = instance->GetCreature(LichKingGUID))
lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING);
- events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, 16000);
+ events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, Seconds(16));
break;
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2:
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2);
- events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, 9000);
+ events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, Seconds(9));
break;
case EVENT_DIALOGUE_SAPPHIRON_LICHKING2:
if (Creature* lichKing = instance->GetCreature(LichKingGUID))
lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING2);
- events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, 12000);
+ events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, Seconds(12));
break;
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3:
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3);
- events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, 6000);
+ events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, Seconds(6));
break;
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4:
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4);
HandleGameObject(KelthuzadDoorGUID, true);
break;
- case EVENT_THADDIUS_RESET:
- if (GetBossState(BOSS_THADDIUS) != DONE)
- if (Creature* thaddius = instance->GetCreature(ThaddiusGUID))
- thaddius->AI()->DoAction(-1);
- break;
default:
break;
}
}
}
- void HeiganErupt(uint32 section)
- {
- for (uint32 i = 0; i < 4; ++i)
- {
- if (i == section)
- continue;
-
- for (ObjectGuid guid : HeiganEruptionGUID[i])
- {
- if (GameObject* heiganEruption = instance->GetGameObject(guid))
- {
- heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress());
- heiganEruption->CastSpell(NULL, SPELL_ERUPTION);
- }
- }
- }
- }
-
// This Function is called in CheckAchievementCriteriaMeet and CheckAchievementCriteriaMeet is called before SetBossState(bossId, DONE),
// so to check if all bosses are done the checker must exclude 1 boss, the last done, if there is at most 1 encouter in progress when is
// called this function then all bosses are done. The one boss that check is the boss that calls this function, so it is dead.
@@ -653,7 +566,6 @@ class instance_naxxramas : public InstanceMapScript
/* The Plague Quarter */
// Heigan the Unclean
- GuidSet HeiganEruptionGUID[4];
ObjectGuid HeiganGUID;
/* The Military Quarter */
@@ -688,6 +600,7 @@ class instance_naxxramas : public InstanceMapScript
bool hadAnubRekhanGreet;
bool hadFaerlinaGreet;
bool hadThaddiusGreet;
+ bool hadSapphironBirth;
uint8 CurrentWingTaunt;
/* The Immortal / The Undying */
diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
index c0caa86e93f..bece5a60bee 100644
--- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h
+++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h
@@ -43,12 +43,11 @@ enum Encounter
enum Data
{
- DATA_HEIGAN_ERUPT,
DATA_GOTHIK_GATE,
- DATA_SAPPHIRON_BIRTH,
DATA_HAD_ANUBREKHAN_GREET,
DATA_HAD_FAERLINA_GREET,
DATA_HAD_THADDIUS_GREET,
+ DATA_HAD_SAPPHIRON_BIRTH,
DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT,
DATA_ABOMINATION_KILLED,
@@ -73,6 +72,7 @@ enum Data64
DATA_HEIGAN,
DATA_FEUGEN,
DATA_STALAGG,
+ DATA_SAPPHIRON,
DATA_KELTHUZAD,
DATA_KELTHUZAD_PORTAL01,
DATA_KELTHUZAD_PORTAL02,
@@ -158,12 +158,6 @@ enum GameObjectsIds
GO_NAXX_PORTAL_MILITARY = 181578
};
-enum SpellIds
-{
- SPELL_ERUPTION = 29371,
- SPELL_SLIME = 28801
-};
-
enum InstanceEvents
{
// Dialogue that happens after Gothik's death.
@@ -176,10 +170,6 @@ enum InstanceEvents
EVENT_DIALOGUE_GOTHIK_KORTHAZZ2,
EVENT_DIALOGUE_GOTHIK_RIVENDARE2,
- // Thaddius AI requesting timed encounter (re-)spawn
- EVENT_THADDIUS_BEGIN_RESET,
- EVENT_THADDIUS_RESET,
-
// Dialogue that happens after each wing.
EVENT_KELTHUZAD_WING_TAUNT,