aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortreeston <treeston.mmoc@gmail.com>2016-02-08 19:41:09 +0100
committertreeston <treeston.mmoc@gmail.com>2016-03-08 13:36:57 +0100
commitf4f7e6324d6c99335bf3479f212edea1e5572f88 (patch)
treebe219b07a14fd37c768f6282e4e11e86a2ed0f57
parent62815c6e1c0427e1d0229d02b1ba70449654cded (diff)
Scripts/Naxxramas: Clean-up and bug-fix megacommit. Read the full commit message if you care.
- Maexxna: - No longer packages pets and returns them to sender. Web Wrap now only targets players. - Heigan the Unclean: Ripped its guts out. - Instance script hacks are gone. - GO spawns (done using the time-honored TC tradition of "eh, this'll work") are gone. You could say I evacuated the dance floor. - Sniffed spawns for all segments of the room. Because if you don't dance - well, you're no friends of mine. - Loatheb: - First spore now spawns properly after 18 seconds on 10-man (down from 36 seconds). Time between subsequent spawns is unchanged. - Thaddius: - Instance script hacks are gone. Again. Feels good man. - Players no longer drop out of combat during the phase transition. Put your snacks away, this is supposed to be a tense situation! - Thaddius will no longer savagely punish the main tank for stepping out of melee range for a fraction of a second by turning around and ball lightning-ing someone in the face. Typically a healer. He hates healers. - Thaddius will instead take out his frustration on another melee range target if available by smacking them in the face with his fists. It hurts, but a Ball Lightning would've hurt more. Blame the tank. - Feugen and Stalagg have been re-educated to improve their patience when a new target is flying towards them. They will no longer move while Magnetic Pull targets are mid-air, which should prevent them from running off their platform while the warrior helplessly flails trying to get them back. - 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 out on raid groups by throwing unsolved two-colored variants at them. Fixes and closes #14966. - Death Knight Understudies will now realize that their situation is Hopeless even if they're currently mind controlled by a player. Apparently, if your situation is hopeless you take 5000% extra damage. No, that is supposed to be three zeroes. - Gothik the Harvester: - Gothik has been schooled in proper Shadow Bolt spamming etiquette and will now take a brief pause to catch a breath and recompose himself between bolts. - The Four Horsemen: - Will no longer stop and stare at the group sometimes when engaged instead of starting the encounter. - Horsemen can no longer be affected by stun, snare and shackle (heh, yeah, you could totally shackle Baron Rivendare) effects. It's called "Four Horsemen" after all, not "Three Horsemen that never attack because their friend can't move". - Sapphiron: - When attempting to FREEZE THE BLOOD IN YOUR VEINS... Wait, no. Wrong boss. I was thinking of #16634. - Anyways, when freezing people into an Ice Block, Sapphiron now takes care to actually place the block on top of the frozen player, even if they were moving or jumping when the bolt hit them. Yay for positioning clarity! - Sapphiron has been sent to take multiple mandatory courses in "How to treat raid parties fairly while attempting to murder them" and will thus... - ...now properly pause after taking off to allow players to get into position before smacking them with ice bolts - ...no longer deal damage to players inside an Ice Block while they cannot fight back. - Being forced to attend the courses mentioned above has led to a large amount of pent-up frustration, which Sapphiron relieves by quite forcefully flapping his wings during take-off. Players immediately below him are now properly knocked back. - In addition, Kel'thuzad was sick of Sapphiron's continous pouting and allowed him to make Blizzard more malicious in exchange. Blizzard will now properly spawn near players and chase them down instead of pathing randomly. - Also, tons of code style cleanups and hack removal that wasn't mentioned above. Read the diff if you really care.
-rw-r--r--sql/updates/world/9999_99_99_99_NAXXCLEANUP.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.cpp116
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp149
-rw-r--r--src/server/scripts/Northrend/Naxxramas/naxxramas.h14
19 files changed, 842 insertions, 533 deletions
diff --git a/sql/updates/world/9999_99_99_99_NAXXCLEANUP.sql b/sql/updates/world/9999_99_99_99_NAXXCLEANUP.sql
new file mode 100644
index 00000000000..9195b652288
--- /dev/null
+++ b/sql/updates/world/9999_99_99_99_NAXXCLEANUP.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 23e2f144ff2..4b1a607b046 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 0f80d83e0ff..50c5c7c737b 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3050,6 +3050,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 be12894ebea..5e6983c41ce 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..65174697409 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 7330f90e585..a197f113d91 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,10 +170,12 @@ 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)
- {
+ {
events.SetPhase(PHASE_NOT_ENGAGED);
SetCombatMovement(false);
@@ -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 c8a4eb7fbc8..7f9a66c275e 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,