diff options
10 files changed, 3848 insertions, 36 deletions
diff --git a/sql/updates/world/2011_10_05_01_world_instance_misc.sql b/sql/updates/world/2011_10_05_01_world_instance_misc.sql new file mode 100644 index 00000000000..656cdd575d2 --- /dev/null +++ b/sql/updates/world/2011_10_05_01_world_instance_misc.sql @@ -0,0 +1,201 @@ +DELETE FROM `creature_text` WHERE `entry` IN (36597,38995,38579,36823,39217); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(36597,0,0,'So the Light''s vaunted justice has finally arrived? Shall I lay down Frostmourne and throw myself at your mercy, Fordring?',14,0,0,0,0,17349,'The Lich King - SAY_LK_INTRO_1'), +(36597,1,0,'You''ll learn of that first hand. When my work is complete, you will beg for mercy -- and I will deny you. Your anguished cries will be testament to my unbridled power...',14,0,0,22,0,17350,'The Lich King - SAY_LK_INTRO_2'), +(36597,2,0,'I''ll keep you alive to witness the end, Fordring. I would not want the Light''s greatest champion to miss seeing this wretched world remade in my image.',14,0,0,0,0,17351,'The Lich King - SAY_LK_INTRO_3'), +(36597,3,0,'Come then champions, feed me your rage!',14,0,0,0,0,0,'The Lich King - SAY_LK_AGGRO'), +(36597,4,0,'I will freeze you from within until all that remains is an icy husk!',14,0,0,0,0,17369,'The Lich King - SAY_LK_REMORSELESS_WINTER'), +(36597,5,0,'Watch as the world around you collapses!',14,0,0,0,0,17370,'The Lich King - SAY_LK_QUAKE'), +(36597,6,0,'Val''kyr, your master calls!',14,0,0,0,0,17373,'The Lich King - SAY_LK_SUMMON_VALKYR'), +(36597,7,0,'Frostmourne hungers...',14,0,0,0,0,17366,'The Lich King - SAY_LK_HARVEST_SOUL'), +(36597,8,0,'Argh... Frostmourne, obey me!',14,0,0,0,0,17367,'The Lich King - SAY_LK_FROSTMOURNE_ESCAPE'), +(36597,9,0,'Frostmourne feeds on the soul of your fallen ally!',14,0,0,0,0,17368,'The Lich King - SAY_LK_FROSTMOURNE_KILL'), +(36597,10,0,'Hope wanes!',14,0,0,0,0,17363,'The Lich King - SAY_LK_KILL'), +(36597,10,1,'The end has come!',14,0,0,0,0,17364,'The Lich King - SAY_LK_KILL'), +(36597,11,0,'Face now your tragic end!',14,0,0,0,0,17365,'The Lich King - SAY_LK_BERSERK'), +(36597,12,0,'%s begins to cast Defile!',41,0,0,0,0,0,'The Lich King - EMOTE_DEFILE_WARNING'), +(36597,13,0,'|TInterface\\Icons\\ability_creature_disease_02.blp:16|tYou have been infected by |cFFCF00FFNecrotic Plague!|r',42,0,0,0,0,0,'The Lich King - EMOTE_NECROTIC_PLAGUE_WARNING'), +(36597,14,0,'No questions remain unanswered. No doubts linger. You ARE Azeroth''s greatest champions. You overcame every challenge I laid before you. My mightiest servants have fallen before your relentless onslaught... your unbridled fury...',14,0,0,0,0,17353,'The Lich King - SAY_LK_OUTRO_1'), +(36597,15,0,'Is it truly the righteousness that drives you? I wonder...',14,0,0,0,0,17354,'The Lich King - SAY_LK_OUTRO_2'), +(36597,16,0,'You trained them well, Fordring. You delivered the greatest fighting force this world has ever known... right into my hands -- exactly as I intended. You shall be rewarded for your unwitting sacrifice.',14,0,0,0,0,17355,'The Lich King - SAY_LK_OUTRO_3'), +(36597,17,0,'Watch now as I raise them from the dead to become masters of the Scourge. They will shroud this world in chaos and destruction. Azeroth''s fall will come at their hands -- and you will be the first to die.',14,0,0,0,0,17356,'The Lich King - SAY_LK_OUTRO_4'), +(36597,18,0,'I delight in the irony...',14,0,0,0,0,17357,'The Lich King - SAY_LK_OUTRO_5'), +(36597,19,0,'Impossible...',14,0,0,0,0,17358,'The Lich King - SAY_LK_OUTRO_6'), +(36597,20,0,'Now I stand, the lion before the lambs... and they do not fear.',14,0,0,0,0,17361,'The Lich King - SAY_LK_OUTRO_7'), +(36597,21,0,'They cannot fear.',14,0,0,0,0,17362,'The Lich King - SAY_LK_OUTRO_8'), +(38995,0,0,'We''ll grant you a swift death, Arthas. More than can be said for the thousands you''ve tortured and slain.',14,0,0,0,0,17390,'Highlord Tirion Fordring - SAY_TIRION_INTRO_1'), +(38995,1,0,'So be it. Champions, attack!',14,0,0,0,0,17391,'Highlord Tirion Fordring - SAY_TIRION_INTRO_2'), +(38995,2,0,'LIGHT, GRANT ME ONE FINAL BLESSING. GIVE ME THE STRENGTH... TO SHATTER THESE BONDS!',14,0,0,0,0,17392,'Highlord Tirion Fordring - SAY_TIRION_OUTRO_1'), +(38995,3,0,'No more, Arthas! No more lives will be consumed by your hatred!',14,0,0,0,0,17393,'Highlord Tirion Fordring - SAY_TIRION_OUTRO_2'), +(38579,0,0,'Free at last! It is over, my son. This is the moment of reckoning.',14,0,0,1,0,17397,'Terenas Menethil - SAY_TERENAS_OUTRO_1'), +(38579,1,0,'Rise up, champions of the Light!',14,0,0,0,0,17398,'Terenas Menethil - SAY_TERENAS_OUTRO_2'), +(36823,0,0,'You have come to bring Arthas to justice? To see the Lich King destroyed?',14,0,0,0,0,17394,'Terenas Menethil - SAY_TERENAS_INTRO_1'), +(36823,1,0,'First, you must escape Frostmourne''s hold, or be damned as I am; trapped within this cursed blade for all eternity.',14,0,0,0,0,17395,'Terenas Menethil - SAY_TERENAS_INTRO_2'), +(36823,2,0,'Aid me in destroying these tortured souls! Together we will loosen Frostmourne''s hold and weaken the Lich King from within!',14,0,0,0,0,17396,'Terenas Menethil - SAY_TERENAS_INTRO_3'), +(39217,0,0,'You have come to bring Arthas to justice? To see the Lich King destroyed?',14,0,0,0,0,17394,'Terenas Menethil - SAY_TERENAS_INTRO_1'), +(39217,1,0,'First, you must escape Frostmourne''s hold, or be damned as I am; trapped within this cursed blade for all eternity.',14,0,0,0,0,17395,'Terenas Menethil - SAY_TERENAS_INTRO_2'); + +-- Text corrections +DELETE FROM `creature_text` WHERE `entry`=36627 AND `groupid` IN (4,9); +DELETE FROM `creature_text` WHERE `entry`=36678 AND `groupid`=9; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(36627,4,0,'|TInterface\\Icons\\spell_shadow_unstableaffliction_2.blp:16|t%s begins to cast |cFFFF0000Unstable Ooze Explosion!|r',41,0,0,0,0,0,'Rotface - EMOTE_UNSTABLE_EXPLOSION'), +(36627,9,0,'|TInterface\\Icons\\ability_creature_disease_02.blp:16|tYou have |cFF00FF00Mutated Infection!|r',42,0,0,0,0,0,'Rotface - EMOTE_MUTATED_INFECTION'), +(36678,9,0,'|TInterface\\Icons\\inv_misc_herb_evergreenmoss.blp:16|t%s cast |cFF00FF00Malleable Goo!|r',41,0,0,0,0,0,'Professor Putricide - EMOTE_MALLEABLE_GOO'); + +UPDATE `creature_template` SET `speed_walk`=2,`speed_run`=1.71429,`exp`=2,`minlevel`=83,`maxlevel`=83,`faction_A`=974,`faction_H`=974,`unit_flags`=768,`dynamicflags`=0,`equipment_id`=2425,`baseattacktime`=1500 WHERE `entry` IN (36597,39166,39167,39168); -- The Lich King +UPDATE `creature_template` SET `exp`=2,`unit_class`=2 WHERE `entry`=38995; -- Highlord Tirion Fordring +UPDATE `creature_template` SET `speed_walk`=1.2,`speed_run`=0.428571,`exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=14,`faction_H`=14,`dynamicflags`=0 WHERE `entry` IN (36633,39305,39306,39307); -- Ice Sphere +UPDATE `creature_template` SET `speed_walk`=2,`speed_run`=1.42857,`exp`=2,`minlevel`=83,`maxlevel`=83,`faction_A`=14,`faction_H`=14,`dynamicflags`=0 WHERE `entry`=36701; -- Raging Spirit +UPDATE `creature_template` SET `speed_walk`=1.2,`speed_run`=0.428571,`exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=14,`faction_H`=14,`dynamicflags`=0,`unit_flags`=33554944 WHERE `entry`=38757; -- Defile +UPDATE `creature_template` SET `minlevel`=80,`maxlevel`=80,`exp`=2,`faction_A`=14,`faction_H`=14,`speed_walk`=2,`speed_run`=1.71429,`unit_flags`=33554944,`dynamicflags`=0,`VehicleId`=532,`InhabitType`=1|4 WHERE `entry` IN (36609,39120,39121,39122); -- Val'kyr Shadowguard +UPDATE `creature_template` SET `speed_walk`=2,`speed_run`=1.71429,`exp`=2,`minlevel`=83,`maxlevel`=83,`faction_A`=35,`faction_H`=35,`unit_flags`=33554944,`dynamicflags`=0,`VehicleId`=531,`InhabitType`=1|4,`flags_extra`=0 WHERE `entry`=36598; -- Strangulate Vehicle +UPDATE `creature_template` SET `speed_walk`=1.2,`speed_run`=0.428571,`exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=14,`faction_H`=14,`unit_flags`=33554944,`dynamicflags`=0,`flags_extra`=128 WHERE `entry`=38584; -- Frostmourne Trigger +UPDATE `creature_template` SET `speed_walk`=2.8,`speed_run`=1,`exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=14,`faction_H`=14,`unit_flags`=32832,`dynamicflags`=0,`flags_extra`=256,`InhabitType`=1|4 WHERE `entry` IN (37799,39284,39285,39286); -- Vile Spirit +UPDATE `creature_template` SET `speed_walk`=1,`speed_run`=1,`exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=1665,`faction_H`=1665,`unit_flags`=32832,`dynamicflags`=0,`flags_extra`=0,`equipment_id`=2475 WHERE `entry` IN (36823,38579,39217); -- Terenas Menethil +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|128 WHERE `entry`=24648; -- Invisible Stalker (Scale x2) +UPDATE `creature_template` SET `difficulty_entry_1`=39287,`difficulty_entry_2`=39288,`difficulty_entry_3`=39289 WHERE `entry`=39190; -- Wicked Spirit +UPDATE `creature_template` SET `speed_walk`=2.8,`speed_run`=1,`exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=14,`faction_H`=14,`unit_flags`=32832,`dynamicflags`=0,`flags_extra`=256,`InhabitType`=1|4 WHERE `entry` IN (39190,39287,39288,39289); -- Wicked Spirit +UPDATE `creature_template` SET `exp`=2,`minlevel`=83,`maxlevel`=83,`faction_A`=14,`faction_H`=14,`dynamicflags`=0,`flags_extra`=256 WHERE `entry`=36824; -- Spirit Warden +UPDATE `creature_template` SET `exp`=2,`minlevel`=83,`maxlevel`=83,`faction_A`=14,`faction_H`=14,`dynamicflags`=0,`flags_extra`=128 WHERE `entry`=39137; -- Shadow Trap +UPDATE `creature_template` SET `exp`=2,`minlevel`=80,`maxlevel`=80,`faction_A`=14,`faction_H`=14,`InhabitType`=1|4,`flags_extra`=`flags_extra`|128 WHERE `entry`=39189; -- Spirit Bomb + +-- HACK, Unit::_IsValidAttackTarget returns false because of UNIT_FLAG_OOC_NOT_ATTACKABLE flag +UPDATE `creature_template` SET `unit_flags`=0x02000000 WHERE `entry`=36171; + +UPDATE `creature_model_info` SET `combat_reach`=5.5 WHERE `modelid`=30721; -- The Lich King +UPDATE `creature_model_info` SET `gender`=0 WHERE `modelid`=31286; -- Highlord Tirion Fordring + +DELETE FROM `creature` WHERE `guid`=202865; +DELETE FROM `creature_addon` WHERE `guid`=150211; +INSERT INTO `creature_addon` (`guid`,`bytes1`,`auras`) VALUES +(150211,1,'72846 73220 73878'); -- The Lich King + +DELETE FROM `creature_template_addon` WHERE `entry` IN (39137,36609,39120,39121,39122,36598,37799,39284,39285,39286,39190,39287,39288,39289,36823,38579,39217,39189); +INSERT INTO `creature_template_addon` (`entry`,`bytes1`,`auras`) VALUES +(39137,0,'73530'), +(36609,50331648,''), -- Val'kyr Shadowguard +(39120,50331648,''), -- Val'kyr Shadowguard +(39121,50331648,''), -- Val'kyr Shadowguard +(39122,50331648,''), -- Val'kyr Shadowguard +(36598,50331648,''), -- Strangulate Vehicle +(37799,50331648,''), -- Vile Spirit +(39284,50331648,''), -- Vile Spirit +(39285,50331648,''), -- Vile Spirit +(39286,50331648,''), -- Vile Spirit +(39190,50331648,''), -- Wicked Spirit +(39287,50331648,''), -- Wicked Spirit +(39288,50331648,''), -- Wicked Spirit +(39289,50331648,''), -- Wicked Spirit +(36823,0,'72372'), -- Terenas Menethil +(38579,0,'72372'), -- Terenas Menethil +(39217,0,'72372'), -- Terenas Menethil +(39189,0,'73572'); -- Spirit Bomb + +UPDATE `gameobject` SET `rotation3`=1,`animprogress`=255,`spawntimesecs`=604800 WHERE `guid` IN (100056,100061,100064); +UPDATE `gameobject` SET `rotation2`=1,`animprogress`=255,`spawntimesecs`=604800 WHERE `guid` IN (100057,100058,100059,100060,100062); +UPDATE `gameobject` SET `rotation3`=1,`animprogress`=255,`spawntimesecs`=-604800 WHERE `guid`=100063; + +UPDATE `gameobject_template` SET `faction`=1375,`flags`=32 WHERE `entry`=202438; -- Lavaman Pillars (Unchained) +UPDATE `gameobject_template` SET `faction`=1375,`flags`=32 WHERE `entry`=202188; -- Doodad_Icecrown_ThroneFrostyWind01 +UPDATE `gameobject_template` SET `faction`=1375,`flags`=32 WHERE `entry`=202189; -- Doodad_Icecrown_ThroneFrostyEdge01 + +DELETE FROM `gameobject` WHERE `id`=202438; +INSERT INTO `gameobject` (`guid`,`id`,`map`,`spawnMask`,`position_x`,`position_y`,`position_z`,`rotation3`,`spawntimesecs`,`animprogress`,`state`) VALUES +(100488,202438,631,15,425.0885,-2123.311,858.6748,1,-604800,255,1); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN (71614,70338,73785,73786,73787,68981,74270,74271,74272,72262,71440,76379,74086,72595,73650,72679,74318,74319,74320,73028,74321,74322,74323,73582,71809,71811,72431,72405,72429,73159); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(13,0,71614,0,18,1,38995,0,0, '', 'Ice Lock - target Highlord Tirion Fordring'), +(13,0,70338,0,18,1,0,0,0, '', 'Necrotic Plague - target player'), +(13,0,70338,0,18,1,37698,0,0, '', 'Necrotic Plague - target Shambling Horror'), +(13,0,70338,0,18,1,37695,0,0, '', 'Necrotic Plague - target Drudge Ghoul'), +(13,0,73785,0,18,1,0,0,0, '', 'Necrotic Plague - target player'), +(13,0,73785,0,18,1,37698,0,0, '', 'Necrotic Plague - target Shambling Horror'), +(13,0,73785,0,18,1,37695,0,0, '', 'Necrotic Plague - target Drudge Ghoul'), +(13,0,73786,0,18,1,0,0,0, '', 'Necrotic Plague - target player'), +(13,0,73786,0,18,1,37698,0,0, '', 'Necrotic Plague - target Shambling Horror'), +(13,0,73786,0,18,1,37695,0,0, '', 'Necrotic Plague - target Drudge Ghoul'), +(13,0,73787,0,18,1,0,0,0, '', 'Necrotic Plague - target player'), +(13,0,73787,0,18,1,37698,0,0, '', 'Necrotic Plague - target Shambling Horror'), +(13,0,73787,0,18,1,37695,0,0, '', 'Necrotic Plague - target Drudge Ghoul'), +(13,0,68981,0,18,0,202141,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing02'), +(13,0,68981,0,18,0,202142,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing01'), +(13,0,68981,0,18,0,202143,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing03'), +(13,0,68981,0,18,0,202144,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing04'), +(13,0,74270,0,18,0,202141,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing02'), +(13,0,74270,0,18,0,202142,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing01'), +(13,0,74270,0,18,0,202143,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing03'), +(13,0,74270,0,18,0,202144,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing04'), +(13,0,74271,0,18,0,202141,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing02'), +(13,0,74271,0,18,0,202142,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing01'), +(13,0,74271,0,18,0,202143,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing03'), +(13,0,74271,0,18,0,202144,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing04'), +(13,0,74272,0,18,0,202141,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing02'), +(13,0,74272,0,18,0,202142,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing01'), +(13,0,74272,0,18,0,202143,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing03'), +(13,0,74272,0,18,0,202144,0,0, '', 'Remorseless Winter - target Doodad_IceShard_standing04'), +(13,0,72262,0,18,1,22515,0,0, '', 'Quake - target World Trigger'), +(13,0,71440,0,18,1,36597,0,0, '', 'Harvest Soul - target The Lich King'), +(13,0,76379,0,18,1,36597,0,0, '', 'Harvest Soul - target The Lich King'), +(13,0,74086,0,18,1,0,0,0, '', 'Destroy Soul - target player'), +(13,0,72595,0,18,1,0,0,0, '', 'Restore Soul - target player'), +(13,0,73650,0,18,1,0,0,0, '', 'Restore Soul - target player'), +(13,0,72679,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,74318,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,74319,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,74320,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,73028,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,74321,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,73650,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,74323,0,18,1,36597,0,0, '', 'Harvested Soul - target The Lich King'), +(13,0,73582,0,18,1,39190,0,0, '', 'Trigger Vile Spirit (Inside, Heroic) - target Wicked Spirit'), +(13,0,71809,0,18,1,36597,0,0, '', 'Jump - target The Lich King'), +(13,0,71811,0,18,1,36597,0,0, '', 'Jump - target The Lich King'), +(13,0,72431,0,18,1,0,0,0, '', 'Jump - target player'), +(13,0,72405,0,18,1,38995,0,0, '', 'Broken Frostmourne - target Highlord Tirion Fordring'), +(13,0,72429,0,18,1,0,0,0, '', 'Mass Resurrection - target player'), +(13,0,73159,0,18,1,0,0,0, '', 'Play Movie - target player'); + +DELETE FROM `spell_target_position` WHERE `id` IN (70860,72546,73655); +INSERT INTO `spell_target_position` (`id`,`target_map`,`target_position_x`,`target_position_y`,`target_position_z`,`target_orientation`) VALUES +(70860,631,529.302,-2124.49, 840.857,3.1765), -- Frozen Throne Teleport +(72546,631,514.000,-2523.00,1050.990,3.1765), -- Harvest Soul (normal mode) +(73655,631,495.708,-2523.76,1050.990,3.1765); -- Harvest Soul (heroic mode) + +DELETE FROM `spell_area` WHERE `spell`=74276; +INSERT INTO `spell_area` (`spell`,`area`,`autocast`) VALUES +(74276,4910,1); -- In Frostmourne Room + +DELETE FROM `disables` WHERE `entry` IN (12825,13246,13247,13244,13245,13342,13309,13362,13311,12823,13163,13164,13243,12764,12909,12826,13103,13136,13137,13138,12818) AND `sourceType`=4; +DELETE FROM `achievement_criteria_data` WHERE `criteria_id` IN (12825,13246,13247,13244,13245,13342,13309,13362,13311,12823,13163,13164,13243,12764,12909,12826,13103,13136,13137,13138,12818); +INSERT INTO `achievement_criteria_data` (`criteria_id`,`type`,`value1`,`value2`,`ScriptName`) VALUES +(12825,12,2,0,''), -- Bane of the Fallen King +(13246,11,0,0,'achievement_been_waiting_long_time'), -- Been Waiting a Long Time for This (10 player) +(13246,12,0,0,''), -- Been Waiting a Long Time for This (10 player) +(13247,11,0,0,'achievement_been_waiting_long_time'), -- Been Waiting a Long Time for This (10 player) Heroic +(13247,12,2,0,''), -- Been Waiting a Long Time for This (10 player) Heroic +(13244,11,0,0,'achievement_been_waiting_long_time'), -- Been Waiting a Long Time for This (25 player) +(13244,12,1,0,''), -- Been Waiting a Long Time for This (25 player) +(13245,11,0,0,'achievement_been_waiting_long_time'), -- Been Waiting a Long Time for This (25 player) Heroic +(13245,12,3,0,''), -- Been Waiting a Long Time for This (25 player) Heroic +(13342,12,0,0,''), -- Lich King 10-player bosses killed +(13309,12,0,0,''), -- Lich King 10-player raids completed (final boss killed) +(13362,12,1,0,''), -- Lich King 25-player bosses killed +(13311,12,1,0,''), -- Lich King 25-player raids completed (final boss killed) +(12823,11,0,0,'achievement_neck_deep_in_vile'), -- Neck-Deep in Vile (10 player) +(12823,12,0,0,''), -- Neck-Deep in Vile (10 player) +(13163,11,0,0,'achievement_neck_deep_in_vile'), -- Neck-Deep in Vile (10 player) Heroic +(13163,12,2,0,''), -- Neck-Deep in Vile (10 player) Heroic +(13164,11,0,0,'achievement_neck_deep_in_vile'), -- Neck-Deep in Vile (25 player) +(13164,12,1,0,''), -- Neck-Deep in Vile (25 player) +(13243,11,0,0,'achievement_neck_deep_in_vile'), -- Neck-Deep in Vile (25 player) Heroic +(13243,12,3,0,''), -- Neck-Deep in Vile (25 player) Heroic +(12764,12,0,0,''), -- The Frozen Throne (10 player) +(12909,12,1,0,''), -- The Frozen Throne (25 player) +(12826,12,3,0,''), -- The Light of Dawn +(13103,12,0,0,''), -- Victories over the Lich King (Icecrown 10 player) +(13136,12,1,0,''), -- Victories over the Lich King (Icecrown 25 player) +(13137,12,2,0,''), -- Victories over the Lich King (Heroic Icecrown 10 player) +(13138,12,3,0,''), -- Victories over the Lich King (Heroic Icecrown 25 player) +(12818,12,3,0,''); -- Realm First! Fall of the Lich King diff --git a/sql/updates/world/2011_10_05_01_world_scriptname.sql b/sql/updates/world/2011_10_05_01_world_scriptname.sql new file mode 100644 index 00000000000..742d74f4029 --- /dev/null +++ b/sql/updates/world/2011_10_05_01_world_scriptname.sql @@ -0,0 +1,10 @@ +UPDATE `creature_template` SET `ScriptName`='boss_the_lich_king' WHERE `entry`=36597; +UPDATE `creature_template` SET `ScriptName`='npc_tirion_fordring_tft' WHERE `entry`=38995; +UPDATE `creature_template` SET `ScriptName`='npc_shambling_horror_icc' WHERE `entry`=37698; +UPDATE `creature_template` SET `ScriptName`='npc_raging_spirit' WHERE `entry`=36701; +UPDATE `creature_template` SET `ScriptName`='npc_valkyr_shadowguard' WHERE `entry`=36609; +UPDATE `creature_template` SET `ScriptName`='npc_strangulate_vehicle' WHERE `entry`=36598; +UPDATE `creature_template` SET `ScriptName`='npc_terenas_menethil' WHERE `entry` IN (36823,38579,39217); -- not difficulty_entries +UPDATE `creature_template` SET `ScriptName`='npc_spirit_warden' WHERE `entry`=36824; +UPDATE `creature_template` SET `ScriptName`='npc_spirit_bomb' WHERE `entry`=39189; +UPDATE `creature_template` SET `ScriptName`='npc_broken_frostmourne' WHERE `entry`=38584; diff --git a/sql/updates/world/2011_10_05_01_world_spell_script_names.sql b/sql/updates/world/2011_10_05_01_world_spell_script_names.sql new file mode 100644 index 00000000000..03d4b649e78 --- /dev/null +++ b/sql/updates/world/2011_10_05_01_world_spell_script_names.sql @@ -0,0 +1,90 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_infest'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_necrotic_plague'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_necrotic_plague_jump'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_shadow_trap_visual'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_shadow_trap_periodic'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_quake'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_ice_burst_target_search'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_raging_spirit'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_defile'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_summon_into_air'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_soul_reaper'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_valkyr_target_search'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_eject_all_passengers'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_cast_back_to_caster'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_life_siphon'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_vile_spirits'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_vile_spirits_visual'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_vile_spirit_move_target_search'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_vile_spirit_damage_target_search'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_harvest_soul'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_lights_favor'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_soul_rip'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_restore_soul'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_in_frostmourne_room'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_summon_spirit_bomb'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_trigger_vile_spirit'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_jump'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_jump_remove_aura'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_mass_resurrection'; +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_the_lich_king_play_movie'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(70541,'spell_the_lich_king_infest'), +(73779,'spell_the_lich_king_infest'), +(73780,'spell_the_lich_king_infest'), +(73781,'spell_the_lich_king_infest'), +(70337,'spell_the_lich_king_necrotic_plague'), +(73912,'spell_the_lich_king_necrotic_plague'), +(73913,'spell_the_lich_king_necrotic_plague'), +(73914,'spell_the_lich_king_necrotic_plague'), +(70338,'spell_the_lich_king_necrotic_plague_jump'), +(73785,'spell_the_lich_king_necrotic_plague_jump'), +(73786,'spell_the_lich_king_necrotic_plague_jump'), +(73787,'spell_the_lich_king_necrotic_plague_jump'), +(73530,'spell_the_lich_king_shadow_trap_visual'), +(74282,'spell_the_lich_king_shadow_trap_periodic'), +(72262,'spell_the_lich_king_quake'), +(69110,'spell_the_lich_king_ice_burst_target_search'), +(69200,'spell_the_lich_king_raging_spirit'), +(72754,'spell_the_lich_king_defile'), +(73708,'spell_the_lich_king_defile'), +(73709,'spell_the_lich_king_defile'), +(73710,'spell_the_lich_king_defile'), +(69037,'spell_the_lich_king_summon_into_air'), +(70497,'spell_the_lich_king_summon_into_air'), +(73579,'spell_the_lich_king_summon_into_air'), +(74300,'spell_the_lich_king_summon_into_air'), +(69409,'spell_the_lich_king_soul_reaper'), +(73797,'spell_the_lich_king_soul_reaper'), +(73798,'spell_the_lich_king_soul_reaper'), +(73799,'spell_the_lich_king_soul_reaper'), +(69030,'spell_the_lich_king_valkyr_target_search'), +(68576,'spell_the_lich_king_eject_all_passengers'), +(74445,'spell_the_lich_king_cast_back_to_caster'), +(68984,'spell_the_lich_king_cast_back_to_caster'), +(73488,'spell_the_lich_king_life_siphon'), +(73782,'spell_the_lich_king_life_siphon'), +(73783,'spell_the_lich_king_life_siphon'), +(73784,'spell_the_lich_king_life_siphon'), +(70498,'spell_the_lich_king_vile_spirits'), +(70499,'spell_the_lich_king_vile_spirits_visual'), +(70501,'spell_the_lich_king_vile_spirit_move_target_search'), +(70534,'spell_the_lich_king_vile_spirit_damage_target_search'), +(68980,'spell_the_lich_king_harvest_soul'), +(74325,'spell_the_lich_king_harvest_soul'), +(74296,'spell_the_lich_king_harvest_soul'), +(74297,'spell_the_lich_king_harvest_soul'), +(69382,'spell_the_lich_king_lights_favor'), +(69397,'spell_the_lich_king_soul_rip'), +(72595,'spell_the_lich_king_restore_soul'), +(73650,'spell_the_lich_king_restore_soul'), +(74276,'spell_the_lich_king_in_frostmourne_room'), +(74302,'spell_the_lich_king_summon_spirit_bomb'), +(74341,'spell_the_lich_king_summon_spirit_bomb'), +(74342,'spell_the_lich_king_summon_spirit_bomb'), +(74343,'spell_the_lich_king_summon_spirit_bomb'), +(73582,'spell_the_lich_king_trigger_vile_spirit'), +(71811,'spell_the_lich_king_jump'), +(72431,'spell_the_lich_king_jump_remove_aura'), +(72429,'spell_the_lich_king_mass_resurrection'), +(73159,'spell_the_lich_king_play_movie'); diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 305821095fa..2322e88d105 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -52,8 +52,7 @@ void SummonList::DespawnEntry(uint32 entry) else if (summon->GetEntry() == entry) { erase(i++); - summon->setDeathState(JUST_DIED); - summon->RemoveCorpse(); + summon->DespawnOrUnsummon(); } else ++i; @@ -70,13 +69,7 @@ void SummonList::DespawnAll() else { erase(begin()); - if (TempSummon* summ = summon->ToTempSummon()) - { - summon->DestroyForNearbyPlayers(); - summ->UnSummon(); - } - else - summon->DisappearAndDie(); + summon->DespawnOrUnsummon(); } } } diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 64c92470fd7..26d703458ac 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -479,6 +479,7 @@ void AddSC_boss_blood_prince_council(); void AddSC_boss_blood_queen_lana_thel(); void AddSC_boss_valithria_dreamwalker(); void AddSC_boss_sindragosa(); +void AddSC_boss_the_lich_king(); void AddSC_icecrown_citadel_teleport(); void AddSC_instance_icecrown_citadel(); void AddSC_icecrown_citadel(); @@ -1181,6 +1182,7 @@ void AddNorthrendScripts() AddSC_boss_blood_queen_lana_thel(); AddSC_boss_valithria_dreamwalker(); AddSC_boss_sindragosa(); + AddSC_boss_the_lich_king(); AddSC_icecrown_citadel_teleport(); AddSC_instance_icecrown_citadel(); AddSC_icecrown_citadel(); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index c80a3123739..2a37a55d830 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2803,6 +2803,10 @@ void SpellMgr::LoadSpellCustomAttr() case 43140: // Flame Breath case 43215: // Flame Breath case 70461: // Coldflame Trap + case 72133: // Pain and Suffering + case 73788: // Pain and Suffering + case 73789: // Pain and Suffering + case 73790: // Pain and Suffering spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_LINE; break; case 24340: // Meteor @@ -3327,6 +3331,91 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_TARGET_ANY; spellInfo->Effect[1] = 0; break; + case 71614: // Ice Lock + spellInfo->Mechanic = MECHANIC_STUN; + break; + case 72762: // Defile + spellInfo->DurationIndex = 559; // 53 seconds + break; + case 72743: // Defile + spellInfo->DurationIndex = 22; // 45 seconds + break; + case 72754: // Defile + case 73708: // Defile + case 73709: // Defile + case 73710: // Defile + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + spellInfo->EffectRadiusIndex[1] = 22; // 200yd + break; + case 69030: // Val'kyr Target Search + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + spellInfo->EffectRadiusIndex[1] = 22; // 200yd + break; + case 69198: // Raging Spirit Visual + spellInfo->rangeIndex = 13; // 50000yd + break; + case 73654: // Harvest Souls + case 74295: // Harvest Souls + case 74296: // Harvest Souls + case 74297: // Harvest Souls + spellInfo->EffectRadiusIndex[0] = 28; // 50000yd + spellInfo->EffectRadiusIndex[1] = 28; // 50000yd + spellInfo->EffectRadiusIndex[2] = 28; // 50000yd + break; + case 73655: // Harvest Soul + spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS; + break; + case 73540: // Summon Shadow Trap + spellInfo->DurationIndex = 23; // 90 seconds + break; + case 73530: // Shadow Trap (visual) + spellInfo->DurationIndex = 28; // 5 seconds + break; + case 73529: // Shadow Trap + spellInfo->EffectRadiusIndex[1] = 13; // 10yd + break; + case 74282: // Shadow Trap (searcher) + spellInfo->EffectRadiusIndex[0] = 15; // 3yd + break; + case 72595: // Restore Soul + case 73650: // Restore Soul + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + break; + case 74086: // Destroy Soul + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + break; + case 74302: // Summon Spirit Bomb + case 74342: // Summon Spirit Bomb + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + spellInfo->MaxAffectedTargets = 1; + break; + case 74341: // Summon Spirit Bomb + case 74343: // Summon Spirit Bomb + spellInfo->EffectRadiusIndex[0] = 22; // 200yd + spellInfo->MaxAffectedTargets = 3; + break; + case 73579: // Summon Spirit Bomb + spellInfo->EffectRadiusIndex[0] = 20; // 25yd + break; + case 72350: // Fury of Frostmourne + spellInfo->EffectRadiusIndex[0] = 28; // 50000yd + spellInfo->EffectRadiusIndex[1] = 28; // 50000yd + break; + case 75127: // Kill Frostmourne Players + case 72351: // Fury of Frostmourne + case 72429: // Mass Resurrection + case 73159: // Play Movie + case 73582: // Trigger Vile Spirit (Inside, Heroic) + spellInfo->EffectRadiusIndex[0] = 28; // 50000yd + break; + case 72376: // Raise Dead + spellInfo->MaxAffectedTargets = 3; + spellInfo->EffectRadiusIndex[0] = 28; // 50000yd + break; + case 71809: // Jump + spellInfo->rangeIndex = 3; // 20yd + spellInfo->EffectRadiusIndex[0] = 20; // 25yd + break; default: break; } diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 3e1f500ebce..63e714d17aa 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -173,6 +173,7 @@ set(scripts_STAT_SRCS Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp Northrend/IcecrownCitadel/boss_sindragosa.cpp + Northrend/IcecrownCitadel/boss_the_lich_king.cpp Northrend/zuldrak.cpp Northrend/icecrown.cpp Northrend/Gundrak/boss_slad_ran.cpp diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp new file mode 100644 index 00000000000..5dbdf38ba7f --- /dev/null +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -0,0 +1,3213 @@ +/* + * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Spell.h" +#include "Vehicle.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "icecrown_citadel.h" + +// TODO: +// test outro + +enum Texts +{ + // The Lich King + SAY_LK_INTRO_1 = 0, + SAY_LK_INTRO_2 = 1, + SAY_LK_INTRO_3 = 2, + SAY_LK_REMORSELESS_WINTER = 4, + SAY_LK_QUAKE = 5, + SAY_LK_SUMMON_VALKYR = 6, + SAY_LK_HARVEST_SOUL = 7, + SAY_LK_FROSTMOURNE_ESCAPE = 8, // not said on heroic + SAY_LK_FROSTMOURNE_KILL = 9, // not said on heroic + SAY_LK_KILL = 10, + SAY_LK_BERSERK = 11, + EMOTE_DEFILE_WARNING = 12, + EMOTE_NECROTIC_PLAGUE_WARNING = 13, + SAY_LK_OUTRO_1 = 14, + SAY_LK_OUTRO_2 = 15, + SAY_LK_OUTRO_3 = 16, + SAY_LK_OUTRO_4 = 17, + SAY_LK_OUTRO_5 = 18, + SAY_LK_OUTRO_6 = 19, + SAY_LK_OUTRO_7 = 20, + SAY_LK_OUTRO_8 = 21, + + // Highlord Tirion Fordring + SAY_TIRION_INTRO_1 = 0, + SAY_TIRION_INTRO_2 = 1, + SAY_TIRION_OUTRO_1 = 2, + SAY_TIRION_OUTRO_2 = 3, + + // Terenas Menethil (outro) + SAY_TERENAS_OUTRO_1 = 0, + SAY_TERENAS_OUTRO_2 = 1, + + // Terenas Menethil (Frostmourne) + SAY_TERENAS_INTRO_1 = 0, + SAY_TERENAS_INTRO_2 = 1, + SAY_TERENAS_INTRO_3 = 2, +}; + +enum Spells +{ + // The Lich King + SPELL_PLAGUE_AVOIDANCE = 72846, // raging spirits also get it + SPELL_EMOTE_SIT_NO_SHEATH = 73220, + SPELL_BOSS_HITTIN_YA = 73878, + SPELL_EMOTE_SHOUT_NO_SHEATH = 73213, + SPELL_ICE_LOCK = 71614, + + // Phase 1 + SPELL_SUMMON_SHAMBLING_HORROR = 70372, + SPELL_RISEN_WITCH_DOCTOR_SPAWN = 69639, + SPELL_SUMMON_DRUDGE_GHOULS = 70358, + SPELL_INFEST = 70541, + SPELL_NECROTIC_PLAGUE = 70337, + SPELL_NECROTIC_PLAGUE_JUMP = 70338, + SPELL_PLAGUE_SIPHON = 74074, + SPELL_SHADOW_TRAP = 73539, + SPELL_SHADOW_TRAP_AURA = 73525, + SPELL_SHADOW_TRAP_KNOCKBACK = 73529, + + // Phase Transition + SPELL_REMORSELESS_WINTER_1 = 68981, + SPELL_REMORSELESS_WINTER_2 = 72259, + SPELL_PAIN_AND_SUFFERING = 72133, + SPELL_SUMMON_ICE_SPHERE = 69104, + SPELL_ICE_SPHERE = 69090, + SPELL_ICE_BURST_TARGET_SEARCH = 69109, + SPELL_ICE_PULSE = 69091, + SPELL_ICE_BURST = 69108, + SPELL_RAGING_SPIRIT = 69200, + SPELL_RAGING_SPIRIT_VISUAL = 69197, + SPELL_RAGING_SPIRIT_VISUAL_CLONE = 69198, + SPELL_SOUL_SHRIEK = 69242, + SPELL_QUAKE = 72262, + + // Phase 2 + SPELL_DEFILE = 72762, + SPELL_DEFILE_AURA = 72743, + SPELL_DEFILE_GROW = 72756, + SPELL_SUMMON_VALKYR = 69037, + SPELL_SUMMON_VALKYR_PERIODIC = 74361, + SPELL_HARVEST_SOUL_VALKYR = 68985, // Val'kyr Shadowguard vehicle aura + SPELL_SOUL_REAPER = 69409, + SPELL_SOUL_REAPER_BUFF = 69410, + SPELL_WINGS_OF_THE_DAMNED = 74352, + SPELL_VALKYR_TARGET_SEARCH = 69030, + SPELL_CHARGE = 74399, // cast on selected target + SPELL_VALKYR_CARRY = 74445, // removes unselectable flag + SPELL_LIFE_SIPHON = 73488, + SPELL_LIFE_SIPHON_HEAL = 73489, + SPELL_EJECT_ALL_PASSENGERS = 68576, + + // Phase 3 + SPELL_VILE_SPIRITS = 70498, + SPELL_VILE_SPIRIT_MOVE_SEARCH = 70501, + SPELL_VILE_SPIRIT_DAMAGE_SEARCH = 70502, + SPELL_SPIRIT_BURST = 70503, + SPELL_HARVEST_SOUL = 68980, + SPELL_HARVEST_SOULS = 73654, // Heroic version, weird because it has all 4 difficulties just like above spell + SPELL_HARVEST_SOUL_VEHICLE = 68984, + SPELL_HARVEST_SOUL_VISUAL = 71372, + SPELL_HARVEST_SOUL_TELEPORT = 72546, + SPELL_HARVEST_SOULS_TELEPORT = 73655, + SPELL_HARVEST_SOUL_TELEPORT_BACK = 72597, + SPELL_IN_FROSTMOURNE_ROOM = 74276, + SPELL_KILL_FROSTMOURNE_PLAYERS = 75127, + SPELL_HARVESTED_SOUL = 72679, + SPELL_TRIGGER_VILE_SPIRIT_HEROIC = 73582, + + // Frostmourne + SPELL_LIGHTS_FAVOR = 69382, + SPELL_RESTORE_SOUL = 72595, + SPELL_RESTORE_SOULS = 73650, // Heroic + SPELL_DARK_HUNGER = 69383, // Passive proc healing + SPELL_DESTROY_SOUL = 74086, // Used when Terenas Menethil dies + SPELL_SOUL_RIP = 69397, // Deals increasing damage + SPELL_SOUL_RIP_DAMAGE = 69398, + SPELL_TERENAS_LOSES_INSIDE = 72572, + SPELL_SUMMON_SPIRIT_BOMB_1 = 73581, // (Heroic) + SPELL_SUMMON_SPIRIT_BOMB_2 = 74299, // (Heroic) + SPELL_EXPLOSION = 73576, // Spirit Bomb (Heroic) + + // Outro + SPELL_FURY_OF_FROSTMOURNE = 72350, + SPELL_FURY_OF_FROSTMOURNE_NO_REZ = 72351, + SPELL_EMOTE_QUESTION_NO_SHEATH = 73330, + SPELL_RAISE_DEAD = 71769, + SPELL_LIGHTS_BLESSING = 71797, + SPELL_JUMP = 71809, + SPELL_JUMP_TRIGGERED = 71811, + SPELL_JUMP_2 = 72431, + SPELL_SUMMON_BROKEN_FROSTMOURNE = 74081, // visual + SPELL_SUMMON_BROKEN_FROSTMOURNE_2 = 72406, // animation + SPELL_SUMMON_BROKEN_FROSTMOURNE_3 = 73017, // real summon + SPELL_BROKEN_FROSTMOURNE = 72398, + SPELL_BROKEN_FROSTMOURNE_KNOCK = 72405, + SPELL_SOUL_BARRAGE = 72305, + SPELL_SUMMON_TERENAS = 72420, + SPELL_MASS_RESURRECTION = 72429, + SPELL_MASS_RESURRECTION_REAL = 72423, + SPELL_PLAY_MOVIE = 73159, + + // Shambling Horror + SPELL_SHOCKWAVE = 72149, + SPELL_ENRAGE = 72143, + SPELL_FRENZY = 28747, +}; + +#define NECROTIC_PLAGUE_LK RAID_MODE<uint32>(70337, 73912, 73913, 73914) +#define NECROTIC_PLAGUE_PLR RAID_MODE<uint32>(70338, 73785, 73786, 73787) +#define REMORSELESS_WINTER_1 RAID_MODE<uint32>(68981, 74270, 74271, 74272) +#define REMORSELESS_WINTER_2 RAID_MODE<uint32>(72259, 74273, 74274, 74275) +#define SUMMON_VALKYR RAID_MODE<uint32>(69037, 74361, 69037, 74361) +#define HARVEST_SOUL RAID_MODE<uint32>(68980, 74325, 74296, 74297) + +enum Events +{ + // The Lich King + // intro events + EVENT_INTRO_MOVE_1 = 1, + EVENT_INTRO_MOVE_2 = 2, + EVENT_INTRO_MOVE_3 = 3, + EVENT_INTRO_TALK_1 = 4, + EVENT_EMOTE_CAST_SHOUT = 5, + EVENT_INTRO_EMOTE_1 = 6, + EVENT_INTRO_CHARGE = 7, + EVENT_INTRO_CAST_FREEZE = 8, + EVENT_FINISH_INTRO = 9, + + // combat events + EVENT_SUMMON_SHAMBLING_HORROR = 10, + EVENT_SUMMON_DRUDGE_GHOUL = 11, + EVENT_INFEST = 12, + EVENT_NECROTIC_PLAGUE = 13, + EVENT_SHADOW_TRAP = 14, // heroic only + EVENT_SOUL_REAPER = 15, + EVENT_DEFILE = 16, + EVENT_HARVEST_SOUL = 17, // normal mode only + EVENT_PAIN_AND_SUFFERING = 18, + EVENT_SUMMON_ICE_SPHERE = 19, + EVENT_SUMMON_RAGING_SPIRIT = 20, + EVENT_QUAKE = 21, + EVENT_SUMMON_VALKYR = 22, + EVENT_GRAB_PLAYER = 23, + EVENT_MOVE_TO_DROP_POS = 24, + EVENT_LIFE_SIPHON = 25, // heroic only + EVENT_START_ATTACK = 26, + EVENT_QUAKE_2 = 27, + EVENT_VILE_SPIRITS = 28, + EVENT_HARVEST_SOULS = 29, // heroic only + EVENT_WICKED_SPIRITS = 30, + EVENT_SOUL_RIP = 31, + EVENT_DESTROY_SOUL = 32, + EVENT_FROSTMOURNE_TALK_1 = 33, + EVENT_FROSTMOURNE_TALK_2 = 34, + EVENT_FROSTMOURNE_TALK_3 = 35, + EVENT_TELEPORT_BACK = 36, + EVENT_FROSTMOURNE_HEROIC = 37, + EVENT_OUTRO_TALK_1 = 38, + EVENT_OUTRO_TALK_2 = 39, + EVENT_OUTRO_EMOTE_TALK = 40, + EVENT_OUTRO_TALK_3 = 41, + EVENT_OUTRO_MOVE_CENTER = 42, + EVENT_OUTRO_TALK_4 = 43, + EVENT_OUTRO_RAISE_DEAD = 44, + EVENT_OUTRO_TALK_5 = 45, + EVENT_OUTRO_BLESS = 46, + EVENT_OUTRO_REMOVE_ICE = 47, + EVENT_OUTRO_MOVE_1 = 48, + EVENT_OUTRO_JUMP = 49, + EVENT_OUTRO_TALK_6 = 50, + EVENT_OUTRO_KNOCK_BACK = 51, + EVENT_OUTRO_SOUL_BARRAGE = 52, + EVENT_OUTRO_SUMMON_TERENAS = 53, + EVENT_OUTRO_TERENAS_TALK_1 = 54, + EVENT_OUTRO_TERENAS_TALK_2 = 55, + EVENT_OUTRO_TALK_7 = 56, + EVENT_OUTRO_TALK_8 = 57, + EVENT_BERSERK = 58, + + // Shambling Horror + EVENT_SHOCKWAVE = 59, + EVENT_ENRAGE = 60, + + // Raging Spirit + EVENT_SOUL_SHRIEK = 61, + + // Strangulate Vehicle (Harvest Soul) + EVENT_TELEPORT = 62, + EVENT_MOVE_TO_LICH_KING = 63, + EVENT_DESPAWN_SELF = 64, +}; + +enum EventGroups +{ + EVENT_GROUP_BERSERK = 1, + EVENT_GROUP_VILE_SPIRITS = 2, +}; + +enum Phases +{ + PHASE_INTRO = 1, + PHASE_ONE = 2, + PHASE_TWO = 3, + PHASE_THREE = 4, + PHASE_TRANSITION = 5, + PHASE_FROSTMOURNE = 6, // only set on heroic mode when all players are sent into frostmourne + PHASE_OUTRO = 7, + + PHASE_MASK_INTRO = 1 << PHASE_INTRO, + PHASE_MASK_ONE = 1 << PHASE_ONE, + PHASE_MASK_TWO = 1 << PHASE_TWO, + PHASE_MASK_THREE = 1 << PHASE_THREE, + PHASE_MASK_TRANSITION = 1 << PHASE_TRANSITION, + PHASE_MASK_NO_CAST_CHECK = (1 << PHASE_TRANSITION) | (1 << PHASE_FROSTMOURNE) | (1 << PHASE_OUTRO), + PHASE_MASK_FROSTMOURNE = 1 << PHASE_FROSTMOURNE, + PHASE_MASK_OUTRO = 1 << PHASE_OUTRO, + PHASE_MASK_NO_VICTIM = (1 << PHASE_INTRO) | (1 << PHASE_OUTRO) | (1 << PHASE_FROSTMOURNE), +}; + +#define PHASE_TWO_THREE (events.GetPhaseMask() & PHASE_MASK_TWO ? PHASE_TWO : PHASE_THREE) + +Position const CenterPosition = {503.6282f, -2124.655f, 840.8569f, 0.0f}; +Position const TirionIntro = {489.2970f, -2124.840f, 840.8569f, 0.0f}; +Position const TirionCharge = {482.9019f, -2124.479f, 840.8570f, 0.0f}; +Position const LichKingIntro[3] = +{ + {432.0851f, -2123.673f, 864.6582f, 0.0f}, + {457.8351f, -2123.423f, 841.1582f, 0.0f}, + {465.0730f, -2123.470f, 840.8569f, 0.0f}, +}; +Position const OutroPosition1 = {493.6286f, -2124.569f, 840.8569f, 0.0f}; +Position const OutroFlying = {508.9897f, -2124.561f, 845.3565f, 0.0f}; +Position const TerenasSpawn = {495.5542f, -2517.012f, 1050.000f, 4.6993f}; +Position const TerenasSpawnHeroic = {495.7080f, -2523.760f, 1050.000f, 0.0f}; +Position const SpiritWardenSpawn = {495.3406f, -2529.983f, 1050.000f, 1.5592f}; + +enum MovePoints +{ + POINT_CENTER_1 = 1, + POINT_CENTER_2 = 2, + POINT_TIRION_INTRO = 3, + POINT_LK_INTRO_1 = 4, + POINT_LK_INTRO_2 = 5, + POINT_LK_INTRO_3 = 6, + POINT_TIRION_CHARGE = 7, + POINT_DROP_PLAYER = 8, + POINT_LK_OUTRO_1 = 9, + POINT_TIRION_OUTRO_1 = 10, + POINT_OUTRO_JUMP = 11, + POINT_LK_OUTRO_2 = 12, + POINT_GROUND = 13, + POINT_CHARGE = 1003, // globally used number for charge spell effects +}; + +enum EncounterActions +{ + ACTION_START_ENCOUNTER = 0, + ACTION_CONTINUE_INTRO = 1, + ACTION_START_ATTACK = 2, + ACTION_OUTRO = 3, + ACTION_PLAY_MUSIC = 4, + ACTION_BREAK_FROSTMOURNE = 5, + ACTION_SUMMON_TERENAS = 6, + ACTION_FINISH_OUTRO = 7, + ACTION_TELEPORT_BACK = 8, +}; + +enum MiscData +{ + LIGHT_SNOWSTORM = 2490, + LIGHT_SOULSTORM = 2508, + + MUSIC_FROZEN_THRONE = 17457, + MUSIC_SPECIAL = 17458, // Summon Shambling Horror, Remorseless Winter, Quake, Summon Val'kyr Periodic, Harvest Soul, Vile Spirits + MUSIC_FURY_OF_FROSTMOURNE = 17459, + MUSIC_FINAL = 17460, // Raise Dead, Light's Blessing + + SOUND_PAIN = 17360, // separate sound, not attached to any text + + EQUIP_ASHBRINGER_GLOWING = 50442, + EQUIP_BROKEN_FROSTMOURNE = 50840, + + MOVIE_FALL_OF_THE_LICH_KING = 16, +}; + +#define DATA_PLAGUE_STACK 70337 +#define DATA_VILE 45814622 + +class NecroticPlagueTargetCheck : public std::unary_function<Unit*, bool> +{ + public: + NecroticPlagueTargetCheck(Unit const* obj, uint32 notAura1 = 0, uint32 notAura2 = 0) + : _sourceObj(obj), _notAura1(notAura1), _notAura2(notAura2) + { + } + + bool operator()(Unit* unit) const + { + if (!unit || unit == _sourceObj || !unit->isTargetableForAttack() || unit->isTotem() || unit->HasAura(SPELL_PLAGUE_AVOIDANCE)) + return false; + if ((_notAura1 && unit->HasAura(_notAura1)) || (_notAura2 && unit->HasAura(_notAura2))) + return false; + return true; + } + + private: + Unit const* _sourceObj; + uint32 _notAura1; + uint32 _notAura2; +}; + +class HeightDifferenceCheck +{ + public: + HeightDifferenceCheck(GameObject* go, float diff, bool reverse) + : _baseObject(go), _difference(diff), _reverse(reverse) + { + } + + bool operator()(Unit* unit) const + { + return (unit->GetPositionZ() - _baseObject->GetPositionZ() > _difference) != _reverse; + } + + private: + GameObject* _baseObject; + float _difference; + bool _reverse; +}; + +class FrozenThroneResetWorker +{ + public: + FrozenThroneResetWorker() { } + + bool operator()(GameObject* go) + { + switch (go->GetEntry()) + { + case GO_ARTHAS_PLATFORM: + go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING); + break; + case GO_DOODAD_ICECROWN_THRONEFROSTYWIND01: + go->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DOODAD_ICECROWN_THRONEFROSTYEDGE01: + go->SetGoState(GO_STATE_READY); + break; + case GO_DOODAD_ICESHARD_STANDING02: + case GO_DOODAD_ICESHARD_STANDING01: + case GO_DOODAD_ICESHARD_STANDING03: + case GO_DOODAD_ICESHARD_STANDING04: + go->ResetDoorOrButton(); + break; + default: + break; + } + + return false; + } +}; + +class StartMovementEvent : public BasicEvent +{ + public: + StartMovementEvent(Creature* summoner, Creature* owner) + : _summoner(summoner), _owner(owner) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) + { + _owner->SetReactState(REACT_AGGRESSIVE); + if (Unit* target = _summoner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(_summoner))) + _owner->AI()->AttackStart(target); + return true; + } + + private: + Creature* _summoner; + Creature* _owner; +}; + +class VileSpiritActivateEvent : public BasicEvent +{ + public: + explicit VileSpiritActivateEvent(Creature* owner) + : _owner(owner) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) + { + _owner->SetReactState(REACT_AGGRESSIVE); + _owner->CastSpell(_owner, SPELL_VILE_SPIRIT_MOVE_SEARCH, true); + _owner->CastSpell((Unit*)NULL, SPELL_VILE_SPIRIT_DAMAGE_SEARCH, true); + return true; + } + + private: + Creature* _owner; +}; + +class boss_the_lich_king : public CreatureScript +{ + public: + boss_the_lich_king() : CreatureScript("boss_the_lich_king") { } + + struct boss_the_lich_kingAI : public BossAI + { + boss_the_lich_kingAI(Creature* creature) : BossAI(creature, DATA_THE_LICH_KING) + { + } + + void Reset() + { + _Reset(); + me->SetReactState(REACT_PASSIVE); + events.SetPhase(PHASE_INTRO); + _necroticPlagueStack = 0; + _vileSpiritExplosions = 0; + SetEquipmentSlots(true); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); + DoCastAOE(SPELL_PLAY_MOVIE, false); + } + + void EnterCombat(Unit* target) + { + //if (!instance->CheckRequiredBosses(DATA_THE_LICH_KING, target->ToPlayer())) + //{ + // EnterEvadeMode(); + // instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); + // return; + //} + + me->setActive(true); + DoZoneInCombat(); + + events.SetPhase(PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 20000, 0, PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 10000, 0, PHASE_ONE); + events.ScheduleEvent(EVENT_INFEST, 5000, 0, PHASE_ONE); + events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, urand(30000, 33000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_BERSERK, 900000, EVENT_GROUP_BERSERK); + if (IsHeroic()) + events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500, 0, PHASE_ONE); + } + + void JustReachedHome() + { + _JustReachedHome(); + instance->SetBossState(DATA_THE_LICH_KING, NOT_STARTED); + + // Reset The Frozen Throne gameobjects + FrozenThroneResetWorker reset; + Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); + me->VisitNearbyGridObject(333.0f, worker); + + // Reset any light override + SendLightOverride(0, 5000); + } + + bool CanAIAttack(Unit const* target) const + { + // The Lich King must not select targets in frostmourne room if he killed everyone outside + return !target->HasAura(SPELL_IN_FROSTMOURNE_ROOM); + } + + void EnterEvadeMode() + { + instance->SetBossState(DATA_THE_LICH_KING, FAIL); + BossAI::EnterEvadeMode(); + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->AI()->EnterEvadeMode(); + DoCastAOE(SPELL_KILL_FROSTMOURNE_PLAYERS); + summons.DoAction(NPC_STRANGULATE_VEHICLE, ACTION_TELEPORT_BACK); + } + + void KilledUnit(Unit* victim) + { + if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !(events.GetPhaseMask() & PHASE_MASK_OUTRO)) + Talk(SAY_LK_KILL); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_START_ENCOUNTER: + instance->SetBossState(DATA_THE_LICH_KING, IN_PROGRESS); + Talk(SAY_LK_INTRO_1); + SendMusicToPlayers(MUSIC_FROZEN_THRONE); + // schedule talks + me->SetStandState(UNIT_STAND_STATE_STAND); + events.ScheduleEvent(EVENT_INTRO_MOVE_1, 4000); + break; + case ACTION_START_ATTACK: + events.ScheduleEvent(EVENT_START_ATTACK, 5000); + break; + case ACTION_PLAY_MUSIC: + SendMusicToPlayers(MUSIC_FINAL); + break; + case ACTION_RESTORE_LIGHT: + SendLightOverride(0, 5000); + break; + case ACTION_BREAK_FROSTMOURNE: + DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE); + DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_2); + SetEquipmentSlots(false, EQUIP_BROKEN_FROSTMOURNE); + events.ScheduleEvent(EVENT_OUTRO_TALK_6, 2500, 0, PHASE_OUTRO); + break; + case ACTION_FINISH_OUTRO: + events.ScheduleEvent(EVENT_OUTRO_TALK_7, 7000, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_TALK_8, 17000, 0, PHASE_OUTRO); + break; + case ACTION_TELEPORT_BACK: + summons.DoAction(NPC_STRANGULATE_VEHICLE, ACTION_TELEPORT_BACK); + if (!IsHeroic()) + Talk(SAY_LK_FROSTMOURNE_ESCAPE); + else + DoCastAOE(SPELL_TRIGGER_VILE_SPIRIT_HEROIC); + break; + default: + break; + } + } + + uint32 GetData(uint32 type) + { + switch (type) + { + case DATA_PLAGUE_STACK: + return _necroticPlagueStack; + case DATA_VILE: + return _vileSpiritExplosions; + default: + break; + } + + return 0; + } + + void SetData(uint32 type, uint32 value) + { + switch (type) + { + case DATA_PLAGUE_STACK: + _necroticPlagueStack = std::max(value, _necroticPlagueStack); + break; + case DATA_VILE: + _vileSpiritExplosions += value; + break; + default: + break; + } + } + + void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) + { + //if (events.GetPhaseMask() & PHASE_MASK_ONE && !HealthAbovePct(70)) + //{ + // events.SetPhase(PHASE_TRANSITION); + // me->GetMotionMaster()->MovePoint(POINT_CENTER_1, CenterPosition); + // return; + //} + + if (events.GetPhaseMask() & (PHASE_MASK_ONE | PHASE_MASK_TWO) && !HealthAbovePct(40)) + { + events.SetPhase(PHASE_TRANSITION); + me->GetMotionMaster()->MovePoint(POINT_CENTER_2, CenterPosition); + return; + } + + if (events.GetPhaseMask() & PHASE_MASK_THREE && !HealthAbovePct(10)) + { + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + events.Reset(); + events.SetPhase(PHASE_OUTRO); + summons.DespawnAll(); + SendMusicToPlayers(MUSIC_FURY_OF_FROSTMOURNE); + DoCastAOE(SPELL_FURY_OF_FROSTMOURNE); + me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + events.ScheduleEvent(EVENT_OUTRO_TALK_1, 2600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 6600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 17600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 27600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_TALK_2, 34600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_TALK_3, 43600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 54600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_EMOTE_TALK, 58600, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_MOVE_CENTER, 69600, 0, PHASE_OUTRO); + // stop here. rest will get scheduled from MovementInform + return; + } + } + + void JustSummoned(Creature* summon) + { + switch (summon->GetEntry()) + { + case NPC_SHAMBLING_HORROR: + case NPC_DRUDGE_GHOUL: + summon->CastSpell(summon, SPELL_RISEN_WITCH_DOCTOR_SPAWN, true); + summon->SetReactState(REACT_PASSIVE); + summon->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + summon->m_Events.AddEvent(new StartMovementEvent(me, summon), summon->m_Events.CalculateTime(5000)); + break; + case NPC_ICE_SPHERE: + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + { + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_ICE_SPHERE, false); + summon->CastSpell(summon, SPELL_ICE_BURST_TARGET_SEARCH, false); + summon->CastSpell(target, SPELL_ICE_PULSE, false); + summon->ClearUnitState(UNIT_STAT_CASTING); + summon->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); + } + else + summon->DespawnOrUnsummon(); + break; + } + case NPC_DEFILE: + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_DEFILE_AURA, false); + break; + case NPC_VALKYR_SHADOWGUARD: + summon->CastSpell(summon, SPELL_WINGS_OF_THE_DAMNED, true); + summon->CastSpell(summon, SPELL_VALKYR_TARGET_SEARCH, true); + break; + case NPC_FROSTMOURNE_TRIGGER: + { + summons.Summon(summon); + summon->CastSpell((Unit*)NULL, SPELL_BROKEN_FROSTMOURNE, true); + + SendLightOverride(LIGHT_SOULSTORM, 10000); + SendWeather(WEATHER_STATE_BLACKSNOW); + + events.ScheduleEvent(EVENT_OUTRO_SOUL_BARRAGE, 5000, 0, PHASE_OUTRO); + return; + } + case NPC_VILE_SPIRIT: + { + summons.Summon(summon); + if (events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE) + { + Position offset; + me->GetPositionOffsetTo(*summon, offset); + offset.m_positionZ += 5.0f; + Position dest = TerenasSpawnHeroic; + dest.RelocateOffset(offset); + summon->NearTeleportTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.GetOrientation()); + summon->UpdateEntry(NPC_WICKED_SPIRIT); + summon->SetSpeed(MOVE_FLIGHT, 0.5f); + summon->CastSpell(summon, SPELL_VILE_SPIRIT_MOVE_SEARCH, true); + summon->CastSpell((Unit*)NULL, SPELL_VILE_SPIRIT_DAMAGE_SEARCH, true); + return; + } + + summon->SetReactState(REACT_PASSIVE); + summon->SetSpeed(MOVE_FLIGHT, 0.5f); + summon->GetMotionMaster()->MoveRandom(10.0f); + summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15000)); + return; + } + case NPC_STRANGULATE_VEHICLE: + summons.Summon(summon); + return; + default: + break; + } + + BossAI::JustSummoned(summon); + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) + { + switch (summon->GetEntry()) + { + case NPC_SHAMBLING_HORROR: + case NPC_DRUDGE_GHOUL: + case NPC_ICE_SPHERE: + case NPC_VALKYR_SHADOWGUARD: + case NPC_RAGING_SPIRIT: + case NPC_VILE_SPIRIT: + case NPC_WICKED_SPIRIT: + summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); + break; + default: + break; + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_HARVESTED_SOUL && me->isInCombat() && !IsHeroic()) + Talk(SAY_LK_FROSTMOURNE_KILL); + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) + { + if (spell->Id == REMORSELESS_WINTER_1 || spell->Id == REMORSELESS_WINTER_2) + { + SendLightOverride(LIGHT_SNOWSTORM, 5000); + SendWeather(WEATHER_STATE_LIGHT_SNOW); + } + } + + void MovementInform(uint32 type, uint32 pointId) + { + if (type != POINT_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_LK_INTRO_1: + // schedule for next update cycle, current update must finalize movement + events.ScheduleEvent(EVENT_INTRO_MOVE_2, 1, 0, PHASE_INTRO); + break; + case POINT_LK_INTRO_2: + events.ScheduleEvent(EVENT_INTRO_MOVE_3, 1, 0, PHASE_INTRO); + break; + case POINT_LK_INTRO_3: + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->AI()->DoAction(ACTION_CONTINUE_INTRO); + events.ScheduleEvent(EVENT_INTRO_TALK_1, 9000, 0, PHASE_INTRO); + break; + case POINT_CENTER_1: + me->SetFacing(0.0f); + Talk(SAY_LK_REMORSELESS_WINTER); + SendMusicToPlayers(MUSIC_SPECIAL); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + DoCast(me, SPELL_REMORSELESS_WINTER_1); + events.DelayEvents(62500, EVENT_GROUP_BERSERK); // delay berserk timer, its not ticking during phase transitions + events.ScheduleEvent(EVENT_QUAKE, 62500, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 4000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 3000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_VALKYR, 78000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_INFEST, 70000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_DEFILE, 97000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_SOUL_REAPER, 94000, 0, PHASE_TWO); + break; + case POINT_CENTER_2: + me->SetFacing(0.0f); + Talk(SAY_LK_REMORSELESS_WINTER); + SendMusicToPlayers(MUSIC_SPECIAL); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + DoCast(me, SPELL_REMORSELESS_WINTER_2); + summons.DespawnEntry(NPC_VALKYR_SHADOWGUARD); + events.DelayEvents(62500, EVENT_GROUP_BERSERK); // delay berserk timer, its not ticking during phase transitions + events.ScheduleEvent(EVENT_QUAKE_2, 62500, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 6000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, 8000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, 5000, 0, PHASE_TRANSITION); + events.ScheduleEvent(EVENT_DEFILE, 95500, 0, PHASE_THREE); + events.ScheduleEvent(EVENT_SOUL_REAPER, 99500, 0, PHASE_THREE); + events.ScheduleEvent(EVENT_VILE_SPIRITS, 79500, EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); + events.ScheduleEvent(IsHeroic() ? EVENT_HARVEST_SOULS : EVENT_HARVEST_SOUL, 73500, 0, PHASE_THREE); + break; + case POINT_LK_OUTRO_1: + events.ScheduleEvent(EVENT_OUTRO_TALK_4, 1, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_RAISE_DEAD, 1000, 0, PHASE_OUTRO); + events.ScheduleEvent(EVENT_OUTRO_TALK_5, 29000, 0, PHASE_OUTRO); + break; + case POINT_LK_OUTRO_2: + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->AI()->Talk(SAY_TIRION_OUTRO_2); + if (Creature* frostmourne = me->FindNearestCreature(NPC_FROSTMOURNE_TRIGGER, 50.0f)) + frostmourne->AI()->DoAction(ACTION_SUMMON_TERENAS); + break; + default: + break; + } + } + + void UpdateAI(uint32 const diff) + { + // check phase first to prevent updating victim and entering evade mode when not wanted + if (!(events.GetPhaseMask() & PHASE_MASK_NO_VICTIM)) + if (!UpdateVictim()) + return; + + events.Update(diff); + + // during Remorseless Winter phases The Lich King is channeling a spell, but we must continue casting other spells + if (me->HasUnitState(UNIT_STAT_CASTING) && !(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_MOVE_1: + me->SetSheath(SHEATH_STATE_MELEE); + me->RemoveAurasDueToSpell(SPELL_EMOTE_SIT_NO_SHEATH); + me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_1, LichKingIntro[0]); + break; + case EVENT_INTRO_MOVE_2: + me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_2, LichKingIntro[1]); + break; + case EVENT_INTRO_MOVE_3: + me->GetMotionMaster()->MovePoint(POINT_LK_INTRO_3, LichKingIntro[2]); + break; + case EVENT_INTRO_TALK_1: + Talk(SAY_LK_INTRO_2); + // for some reason blizz sends 2 emotes in row here so (we handle one in Talk) + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NOSHEATHE); + events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 7000, 0, PHASE_INTRO); + events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 13000, 0, PHASE_INTRO); + events.ScheduleEvent(EVENT_EMOTE_CAST_SHOUT, 18000, 0, PHASE_INTRO); + events.ScheduleEvent(EVENT_INTRO_CAST_FREEZE, 31000, 0, PHASE_INTRO); + break; + case EVENT_EMOTE_CAST_SHOUT: + DoCast(me, SPELL_EMOTE_SHOUT_NO_SHEATH, false); + break; + case EVENT_INTRO_EMOTE_1: + me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NOSHEATHE); + break; + case EVENT_INTRO_CAST_FREEZE: + Talk(SAY_LK_INTRO_3); + DoCastAOE(SPELL_ICE_LOCK, false); + events.ScheduleEvent(EVENT_FINISH_INTRO, 1000, 0, PHASE_INTRO); + break; + case EVENT_FINISH_INTRO: + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + events.SetPhase(PHASE_ONE); + break; + case EVENT_SUMMON_SHAMBLING_HORROR: + DoCast(me, SPELL_SUMMON_SHAMBLING_HORROR); + SendMusicToPlayers(MUSIC_SPECIAL); + events.ScheduleEvent(EVENT_SUMMON_SHAMBLING_HORROR, 60000, 0, PHASE_ONE); + break; + case EVENT_SUMMON_DRUDGE_GHOUL: + DoCast(me, SPELL_SUMMON_DRUDGE_GHOULS); + events.ScheduleEvent(EVENT_SUMMON_DRUDGE_GHOUL, 30000, 0, PHASE_ONE); + break; + case EVENT_INFEST: + DoCast(me, SPELL_INFEST); + events.ScheduleEvent(EVENT_INFEST, urand(21000, 24000), 0, (events.GetPhaseMask() & PHASE_MASK_ONE) ? PHASE_ONE : PHASE_TWO); + break; + case EVENT_NECROTIC_PLAGUE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR))) + { + Talk(EMOTE_NECROTIC_PLAGUE_WARNING, target->GetGUID()); + DoCast(target, SPELL_NECROTIC_PLAGUE); + } + events.ScheduleEvent(EVENT_NECROTIC_PLAGUE, urand(30000, 33000), 0, PHASE_ONE); + break; + case EVENT_SHADOW_TRAP: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, NonTankTargetSelector(me))) + DoCast(target, SPELL_SHADOW_TRAP); + events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500, 0, PHASE_ONE); + break; + case EVENT_SOUL_REAPER: + DoCastVictim(SPELL_SOUL_REAPER); + events.ScheduleEvent(EVENT_SOUL_REAPER, urand(33000, 35000), 0, PHASE_TWO_THREE); + break; + case EVENT_DEFILE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_HARVEST_SOUL_VALKYR)) + { + Talk(EMOTE_DEFILE_WARNING); + DoCast(target, SPELL_DEFILE); + } + events.ScheduleEvent(EVENT_DEFILE, urand(32000, 35000), 0, PHASE_TWO_THREE); + break; + case EVENT_HARVEST_SOUL: + Talk(SAY_LK_HARVEST_SOUL); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, SpellTargetSelector(me, SPELL_HARVEST_SOUL))) + DoCast(target, SPELL_HARVEST_SOUL); + events.ScheduleEvent(EVENT_HARVEST_SOUL, 75000, 0, PHASE_THREE); + break; + case EVENT_PAIN_AND_SUFFERING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + me->CastSpell(target, SPELL_PAIN_AND_SUFFERING, TRIGGERED_NONE); + events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, urand(1500, 4000), 0, PHASE_TRANSITION); + break; + case EVENT_SUMMON_ICE_SPHERE: + DoCastAOE(SPELL_SUMMON_ICE_SPHERE); + events.ScheduleEvent(EVENT_SUMMON_ICE_SPHERE, urand(7500, 8500), 0, PHASE_TRANSITION); + break; + case EVENT_SUMMON_RAGING_SPIRIT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + me->CastSpell(target, SPELL_RAGING_SPIRIT, TRIGGERED_NONE); + events.ScheduleEvent(EVENT_SUMMON_RAGING_SPIRIT, urand(22000, 23000), 0, PHASE_TRANSITION); + break; + case EVENT_QUAKE: + events.SetPhase(PHASE_TWO); + me->ClearUnitState(UNIT_STAT_CASTING); // clear state to ensure check in DoCastAOE passes + DoCastAOE(SPELL_QUAKE); + SendMusicToPlayers(MUSIC_SPECIAL); + Talk(SAY_LK_QUAKE); + break; + case EVENT_QUAKE_2: + events.SetPhase(PHASE_THREE); + me->ClearUnitState(UNIT_STAT_CASTING); // clear state to ensure check in DoCastAOE passes + DoCastAOE(SPELL_QUAKE); + SendMusicToPlayers(MUSIC_SPECIAL); + Talk(SAY_LK_QUAKE); + break; + case EVENT_SUMMON_VALKYR: + SendMusicToPlayers(MUSIC_SPECIAL); + Talk(SAY_LK_SUMMON_VALKYR); + DoCastAOE(SUMMON_VALKYR); + events.ScheduleEvent(EVENT_SUMMON_VALKYR, urand(45000, 50000), 0, PHASE_TWO); + break; + case EVENT_START_ATTACK: + me->SetReactState(REACT_AGGRESSIVE); + if (events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE) + events.SetPhase(PHASE_THREE); + break; + case EVENT_VILE_SPIRITS: + SendMusicToPlayers(MUSIC_SPECIAL); + DoCastAOE(SPELL_VILE_SPIRITS); + events.ScheduleEvent(EVENT_VILE_SPIRITS, urand(35000, 40000), EVENT_GROUP_VILE_SPIRITS, PHASE_THREE); + break; + case EVENT_WICKED_SPIRITS: + DoCastAOE(SPELL_VILE_SPIRITS); + events.ScheduleEvent(EVENT_WICKED_SPIRITS, urand(35000, 40000), 0, PHASE_FROSTMOURNE); + break; + case EVENT_HARVEST_SOULS: + Talk(SAY_LK_HARVEST_SOUL); + DoCastAOE(SPELL_HARVEST_SOULS); + events.ScheduleEvent(EVENT_HARVEST_SOULS, urand(100000, 110000), 0, PHASE_THREE); + events.SetPhase(PHASE_FROSTMOURNE); // will stop running UpdateVictim (no evading) + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + events.ScheduleEvent(EVENT_WICKED_SPIRITS, events.GetNextEventTime(EVENT_VILE_SPIRITS) - events.GetTimer(), 0, PHASE_FROSTMOURNE); + events.DelayEvents(50000, EVENT_GROUP_VILE_SPIRITS); + events.RescheduleEvent(EVENT_DEFILE, 50000, 0, PHASE_THREE); + events.RescheduleEvent(EVENT_SOUL_REAPER, urand(57000, 62000), 0, PHASE_THREE); + events.ScheduleEvent(EVENT_START_ATTACK, 49000); + events.ScheduleEvent(EVENT_FROSTMOURNE_HEROIC, 6500); + break; + case EVENT_FROSTMOURNE_HEROIC: + if (TempSummon* terenas = me->GetMap()->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE_H, TerenasSpawnHeroic, NULL, 50000)) + { + terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO); + std::list<Creature*> triggers; + GetCreatureListWithEntryInGrid(triggers, terenas, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f); + if (!triggers.empty()) + { + triggers.sort(Trinity::ObjectDistanceOrderPred(terenas, true)); + Unit* spawner = triggers.front(); + spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_1, true); // summons bombs randomly + spawner->CastSpell(spawner, SPELL_SUMMON_SPIRIT_BOMB_2, true); // summons bombs on players + } + } + break; + case EVENT_OUTRO_TALK_1: + Talk(SAY_LK_OUTRO_1); + DoCastAOE(SPELL_FURY_OF_FROSTMOURNE_NO_REZ, true); + break; + case EVENT_OUTRO_TALK_2: + Talk(SAY_LK_OUTRO_2); + DoCastAOE(SPELL_EMOTE_QUESTION_NO_SHEATH); + break; + case EVENT_OUTRO_EMOTE_TALK: + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK_NOSHEATHE); + break; + case EVENT_OUTRO_TALK_3: + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + me->SetFacing(0.0f, tirion); + Talk(SAY_LK_OUTRO_3); + break; + case EVENT_OUTRO_MOVE_CENTER: + me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition); + break; + case EVENT_OUTRO_TALK_4: + me->SetFacing(0.01745329f); + Talk(SAY_LK_OUTRO_4); + break; + case EVENT_OUTRO_RAISE_DEAD: + DoCastAOE(SPELL_RAISE_DEAD); + me->ClearUnitState(UNIT_STAT_CASTING); + SendMusicToPlayers(MUSIC_FINAL); + break; + case EVENT_OUTRO_TALK_5: + Talk(SAY_LK_OUTRO_5); + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->AI()->DoAction(ACTION_OUTRO); + break; + case EVENT_OUTRO_TALK_6: + Talk(SAY_LK_OUTRO_6); + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->SetFacing(0.0f, me); + me->ClearUnitState(UNIT_STAT_CASTING); + DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_3); + SetEquipmentSlots(false, EQUIP_UNEQUIP); + break; + case EVENT_OUTRO_SOUL_BARRAGE: + DoCastAOE(SPELL_SOUL_BARRAGE); + sCreatureTextMgr->SendSound(me, SOUND_PAIN, CHAT_MSG_MONSTER_YELL, 0, TEXT_RANGE_NORMAL, TEAM_OTHER, false); + // set flight + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x03); + me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_2, OutroFlying); + break; + case EVENT_OUTRO_TALK_7: + Talk(SAY_LK_OUTRO_7); + break; + case EVENT_OUTRO_TALK_8: + Talk(SAY_LK_OUTRO_8); + break; + case EVENT_BERSERK: + Talk(SAY_LK_BERSERK); + DoCast(me, SPELL_BERSERK2); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + + void SendMusicToPlayers(uint32 musicId) const + { + WorldPacket data(SMSG_PLAY_MUSIC, 4); + data << uint32(musicId); + SendPacketToPlayers(&data); + } + + void SendLightOverride(uint32 overrideId, uint32 fadeInTime) const + { + WorldPacket data(SMSG_OVERRIDE_LIGHT, 12); + data << uint32(2488); // Light.dbc entry (map default) + data << uint32(overrideId); // Light.dbc entry (override) + data << uint32(fadeInTime); + SendPacketToPlayers(&data); + } + + void SendWeather(WeatherState weather) const + { + WorldPacket data(SMSG_WEATHER, 9); + data << uint32(weather); + data << float(0.5f); + data << uint8(0); + SendPacketToPlayers(&data); + } + + // Send packet to all players in The Frozen Throne + void SendPacketToPlayers(WorldPacket const* data) const + { + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + if (!players.isEmpty()) + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + if (player->GetAreaId() == AREA_THE_FROZEN_THRONE) + player->GetSession()->SendPacket(data); + } + + uint32 _necroticPlagueStack; + uint32 _vileSpiritExplosions; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<boss_the_lich_kingAI>(creature); + } +}; + +class npc_tirion_fordring_tft : public CreatureScript +{ + public: + npc_tirion_fordring_tft() : CreatureScript("npc_tirion_fordring_tft") { } + + struct npc_tirion_fordringAI : public ScriptedAI + { + npc_tirion_fordringAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_TIRION_INTRO: + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); + if (Creature* theLichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + theLichKing->AI()->DoAction(ACTION_START_ENCOUNTER); + break; + case POINT_TIRION_OUTRO_1: + _events.ScheduleEvent(EVENT_OUTRO_JUMP, 1, 0, PHASE_OUTRO); + break; + } + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_CONTINUE_INTRO: + Talk(SAY_TIRION_INTRO_1); + _events.ScheduleEvent(EVENT_INTRO_TALK_1, 34000, 0, PHASE_INTRO); + break; + case ACTION_OUTRO: + _events.SetPhase(PHASE_OUTRO); + _events.ScheduleEvent(EVENT_OUTRO_TALK_1, 7000, 0, PHASE_OUTRO); + _events.ScheduleEvent(EVENT_OUTRO_BLESS, 18000, 0, PHASE_OUTRO); + _events.ScheduleEvent(EVENT_OUTRO_REMOVE_ICE, 23000, 0, PHASE_OUTRO); + _events.ScheduleEvent(EVENT_OUTRO_MOVE_1, 25000, 0, PHASE_OUTRO); + break; + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_ICE_LOCK) + me->SetFacing(3.085098f); + else if (spell->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK) + SetEquipmentSlots(true); // remove glow on ashbringer + } + + void sGossipSelect(Player* player, uint32 sender, uint32 action) + { + if (me->GetCreatureInfo()->GossipMenuId == sender && !action) + { + _events.SetPhase(PHASE_INTRO); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(POINT_TIRION_INTRO, TirionIntro); + } + } + + void JustReachedHome() + { + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() && !(_events.GetPhaseMask() & (PHASE_MASK_INTRO | PHASE_MASK_OUTRO))) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_TALK_1: + Talk(SAY_TIRION_INTRO_2); + _events.ScheduleEvent(EVENT_INTRO_EMOTE_1, 2000, 0, PHASE_INTRO); + _events.ScheduleEvent(EVENT_INTRO_CHARGE, 5000, 0, PHASE_INTRO); + break; + case EVENT_INTRO_EMOTE_1: + me->HandleEmoteCommand(EMOTE_ONESHOT_POINT_NOSHEATHE); + break; + case EVENT_INTRO_CHARGE: + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(POINT_TIRION_CHARGE, TirionCharge); + break; + case EVENT_OUTRO_TALK_1: + Talk(SAY_TIRION_OUTRO_1); + break; + case EVENT_OUTRO_BLESS: + DoCast(me, SPELL_LIGHTS_BLESSING); + break; + case EVENT_OUTRO_REMOVE_ICE: + me->RemoveAurasDueToSpell(SPELL_ICE_LOCK); + SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING); + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + { + me->SetFacing(0.0f, lichKing); + lichKing->AI()->DoAction(ACTION_PLAY_MUSIC); + } + break; + case EVENT_OUTRO_MOVE_1: + me->GetMotionMaster()->MovePoint(POINT_TIRION_OUTRO_1, OutroPosition1); + break; + case EVENT_OUTRO_JUMP: + DoCastAOE(SPELL_JUMP); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_tirion_fordringAI>(creature); + } +}; + +class npc_shambling_horror_icc : public CreatureScript +{ + public: + npc_shambling_horror_icc() : CreatureScript("npc_shambling_horror_icc") { } + + struct npc_shambling_horror_iccAI : public ScriptedAI + { + npc_shambling_horror_iccAI(Creature* creature) : ScriptedAI(creature) + { + _frenzied = false; + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_SHOCKWAVE, urand(20000, 25000)); + _events.ScheduleEvent(EVENT_ENRAGE, urand(11000, 14000)); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (IsHeroic() && me->HealthBelowPctDamaged(20, damage)) + { + _frenzied = true; + DoCast(me, SPELL_FRENZY, true); + } + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHOCKWAVE: + DoCast(me, SPELL_SHOCKWAVE); + _events.ScheduleEvent(EVENT_SHOCKWAVE, urand(20000, 25000)); + break; + case EVENT_ENRAGE: + DoCast(me, SPELL_ENRAGE); + _events.ScheduleEvent(EVENT_ENRAGE, urand(20000, 25000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + bool _frenzied; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_shambling_horror_iccAI>(creature); + } +}; + +class npc_raging_spirit : public CreatureScript +{ + public: + npc_raging_spirit() : CreatureScript("npc_raging_spirit") { } + + struct npc_raging_spiritAI : public ScriptedAI + { + npc_raging_spiritAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); + DoCast(me, SPELL_PLAGUE_AVOIDANCE, true); + DoCast(me, SPELL_RAGING_SPIRIT_VISUAL, true); + if (TempSummon* summon = me->ToTempSummon()) + if (Unit* summoner = summon->GetSummoner()) + summoner->CastSpell(me, SPELL_RAGING_SPIRIT_VISUAL_CLONE, true); + DoCast(me, SPELL_BOSS_HITTIN_YA, true); + } + + void IsSummonedBy(Unit* summoner) + { + // player is the spellcaster so register summon manually + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->JustSummoned(me); + } + + void JustDied(Unit* killer) + { + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->SummonedCreatureDespawn(me); + if (TempSummon* summon = me->ToTempSummon()) + summon->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SOUL_SHRIEK: + DoCastAOE(SPELL_SOUL_SHRIEK); + _events.ScheduleEvent(EVENT_SOUL_SHRIEK, urand(12000, 15000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_raging_spiritAI>(creature); + } +}; + +class npc_valkyr_shadowguard : public CreatureScript +{ + public: + npc_valkyr_shadowguard() : CreatureScript("npc_valkyr_shadowguard") { } + + struct npc_valkyr_shadowguardAI : public ScriptedAI + { + npc_valkyr_shadowguardAI(Creature* creature) : ScriptedAI(creature), + _grabbedPlayer(0), _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + me->SetReactState(REACT_PASSIVE); + me->SetSpeed(MOVE_FLIGHT, 0.642857f, true); + } + + void IsSummonedBy(Unit* /*summoner*/) + { + _events.Reset(); + _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2500); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (!IsHeroic()) + return; + + if (!me->HasAuraType(SPELL_AURA_CONTROL_VEHICLE)) + return; + + if (me->HealthBelowPctDamaged(50, damage)) + { + _events.Reset(); + DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); + me->GetMotionMaster()->MoveTargetedHome(); + me->ClearUnitState(UNIT_STAT_EVADE); + } + } + + void JustReachedHome() + { + // schedule siphon life event (heroic only) + DoZoneInCombat(); + _events.Reset(); + _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2000); + } + + void AttackStart(Unit* /*target*/) + { + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_DROP_PLAYER: + DoCastAOE(SPELL_EJECT_ALL_PASSENGERS); + me->DespawnOrUnsummon(1000); + break; + case POINT_CHARGE: + if (Player* target = ObjectAccessor::GetPlayer(*me, _grabbedPlayer)) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if (GameObject* platform = ObjectAccessor::GetGameObject(*me, _instance->GetData64(DATA_ARTHAS_PLATFORM))) + { + std::list<Creature*> triggers; + GetCreatureListWithEntryInGrid(triggers, me, NPC_WORLD_TRIGGER, 150.0f); + triggers.remove_if(HeightDifferenceCheck(platform, 5.0f, true)); + if (triggers.empty()) + return; + + triggers.sort(Trinity::ObjectDistanceOrderPred(me)); + DoCast(target, SPELL_VALKYR_CARRY); + _dropPoint.Relocate(triggers.front()); + _events.ScheduleEvent(EVENT_MOVE_TO_DROP_POS, 1500); + + } + } + else + me->DespawnOrUnsummon(); + break; + default: + break; + } + } + + void SetGUID(uint64 guid, int32 /* = 0*/) + { + _grabbedPlayer = guid; + _events.Reset(); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_GRAB_PLAYER: + DoCastAOE(SPELL_VALKYR_TARGET_SEARCH); + _events.ScheduleEvent(EVENT_GRAB_PLAYER, 2000); + break; + case EVENT_MOVE_TO_DROP_POS: + me->GetMotionMaster()->MovePoint(POINT_DROP_PLAYER, _dropPoint); + break; + case EVENT_LIFE_SIPHON: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) + DoCast(target, SPELL_LIFE_SIPHON); + _events.ScheduleEvent(EVENT_LIFE_SIPHON, 2500); + break; + default: + break; + } + } + + // no melee attacks + } + + private: + EventMap _events; + Position _dropPoint; + uint64 _grabbedPlayer; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_valkyr_shadowguardAI>(creature); + } +}; + +class npc_strangulate_vehicle : public CreatureScript +{ + public: + npc_strangulate_vehicle() : CreatureScript("npc_strangulate_vehicle") { } + + struct npc_strangulate_vehicleAI : public ScriptedAI + { + npc_strangulate_vehicleAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void IsSummonedBy(Unit* summoner) + { + me->SetFacing(0.0f, summoner); + DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE); + _events.Reset(); + _events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2000); + _events.ScheduleEvent(EVENT_TELEPORT, 6000); + + // this will let us easily access all creatures of this entry on heroic mode when its time to teleport back + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->JustSummoned(me); + } + + void DoAction(int32 const action) + { + if (action != ACTION_TELEPORT_BACK) + return; + + if (TempSummon* summ = me->ToTempSummon()) + if (Unit* summoner = summ->GetSummoner()) + DoCast(summoner, SPELL_HARVEST_SOUL_TELEPORT_BACK); + + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->SummonedCreatureDespawn(me); + } + + void UpdateAI(uint32 const diff) + { + UpdateVictim(); + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TELEPORT: + me->GetMotionMaster()->MoveIdle(MOTION_SLOT_ACTIVE); + if (TempSummon* summ = me->ToTempSummon()) + { + if (Unit* summoner = summ->GetSummoner()) + { + summoner->CastSpell((Unit*)NULL, SPELL_HARVEST_SOUL_VISUAL, true); + summoner->ExitVehicle(summoner); + if (!IsHeroic()) + summoner->CastSpell(summoner, SPELL_HARVEST_SOUL_TELEPORT, true); + else + { + summoner->CastSpell(summoner, SPELL_HARVEST_SOULS_TELEPORT, true); + summoner->RemoveAurasDueToSpell(HARVEST_SOUL, 0, 0, AURA_REMOVE_BY_EXPIRE); + } + } + } + + _events.ScheduleEvent(EVENT_DESPAWN_SELF, 65000); + break; + case EVENT_MOVE_TO_LICH_KING: + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + { + if (me->GetExactDist(lichKing) > 10.0f) + { + Position pos; + lichKing->GetNearPosition(pos, float(rand_norm()) * 5.0f + 7.5f, lichKing->GetAngle(me)); + me->GetMotionMaster()->MovePoint(0, pos); + } + } + break; + case EVENT_DESPAWN_SELF: + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->SummonedCreatureDespawn(me); + me->DespawnOrUnsummon(1); + break; + default: + break; + } + } + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_strangulate_vehicleAI>(creature); + } +}; + +class npc_terenas_menethil : public CreatureScript +{ + public: + npc_terenas_menethil() : CreatureScript("npc_terenas_menethil") { } + + struct npc_terenas_menethilAI : public ScriptedAI + { + npc_terenas_menethilAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + bool CanAIAttack(Unit const* target) const + { + return target->GetEntry() != NPC_THE_LICH_KING; + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_FROSTMOURNE_INTRO: + me->setActive(true); + DoCast(me, SPELL_LIGHTS_FAVOR); + _events.Reset(); + _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_1, 2000, PHASE_FROSTMOURNE); + _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_2, 11000, PHASE_FROSTMOURNE); + if (!IsHeroic()) + { + _events.ScheduleEvent(EVENT_DESTROY_SOUL, 60000, PHASE_FROSTMOURNE); + _events.ScheduleEvent(EVENT_FROSTMOURNE_TALK_3, 25000); + } + break; + case ACTION_TELEPORT_BACK: + me->CastSpell((Unit*)NULL, SPELL_RESTORE_SOUL, TRIGGERED_NONE); + me->DespawnOrUnsummon(3000); + break; + default: + break; + } + } + + void EnterEvadeMode() + { + // no running back home + if (!me->isAlive()) + return; + + me->DeleteThreatList(); + me->CombatStop(false); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (damage >= me->GetHealth()) + { + damage = me->GetHealth() - 1; + if (!me->HasAura(SPELL_TERENAS_LOSES_INSIDE) && !IsHeroic()) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(SPELL_TERENAS_LOSES_INSIDE); + _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1000); + if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) + { + warden->CastSpell((Unit*)NULL, SPELL_DESTROY_SOUL, TRIGGERED_NONE); + warden->DespawnOrUnsummon(2000); + } + + me->DespawnOrUnsummon(2000); + } + } + } + + void IsSummonedBy(Unit* /*summoner*/) + { + _events.Reset(); + _events.SetPhase(PHASE_OUTRO); + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + me->SetFacing(0.0f, lichKing); + + _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2000, 0, PHASE_OUTRO); + _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14000, 0, PHASE_OUTRO); + } + + void UpdateAI(uint32 const diff) + { + UpdateVictim(); + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FROSTMOURNE_TALK_1: + Talk(SAY_TERENAS_INTRO_1); + if (IsHeroic()) + DoCastAOE(SPELL_RESTORE_SOULS); + break; + case EVENT_FROSTMOURNE_TALK_2: + Talk(SAY_TERENAS_INTRO_2); + break; + case EVENT_FROSTMOURNE_TALK_3: + Talk(SAY_TERENAS_INTRO_3); + break; + case EVENT_OUTRO_TERENAS_TALK_1: + Talk(SAY_TERENAS_OUTRO_1); + break; + case EVENT_OUTRO_TERENAS_TALK_2: + Talk(SAY_TERENAS_OUTRO_2); + DoCastAOE(SPELL_MASS_RESURRECTION); + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + { + lichKing->AI()->DoAction(ACTION_FINISH_OUTRO); + lichKing->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + if (Creature* tirion = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->AI()->AttackStart(lichKing); + } + break; + case EVENT_DESTROY_SOUL: + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if (Creature* warden = me->FindNearestCreature(NPC_SPIRIT_WARDEN, 20.0f)) + warden->CastSpell((Unit*)NULL, SPELL_DESTROY_SOUL, TRIGGERED_NONE); + DoCast(SPELL_TERENAS_LOSES_INSIDE); + _events.ScheduleEvent(EVENT_TELEPORT_BACK, 1000); + break; + case EVENT_TELEPORT_BACK: + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); + break; + default: + break; + } + } + + // fighting Spirit Warden + if (me->isInCombat()) + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_terenas_menethilAI>(creature); + } +}; + +class npc_spirit_warden : public CreatureScript +{ + public: + npc_spirit_warden() : CreatureScript("npc_spirit_warden") { } + + struct npc_spirit_wardenAI : public ScriptedAI + { + npc_spirit_wardenAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_SOUL_RIP, urand(12000, 15000)); + DoCast(SPELL_DARK_HUNGER); + } + + void JustDied(Unit* /*killer*/) + { + if (Creature* terenas = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_TERENAS_MENETHIL))) + terenas->AI()->DoAction(ACTION_TELEPORT_BACK); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SOUL_RIP: + DoCastVictim(SPELL_SOUL_RIP); + _events.ScheduleEvent(EVENT_SOUL_RIP, urand(23000, 27000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_spirit_wardenAI>(creature); + } +}; + +class npc_spirit_bomb : public CreatureScript +{ + public: + npc_spirit_bomb() : CreatureScript("npc_spirit_bomb") { } + + struct npc_spirit_bombAI : public CreatureAI + { + npc_spirit_bombAI(Creature* creature) : CreatureAI(creature) + { + } + + void IsSummonedBy(Unit* summoner) + { + float destX, destY, destZ; + me->GetPosition(destX, destY); + destZ = 1055.0f; // approximation, gets more precise later + me->UpdateGroundPositionZ(destX, destY, destZ); + me->GetMotionMaster()->MovePoint(POINT_GROUND, destX, destY, destZ); + } + + void MovementInform(uint32 type, uint32 point) + { + if (type != POINT_MOTION_TYPE || point != POINT_GROUND) + return; + + me->RemoveAllAuras(); + DoCastAOE(SPELL_EXPLOSION); + me->DespawnOrUnsummon(1000); + } + + void AttackStart(Unit* /*victim*/) + { + } + + void UpdateAI(uint32 const diff) + { + UpdateVictim(); + // no melee attacks + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_spirit_bombAI>(creature); + } +}; + +class npc_broken_frostmourne : public CreatureScript +{ + public: + npc_broken_frostmourne() : CreatureScript("npc_broken_frostmourne") { } + + struct npc_broken_frostmourneAI : public CreatureAI + { + npc_broken_frostmourneAI(Creature* creature) : CreatureAI(creature) + { + } + + void Reset() + { + _events.Reset(); + } + + void IsSummonedBy(Unit* summoner) + { + _events.SetPhase(PHASE_OUTRO); + _events.ScheduleEvent(EVENT_OUTRO_KNOCK_BACK, 3000, 0, PHASE_OUTRO); + } + + void DoAction(int32 const action) + { + if (action == ACTION_SUMMON_TERENAS) + _events.ScheduleEvent(EVENT_OUTRO_SUMMON_TERENAS, 6000, 0, PHASE_OUTRO); + } + + void UpdateAI(uint32 const diff) + { + UpdateVictim(); + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_OUTRO_KNOCK_BACK: + DoCastAOE(SPELL_BROKEN_FROSTMOURNE_KNOCK); + break; + case EVENT_OUTRO_SUMMON_TERENAS: + DoCastAOE(SPELL_SUMMON_TERENAS); + break; + default: + break; + } + } + + // no melee attacks + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_broken_frostmourneAI>(creature); + } +}; + +class spell_the_lich_king_infest : public SpellScriptLoader +{ + public: + spell_the_lich_king_infest() : SpellScriptLoader("spell_the_lich_king_infest") { } + + class spell_the_lich_king_infest_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_infest_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (GetUnitOwner()->HealthAbovePct(90)) + { + PreventDefaultAction(); + Remove(AURA_REMOVE_BY_ENEMY_SPELL); + } + } + + void OnUpdate(AuraEffect* aurEff) + { + // multiply, starting from 2nd tick + if (aurEff->GetTickNumber() == 1) + return; + + aurEff->SetAmount(int32(aurEff->GetAmount() * 1.15f)); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_infest_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_the_lich_king_infest_AuraScript::OnUpdate, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_infest_AuraScript(); + } +}; + +class spell_the_lich_king_necrotic_plague : public SpellScriptLoader +{ + public: + spell_the_lich_king_necrotic_plague() : SpellScriptLoader("spell_the_lich_king_necrotic_plague") { } + + class spell_the_lich_king_necrotic_plague_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_necrotic_plague_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_NECROTIC_PLAGUE_JUMP)) + return false; + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* newCaster = GetTarget(); + switch (GetTargetApplication()->GetRemoveMode()) + { + case AURA_REMOVE_BY_ENEMY_SPELL: + case AURA_REMOVE_BY_EXPIRE: + case AURA_REMOVE_BY_DEATH: + break; + default: + return; + } + + CustomSpellValues values; + //values.AddSpellMod(SPELLVALUE_AURA_STACK, 2); + values.AddSpellMod(SPELLVALUE_MAX_TARGETS, 1); + GetTarget()->CastCustomSpell(SPELL_NECROTIC_PLAGUE_JUMP, values, NULL, true, NULL, NULL, GetCasterGUID()); + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_necrotic_plague_AuraScript(); + } +}; + +class spell_the_lich_king_necrotic_plague_jump : public SpellScriptLoader +{ + public: + spell_the_lich_king_necrotic_plague_jump() : SpellScriptLoader("spell_the_lich_king_necrotic_plague_jump") { } + + class spell_the_lich_king_necrotic_plague_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_necrotic_plague_SpellScript); + + bool Load() + { + _hadAura = false; + return true; + } + + void SelectTarget(std::list<Unit*>& targets) + { + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster())); + if (targets.size() < 2) + return; + + targets.resize(1); + } + + void CheckAura() + { + if (GetHitUnit()->HasAura(GetSpellInfo()->Id)) + _hadAura = true; + } + + void AddMissingStack() + { + if (!_hadAura && GetSpellValue()->EffectBasePoints[EFFECT_1] != AURA_REMOVE_BY_ENEMY_SPELL) + GetHitAura()->ModStackAmount(1); + } + + void Register() + { + BeforeHit += SpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::CheckAura); + OnHit += SpellHitFn(spell_the_lich_king_necrotic_plague_SpellScript::AddMissingStack); + } + + bool _hadAura; + }; + + class spell_the_lich_king_necrotic_plague_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_necrotic_plague_AuraScript); + + bool Load() + { + _lastAmount = 0; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + caster->GetAI()->SetData(DATA_PLAGUE_STACK, GetStackAmount()); + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + _lastAmount = aurEff->GetAmount(); + switch (GetTargetApplication()->GetRemoveMode()) + { + case AURA_REMOVE_BY_EXPIRE: + case AURA_REMOVE_BY_DEATH: + break; + default: + return; + } + + CustomSpellValues values; + values.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount()); + GetTarget()->CastCustomSpell(SPELL_NECROTIC_PLAGUE_JUMP, values, NULL, true, NULL, NULL, GetCasterGUID()); + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); + } + + void OnDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + _lastAmount = aurEff->GetAmount(); + } + + void AfterDispel(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + // this means the stack increased so don't process as if dispelled + if (aurEff->GetAmount() > _lastAmount) + return; + + CustomSpellValues values; + values.AddSpellMod(SPELLVALUE_AURA_STACK, GetStackAmount()); + values.AddSpellMod(SPELLVALUE_BASE_POINT1, AURA_REMOVE_BY_ENEMY_SPELL); // add as marker (spell has no effect 1) + GetTarget()->CastCustomSpell(SPELL_NECROTIC_PLAGUE_JUMP, values, NULL, true, NULL, NULL, GetCasterGUID()); + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, SPELL_PLAGUE_SIPHON, true); + + Remove(AURA_REMOVE_BY_ENEMY_SPELL); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_the_lich_king_necrotic_plague_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::OnDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); + AfterEffectApply += AuraEffectRemoveFn(spell_the_lich_king_necrotic_plague_AuraScript::AfterDispel, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAPPLY); + } + + int32 _lastAmount; + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_necrotic_plague_SpellScript(); + } + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_necrotic_plague_AuraScript(); + } +}; + +class spell_the_lich_king_shadow_trap_visual : public SpellScriptLoader +{ + public: + spell_the_lich_king_shadow_trap_visual() : SpellScriptLoader("spell_the_lich_king_shadow_trap_visual") { } + + class spell_the_lich_king_shadow_trap_visual_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_shadow_trap_visual_AuraScript); + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes mode) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + GetTarget()->CastSpell(GetTarget(), SPELL_SHADOW_TRAP_AURA, TRIGGERED_NONE); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_shadow_trap_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_shadow_trap_visual_AuraScript(); + } +}; + +class spell_the_lich_king_shadow_trap_periodic : public SpellScriptLoader +{ + public: + spell_the_lich_king_shadow_trap_periodic() : SpellScriptLoader("spell_the_lich_king_shadow_trap_periodic") { } + + class spell_the_lich_king_shadow_trap_periodic_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_shadow_trap_periodic_SpellScript); + + void CheckTargetCount(std::list<Unit*>& targets) + { + if (targets.empty()) + return; + + GetCaster()->CastSpell((Unit*)NULL, SPELL_SHADOW_TRAP_KNOCKBACK, true); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_shadow_trap_periodic_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_shadow_trap_periodic_SpellScript(); + } +}; + +class spell_the_lich_king_quake : public SpellScriptLoader +{ + public: + spell_the_lich_king_quake() : SpellScriptLoader("spell_the_lich_king_quake") { } + + class spell_the_lich_king_quake_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_quake_SpellScript); + + bool Load() + { + return GetCaster()->GetInstanceScript() != NULL; + } + + void FilterTargets(std::list<Unit*>& unitList) + { + if (GameObject* platform = ObjectAccessor::GetGameObject(*GetCaster(), GetCaster()->GetInstanceScript()->GetData64(DATA_ARTHAS_PLATFORM))) + unitList.remove_if(HeightDifferenceCheck(platform, 5.0f, false)); + } + + void HandleSendEvent(SpellEffIndex /*effIndex*/) + { + if (GetCaster()->IsAIEnabled) + GetCaster()->GetAI()->DoAction(ACTION_START_ATTACK); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHit += SpellEffectFn(spell_the_lich_king_quake_SpellScript::HandleSendEvent, EFFECT_1, SPELL_EFFECT_SEND_EVENT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_quake_SpellScript(); + } +}; + +class spell_the_lich_king_ice_burst_target_search : public SpellScriptLoader +{ + public: + spell_the_lich_king_ice_burst_target_search() : SpellScriptLoader("spell_the_lich_king_ice_burst_target_search") { } + + class spell_the_lich_king_ice_burst_target_search_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_ice_burst_target_search_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ICE_BURST)) + return false; + return true; + } + + void CheckTargetCount(std::list<Unit*>& unitList) + { + if (unitList.empty()) + return; + + // if there is at least one affected target cast the explosion + GetCaster()->CastSpell(GetCaster(), SPELL_ICE_BURST, true); + if (GetCaster()->GetTypeId() == TYPEID_UNIT) + GetCaster()->ToCreature()->DespawnOrUnsummon(500); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_ice_burst_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_ice_burst_target_search_SpellScript(); + } +}; + +class spell_the_lich_king_raging_spirit : public SpellScriptLoader +{ + public: + spell_the_lich_king_raging_spirit() : SpellScriptLoader("spell_the_lich_king_raging_spirit") { } + + class spell_the_lich_king_raging_spirit_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_raging_spirit_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_LIFE_SIPHON_HEAL)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_raging_spirit_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_raging_spirit_SpellScript(); + } +}; + +class ExactDistanceCheck +{ + public: + ExactDistanceCheck(Unit* source, float dist) : _source(source), _dist(dist) {} + + bool operator()(Unit* unit) + { + return _source->GetExactDist2d(unit) > _dist; + } + + private: + Unit* _source; + float _dist; +}; + +class spell_the_lich_king_defile : public SpellScriptLoader +{ + public: + spell_the_lich_king_defile() : SpellScriptLoader("spell_the_lich_king_defile") { } + + class spell_the_lich_king_defile_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_defile_SpellScript); + + void CorrectRange(std::list<Unit*>& targets) + { + targets.remove_if(ExactDistanceCheck(GetCaster(), 10.0f * GetCaster()->GetFloatValue(OBJECT_FIELD_SCALE_X))); + } + + void ChangeDamageAndGrow() + { + SetHitDamage(int32(GetHitDamage() * GetCaster()->GetFloatValue(OBJECT_FIELD_SCALE_X))); + // HACK: target player should cast this spell on defile + // however with current aura handling auras cast by different units + // cannot stack on the same aura object increasing the stack count + GetCaster()->CastSpell(GetCaster(), SPELL_DEFILE_GROW, true); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_defile_SpellScript::CorrectRange, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_defile_SpellScript::CorrectRange, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnHit += SpellHitFn(spell_the_lich_king_defile_SpellScript::ChangeDamageAndGrow); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_defile_SpellScript(); + } +}; + +class spell_the_lich_king_summon_into_air : public SpellScriptLoader +{ + public: + spell_the_lich_king_summon_into_air() : SpellScriptLoader("spell_the_lich_king_summon_into_air") { } + + class spell_the_lich_king_summon_into_air_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_summon_into_air_SpellScript); + + void ModDestHeight(SpellEffIndex effIndex) + { + static Position const offset = {0.0f, 0.0f, 15.0f, 0.0f}; + WorldLocation* dest = const_cast<WorldLocation*>(GetTargetDest()); + dest->RelocateOffset(offset); + // spirit bombs get higher + if (GetSpellInfo()->Effects[effIndex].MiscValue == NPC_SPIRIT_BOMB) + dest->RelocateOffset(offset); + } + + void Register() + { + OnEffectLaunch += SpellEffectFn(spell_the_lich_king_summon_into_air_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_summon_into_air_SpellScript(); + } +}; + +class spell_the_lich_king_soul_reaper : public SpellScriptLoader +{ + public: + spell_the_lich_king_soul_reaper() : SpellScriptLoader("spell_the_lich_king_soul_reaper") { } + + class spell_the_lich_king_soul_reaper_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_soul_reaper_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SOUL_REAPER_BUFF)) + return false; + return true; + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* caster = GetCaster()) + GetTarget()->CastSpell(caster, SPELL_SOUL_REAPER_BUFF, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_reaper_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_soul_reaper_AuraScript(); + } +}; + +class spell_the_lich_king_valkyr_target_search : public SpellScriptLoader +{ + public: + spell_the_lich_king_valkyr_target_search() : SpellScriptLoader("spell_the_lich_king_valkyr_target_search") { } + + class spell_the_lich_king_valkyr_target_search_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_valkyr_target_search_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ICE_BURST)) + return false; + return true; + } + + bool Load() + { + _target = NULL; + return true; + } + + void SelectTarget(std::list<Unit*>& unitList) + { + if (unitList.empty()) + return; + + unitList.remove_if(Trinity::UnitAuraCheck(true, GetSpellInfo()->Id)); + if (unitList.empty()) + return; + + _target = SelectRandomContainerElement(unitList); + unitList.clear(); + unitList.push_back(_target); + GetCaster()->GetAI()->SetGUID(_target->GetGUID()); + } + + void ReplaceTarget(std::list<Unit*>& unitList) + { + unitList.clear(); + if (_target) + unitList.push_back(_target); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetCaster()->CastSpell(GetHitUnit(), SPELL_CHARGE, true); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_valkyr_target_search_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_valkyr_target_search_SpellScript::ReplaceTarget, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_valkyr_target_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + + Unit* _target; + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_valkyr_target_search_SpellScript(); + } +}; + +class spell_the_lich_king_eject_all_passengers : public SpellScriptLoader +{ + public: + spell_the_lich_king_eject_all_passengers() : SpellScriptLoader("spell_the_lich_king_eject_all_passengers") { } + + class spell_the_lich_king_eject_all_passengers_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_eject_all_passengers_SpellScript); + + bool Load() + { + return GetCaster()->IsVehicle(); + } + + void HandleDummy(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetCaster()->GetVehicleKit()->RemoveAllPassengers(); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_eject_all_passengers_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_eject_all_passengers_SpellScript(); + } +}; + +class spell_the_lich_king_cast_back_to_caster : public SpellScriptLoader +{ + public: + spell_the_lich_king_cast_back_to_caster() : SpellScriptLoader("spell_the_lich_king_cast_back_to_caster") { } + + class spell_the_lich_king_cast_back_to_caster_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_cast_back_to_caster_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_cast_back_to_caster_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_cast_back_to_caster_SpellScript(); + } +}; + +class spell_the_lich_king_life_siphon : public SpellScriptLoader +{ + public: + spell_the_lich_king_life_siphon() : SpellScriptLoader("spell_the_lich_king_life_siphon") { } + + class spell_the_lich_king_life_siphon_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_life_siphon_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_LIFE_SIPHON_HEAL)) + return false; + return true; + } + + void TriggerHeal() + { + GetHitUnit()->CastCustomSpell(SPELL_LIFE_SIPHON_HEAL, SPELLVALUE_BASE_POINT0, GetHitDamage() * 10, GetCaster(), true); + } + + void Register() + { + AfterHit += SpellHitFn(spell_the_lich_king_life_siphon_SpellScript::TriggerHeal); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_life_siphon_SpellScript(); + } +}; + +class spell_the_lich_king_vile_spirits : public SpellScriptLoader +{ + public: + spell_the_lich_king_vile_spirits() : SpellScriptLoader("spell_the_lich_king_vile_spirits") { } + + class spell_the_lich_king_vile_spirits_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_vile_spirits_AuraScript); + + bool Load() + { + _is25Man = GetUnitOwner()->GetMap()->Is25ManRaid(); + return true; + } + + void OnPeriodic(AuraEffect const* aurEff) + { + if (_is25Man || ((aurEff->GetTickNumber() - 1) % 5)) + GetTarget()->CastSpell((Unit*)NULL, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true, NULL, aurEff, GetCasterGUID()); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_vile_spirits_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + + bool _is25Man; + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_vile_spirits_AuraScript(); + } +}; + +class spell_the_lich_king_vile_spirits_visual : public SpellScriptLoader +{ + public: + spell_the_lich_king_vile_spirits_visual() : SpellScriptLoader("spell_the_lich_king_vile_spirits_visual") { } + + class spell_the_lich_king_vile_spirits_visual_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_vile_spirits_visual_SpellScript); + + void ModDestHeight(SpellEffIndex /*effIndex*/) + { + Position offset = {0.0f, 0.0f, 15.0f, 0.0f}; + const_cast<WorldLocation*>(GetTargetDest())->RelocateOffset(offset); + } + + void Register() + { + OnEffectLaunch += SpellEffectFn(spell_the_lich_king_vile_spirits_visual_SpellScript::ModDestHeight, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_vile_spirits_visual_SpellScript(); + } +}; + +class spell_the_lich_king_vile_spirit_move_target_search : public SpellScriptLoader +{ + public: + spell_the_lich_king_vile_spirit_move_target_search() : SpellScriptLoader("spell_the_lich_king_vile_spirit_move_target_search") { } + + class spell_the_lich_king_vile_spirit_move_target_search_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_vile_spirit_move_target_search_SpellScript); + + bool Load() + { + _target = NULL; + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void SelectTarget(std::list<Unit*>& targets) + { + if (targets.empty()) + return; + + _target = SelectRandomContainerElement(targets); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + // for this spell, all units are in target map, however it should select one to attack + if (GetHitUnit() != _target) + return; + + GetCaster()->ToCreature()->AI()->AttackStart(GetHitUnit()); + GetCaster()->AddThreat(GetHitUnit(), 100000.0f); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_vile_spirit_move_target_search_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_vile_spirit_move_target_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + + Unit* _target; + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_vile_spirit_move_target_search_SpellScript(); + } +}; + +class spell_the_lich_king_vile_spirit_damage_target_search : public SpellScriptLoader +{ + public: + spell_the_lich_king_vile_spirit_damage_target_search() : SpellScriptLoader("spell_the_lich_king_vile_spirit_damage_target_search") { } + + class spell_the_lich_king_vile_spirit_damage_target_search_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void CheckTargetCount(std::list<Unit*>& targets) + { + if (targets.empty()) + return; + + // this spell has SPELL_AURA_BLOCK_SPELL_FAMILY so every next cast of this + // searcher spell will be blocked + GetCaster()->GetAI()->SetData(DATA_VILE, 1); + GetCaster()->CastSpell((Unit*)NULL, SPELL_SPIRIT_BURST, true); + GetCaster()->ToCreature()->DespawnOrUnsummon(3000); + GetCaster()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + + Unit* _target; + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_vile_spirit_damage_target_search_SpellScript(); + } +}; + +class spell_the_lich_king_harvest_soul : public SpellScriptLoader +{ + public: + spell_the_lich_king_harvest_soul() : SpellScriptLoader("spell_the_lich_king_harvest_soul") { } + + class spell_the_lich_king_harvest_soul_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_harvest_soul_AuraScript); + + bool Load() + { + return GetOwner()->GetInstanceScript() != NULL; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + // m_originalCaster to allow stacking from different casters, meh + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) + GetTarget()->CastSpell((Unit*)NULL, SPELL_HARVESTED_SOUL, true, NULL, NULL, GetTarget()->GetInstanceScript()->GetData64(DATA_THE_LICH_KING)); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_harvest_soul_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_harvest_soul_AuraScript(); + } +}; + +class spell_the_lich_king_lights_favor : public SpellScriptLoader +{ + public: + spell_the_lich_king_lights_favor() : SpellScriptLoader("spell_the_lich_king_lights_favor") { } + + class spell_the_lich_king_lights_favor_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_lights_favor_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* caster = GetCaster()) + if (AuraEffect* effect = GetAura()->GetEffect(EFFECT_1)) + effect->RecalculateAmount(caster); + } + + void CalculateBonus(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) + { + canBeRecalculated = true; + amount = 0; + if (Unit* caster = GetCaster()) + amount = int32(caster->GetHealthPct()); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_lights_favor_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_HEAL); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_the_lich_king_lights_favor_AuraScript::CalculateBonus, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_lights_favor_AuraScript(); + } +}; + +class spell_the_lich_king_soul_rip : public SpellScriptLoader +{ + public: + spell_the_lich_king_soul_rip() : SpellScriptLoader("spell_the_lich_king_soul_rip") { } + + class spell_the_lich_king_soul_rip_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_soul_rip_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + // shouldn't be needed, this is channeled + if (Unit* caster = GetCaster()) + caster->CastCustomSpell(SPELL_SOUL_RIP_DAMAGE, SPELLVALUE_BASE_POINT0, 5000 * aurEff->GetTickNumber(), GetTarget(), true, NULL, aurEff, GetCasterGUID()); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_the_lich_king_soul_rip_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_soul_rip_AuraScript(); + } +}; + +class spell_the_lich_king_restore_soul : public SpellScriptLoader +{ + public: + spell_the_lich_king_restore_soul() : SpellScriptLoader("spell_the_lich_king_restore_soul") { } + + class spell_the_lich_king_restore_soul_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_restore_soul_SpellScript); + + bool Load() + { + _instance = GetCaster()->GetInstanceScript(); + return _instance != NULL; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Creature* lichKing = ObjectAccessor::GetCreature(*GetCaster(), _instance->GetData64(DATA_THE_LICH_KING))) + lichKing->AI()->DoAction(ACTION_TELEPORT_BACK); + if (Creature* spawner = GetCaster()->FindNearestCreature(NPC_WORLD_TRIGGER_INFINITE_AOI, 50.0f)) + spawner->RemoveAllAuras(); + } + + void RemoveAura() + { + if (Unit* target = GetHitUnit()) + target->RemoveAurasDueToSpell(target->GetMap()->IsHeroic() ? SPELL_HARVEST_SOULS_TELEPORT : SPELL_HARVEST_SOUL_TELEPORT); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_the_lich_king_restore_soul_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + BeforeHit += SpellHitFn(spell_the_lich_king_restore_soul_SpellScript::RemoveAura); + } + + InstanceScript* _instance; + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_restore_soul_SpellScript(); + } +}; + +class spell_the_lich_king_in_frostmourne_room : public SpellScriptLoader +{ + public: + spell_the_lich_king_in_frostmourne_room() : SpellScriptLoader("spell_the_lich_king_in_frostmourne_room") { } + + class spell_the_lich_king_in_frostmourne_room_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_in_frostmourne_room_AuraScript); + + bool Load() + { + return GetOwner()->GetInstanceScript() != NULL; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + // m_originalCaster to allow stacking from different casters, meh + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) + GetTarget()->CastSpell((Unit*)NULL, SPELL_HARVESTED_SOUL, true, NULL, NULL, GetTarget()->GetInstanceScript()->GetData64(DATA_THE_LICH_KING)); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_the_lich_king_in_frostmourne_room_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_in_frostmourne_room_AuraScript(); + } +}; + +class spell_the_lich_king_summon_spirit_bomb : public SpellScriptLoader +{ + public: + spell_the_lich_king_summon_spirit_bomb() : SpellScriptLoader("spell_the_lich_king_summon_spirit_bomb") { } + + class spell_the_lich_king_summon_spirit_bomb_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_summon_spirit_bomb_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell((Unit*)NULL, uint32(GetEffectValue()), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_summon_spirit_bomb_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_summon_spirit_bomb_SpellScript(); + } +}; + +class spell_the_lich_king_trigger_vile_spirit : public SpellScriptLoader +{ + public: + spell_the_lich_king_trigger_vile_spirit() : SpellScriptLoader("spell_the_lich_king_trigger_vile_spirit") { } + + class spell_the_lich_king_trigger_vile_spirit_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_trigger_vile_spirit_SpellScript); + + void TeleportOutside() + { + Creature* target = GetHitCreature(); + if (!target) + return; + + Position dest; + Position offset; + TerenasSpawnHeroic.GetPositionOffsetTo(*target, offset); + GetCaster()->GetPosition(&dest); + dest.RelocateOffset(offset); + target->NearTeleportTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.GetOrientation()); + } + + void Register() + { + OnHit += SpellHitFn(spell_the_lich_king_trigger_vile_spirit_SpellScript::TeleportOutside); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_trigger_vile_spirit_SpellScript(); + } +}; + +class spell_the_lich_king_jump : public SpellScriptLoader +{ + public: + spell_the_lich_king_jump() : SpellScriptLoader("spell_the_lich_king_jump") { } + + class spell_the_lich_king_jump_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_jump_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->RemoveAurasDueToSpell(SPELL_RAISE_DEAD); + GetHitUnit()->CastSpell((Unit*)NULL, SPELL_JUMP_2, true); + if (Creature* creature = GetHitCreature()) + creature->AI()->DoAction(ACTION_BREAK_FROSTMOURNE); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_jump_SpellScript(); + } +}; + +class spell_the_lich_king_jump_remove_aura : public SpellScriptLoader +{ + public: + spell_the_lich_king_jump_remove_aura() : SpellScriptLoader("spell_the_lich_king_jump_remove_aura") { } + + class spell_the_lich_king_jump_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_jump_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->RemoveAurasDueToSpell(uint32(GetEffectValue())); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_jump_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_jump_SpellScript(); + } +}; + +class spell_the_lich_king_play_movie : public SpellScriptLoader +{ + public: + spell_the_lich_king_play_movie() : SpellScriptLoader("spell_the_lich_king_play_movie") { } + + class spell_the_lich_king_play_movie_SpellScript : public SpellScript + { + PrepareSpellScript(spell_the_lich_king_play_movie_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sMovieStore.LookupEntry(MOVIE_FALL_OF_THE_LICH_KING)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Player* player = GetHitPlayer()) + player->SendMovieStart(MOVIE_FALL_OF_THE_LICH_KING); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_the_lich_king_play_movie_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_the_lich_king_play_movie_SpellScript(); + } +}; + +class achievement_been_waiting_long_time : public AchievementCriteriaScript +{ + public: + achievement_been_waiting_long_time() : AchievementCriteriaScript("achievement_been_waiting_long_time") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + return target->GetAI()->GetData(DATA_PLAGUE_STACK) >= 30; + } +}; + +class achievement_neck_deep_in_vile : public AchievementCriteriaScript +{ + public: + achievement_neck_deep_in_vile() : AchievementCriteriaScript("achievement_neck_deep_in_vile") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (!target) + return false; + + return !target->GetAI()->GetData(DATA_VILE); + } +}; + +void AddSC_boss_the_lich_king() +{ + new boss_the_lich_king(); + new npc_tirion_fordring_tft(); + new npc_shambling_horror_icc(); + new npc_raging_spirit(); + new npc_valkyr_shadowguard(); + new npc_strangulate_vehicle(); + new npc_terenas_menethil(); + new npc_spirit_warden(); + new npc_spirit_bomb(); + new npc_broken_frostmourne(); + new spell_the_lich_king_infest(); + new spell_the_lich_king_necrotic_plague(); + new spell_the_lich_king_necrotic_plague_jump(); + new spell_the_lich_king_shadow_trap_visual(); + new spell_the_lich_king_shadow_trap_periodic(); + new spell_the_lich_king_quake(); + new spell_the_lich_king_ice_burst_target_search(); + new spell_the_lich_king_raging_spirit(); + new spell_the_lich_king_defile(); + new spell_the_lich_king_summon_into_air(); + new spell_the_lich_king_soul_reaper(); + new spell_the_lich_king_valkyr_target_search(); + new spell_the_lich_king_eject_all_passengers(); + new spell_the_lich_king_cast_back_to_caster(); + new spell_the_lich_king_life_siphon(); + new spell_the_lich_king_vile_spirits(); + new spell_the_lich_king_vile_spirits_visual(); + new spell_the_lich_king_vile_spirit_move_target_search(); + new spell_the_lich_king_vile_spirit_damage_target_search(); + new spell_the_lich_king_harvest_soul(); + new spell_the_lich_king_lights_favor(); + new spell_the_lich_king_soul_rip(); + new spell_the_lich_king_restore_soul(); + new spell_the_lich_king_in_frostmourne_room(); + new spell_the_lich_king_summon_spirit_bomb(); + new spell_the_lich_king_trigger_vile_spirit(); + new spell_the_lich_king_jump(); + new spell_the_lich_king_jump_remove_aura(); + new spell_trigger_spell_from_caster("spell_the_lich_king_mass_resurrection", SPELL_MASS_RESURRECTION_REAL); + new spell_the_lich_king_play_movie(); + new achievement_been_waiting_long_time(); + new achievement_neck_deep_in_vile(); +} diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 26b2546fc50..ece966fcda5 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -28,22 +28,30 @@ uint32 const EncounterCount = 13; uint32 const WeeklyNPCs = 9; uint32 const MaxHeroicAttempts = 50; +// Defined in boss_valithria_dreamwalker.cpp extern Position const ValithriaSpawnPos; // Defined in boss_sindragosa.cpp extern Position const SindragosaSpawnPos; +// Defined in boss_the_lich_king.cpp +extern Position const TerenasSpawn; +extern Position const TerenasSpawnHeroic; +extern Position const SpiritWardenSpawn; // Shared spells used by more than one script enum SharedSpells { - SPELL_BERSERK = 26662, - SPELL_BERSERK2 = 47008, + SPELL_BERSERK = 26662, + SPELL_BERSERK2 = 47008, // Deathbound Ward - SPELL_STONEFORM = 70733, + SPELL_STONEFORM = 70733, // Residue Rendezvous - SPELL_ORANGE_BLIGHT_RESIDUE = 72144, - SPELL_GREEN_BLIGHT_RESIDUE = 72145, + SPELL_ORANGE_BLIGHT_RESIDUE = 72144, + SPELL_GREEN_BLIGHT_RESIDUE = 72145, + + // The Lich King + SPELL_FROSTMOURNE_TELEPORT_VISUAL = 73078, }; enum TeleporterSpells @@ -99,6 +107,9 @@ enum DataTypes DATA_CAPTAIN_RUPERT = 34, DATA_VALITHRIA_TRIGGER = 35, DATA_VALITHRIA_LICH_KING = 36, + DATA_HIGHLORD_TIRION_FORDRING = 37, + DATA_ARTHAS_PLATFORM = 38, + DATA_TERENAS_MENETHIL = 39, }; enum CreaturesIds @@ -247,7 +258,23 @@ enum CreaturesIds // The Lich King NPC_THE_LICH_KING = 36597, + NPC_HIGHLORD_TIRION_FORDRING_LK = 38995, + NPC_TERENAS_MENETHIL_FROSTMOURNE = 36823, + NPC_SPIRIT_WARDEN = 36824, + NPC_TERENAS_MENETHIL_FROSTMOURNE_H = 39217, + NPC_SHAMBLING_HORROR = 37698, + NPC_DRUDGE_GHOUL = 37695, + NPC_ICE_SPHERE = 36633, + NPC_RAGING_SPIRIT = 36701, + NPC_DEFILE = 38757, + NPC_VALKYR_SHADOWGUARD = 36609, + NPC_VILE_SPIRIT = 37799, + NPC_WICKED_SPIRIT = 39190, + NPC_STRANGULATE_VEHICLE = 36598, NPC_WORLD_TRIGGER = 22515, + NPC_WORLD_TRIGGER_INFINITE_AOI = 36171, + NPC_SPIRIT_BOMB = 39189, + NPC_FROSTMOURNE_TRIGGER = 38584, }; enum GameObjectsIds @@ -312,6 +339,20 @@ enum GameObjectsIds GO_ICE_WALL = 202396, GO_ICE_BLOCK = 201722, GO_SIGIL_OF_THE_FROSTWING = 202181, + + // The Lich King + GO_ARTHAS_PLATFORM = 202161, + GO_ARTHAS_PRECIPICE = 202078, + GO_DOODAD_ICECROWN_THRONEFROSTYWIND01 = 202188, + GO_DOODAD_ICECROWN_THRONEFROSTYEDGE01 = 202189, + GO_DOODAD_ICESHARD_STANDING02 = 202141, + GO_DOODAD_ICESHARD_STANDING01 = 202142, + GO_DOODAD_ICESHARD_STANDING03 = 202143, + GO_DOODAD_ICESHARD_STANDING04 = 202144, + GO_DOODAD_ICECROWN_SNOWEDGEWARNING01 = 202190, + GO_FROZEN_LAVAMAN = 202436, + GO_LAVAMAN_PILLARS_CHAINED = 202437, + GO_LAVAMAN_PILLARS_UNCHAINED = 202438, }; enum AchievementCriteriaIds @@ -351,9 +392,6 @@ enum AchievementCriteriaIds enum SharedActions { - // Coldflame Traps - ACTION_STOP_TRAPS = -377440, - // Festergut ACTION_FESTERGUT_COMBAT = -366260, ACTION_FESTERGUT_GAS = -366261, @@ -374,6 +412,10 @@ enum SharedActions // Sindragosa ACTION_START_FROSTWYRM = -368530, ACTION_TRIGGER_ASPHYXIATION = -368531, + + // The Lich King + ACTION_RESTORE_LIGHT = -72262, + ACTION_FROSTMOURNE_INTRO = -36823, }; enum WeekliesICC @@ -399,6 +441,11 @@ enum WorldStatesICC WORLDSTATE_ATTEMPTS_MAX = 4942, }; +enum AreaIds +{ + AREA_THE_FROZEN_THRONE = 4859, +}; + class spell_trigger_spell_from_caster : public SpellScriptLoader { public: diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index d38af614bc0..90078e44d10 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -23,6 +23,20 @@ #include "PoolMgr.h" #include "icecrown_citadel.h" +enum EventIds +{ + EVENT_QUAKE = 23437, + EVENT_SECOND_REMORSELESS_WINTER = 23507, + EVENT_TELEPORT_TO_FROSMOURNE = 23617, +}; + +enum TimedEvents +{ + EVENT_UPDATE_EXECUTION_TIME = 1, + EVENT_QUAKE_SHATTER = 2, + EVENT_REBUILD_PLATFORM = 3, +}; + DoorData const doorData[] = { {GO_LORD_MARROWGAR_S_ENTRANCE, DATA_LORD_MARROWGAR, DOOR_TYPE_ROOM, BOUNDARY_N }, @@ -116,6 +130,13 @@ class instance_icecrown_citadel : public InstanceMapScript SpinestalkerGUID = 0; RimefangGUID = 0; TheLichKingGUID = 0; + HighlordTirionFordringGUID = 0; + TerenasMenethilGUID = 0; + ArthasPlatformGUID = 0; + ArthasPrecipiceGUID = 0; + FrozenThroneEdgeGUID = 0; + FrozenThroneWindGUID = 0; + FrozenThroneWarningGUID = 0; FrostwyrmCount = 0; SpinestalkerTrashCount = 0; RimefangTrashCount = 0; @@ -125,7 +146,6 @@ class instance_icecrown_citadel : public InstanceMapScript IsOrbWhispererEligible = true; ColdflameJetsState = NOT_STARTED; BloodQuickeningState = NOT_STARTED; - BloodQuickeningTimer = 0; BloodQuickeningMinutes = 0; } @@ -269,6 +289,13 @@ class instance_icecrown_citadel : public InstanceMapScript case NPC_THE_LICH_KING: TheLichKingGUID = creature->GetGUID(); break; + case NPC_HIGHLORD_TIRION_FORDRING_LK: + HighlordTirionFordringGUID = creature->GetGUID(); + break; + case NPC_TERENAS_MENETHIL_FROSTMOURNE: + case NPC_TERENAS_MENETHIL_FROSTMOURNE_H: + TerenasMenethilGUID = creature->GetGUID(); + break; default: break; } @@ -424,6 +451,40 @@ class instance_icecrown_citadel : public InstanceMapScript case GO_DRINK_ME: PutricideTableGUID = go->GetGUID(); break; + case GO_ARTHAS_PLATFORM: + // this enables movement at The Frozen Throne, when printed this value is 0.000000f + // however, when represented as integer client will accept only this value + go->SetUInt32Value(GAMEOBJECT_PARENTROTATION, 5535469); + ArthasPlatformGUID = go->GetGUID(); + break; + case GO_ARTHAS_PRECIPICE: + go->SetUInt32Value(GAMEOBJECT_PARENTROTATION, 4178312); + ArthasPrecipiceGUID = go->GetGUID(); + break; + case GO_DOODAD_ICECROWN_THRONEFROSTYEDGE01: + FrozenThroneEdgeGUID = go->GetGUID(); + break; + case GO_DOODAD_ICECROWN_THRONEFROSTYWIND01: + FrozenThroneWindGUID = go->GetGUID(); + break; + case GO_DOODAD_ICECROWN_SNOWEDGEWARNING01: + FrozenThroneWarningGUID = go->GetGUID(); + break; + case GO_FROZEN_LAVAMAN: + FrozenBolvarGUID = go->GetGUID(); + if (GetBossState(DATA_THE_LICH_KING) == DONE) + go->SetRespawnTime(7 * DAY); + break; + case GO_LAVAMAN_PILLARS_CHAINED: + PillarsChainedGUID = go->GetGUID(); + if (GetBossState(DATA_THE_LICH_KING) == DONE) + go->SetRespawnTime(7 * DAY); + break; + case GO_LAVAMAN_PILLARS_UNCHAINED: + PillarsUnchainedGUID = go->GetGUID(); + if (GetBossState(DATA_THE_LICH_KING) == DONE) + go->SetRespawnTime(7 * DAY); + break; default: break; } @@ -541,6 +602,12 @@ class instance_icecrown_citadel : public InstanceMapScript return RimefangGUID; case DATA_THE_LICH_KING: return TheLichKingGUID; + case DATA_HIGHLORD_TIRION_FORDRING: + return HighlordTirionFordringGUID; + case DATA_ARTHAS_PLATFORM: + return ArthasPlatformGUID; + case DATA_TERENAS_MENETHIL: + return TerenasMenethilGUID; default: break; } @@ -661,6 +728,14 @@ class instance_icecrown_citadel : public InstanceMapScript } break; case DATA_THE_LICH_KING: + { + // set the platform as active object to dramatically increase visibility range + // note: "active" gameobjects do not block grid unloading + if (GameObject* precipice = instance->GetGameObject(ArthasPrecipiceGUID)) + precipice->setActive(state == IN_PROGRESS); + if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID)) + platform->setActive(state == IN_PROGRESS); + if (instance->IsHeroic()) { if (state == FAIL && HeroicAttempts) @@ -672,7 +747,18 @@ class instance_icecrown_citadel : public InstanceMapScript theLichKing->DespawnOrUnsummon(); } } + + if (state == DONE) + { + if (GameObject* bolvar = instance->GetGameObject(FrozenBolvarGUID)) + bolvar->SetRespawnTime(7 * DAY); + if (GameObject* pillars = instance->GetGameObject(PillarsChainedGUID)) + pillars->SetRespawnTime(7 * DAY); + if (GameObject* pillars = instance->GetGameObject(PillarsUnchainedGUID)) + pillars->SetRespawnTime(7 * DAY); + } break; + } default: break; } @@ -798,13 +884,13 @@ class instance_icecrown_citadel : public InstanceMapScript switch (data) { case IN_PROGRESS: - BloodQuickeningTimer = 60000; + Events.ScheduleEvent(EVENT_UPDATE_EXECUTION_TIME, 60000); BloodQuickeningMinutes = 30; DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1); DoUpdateWorldState(WORLDSTATE_EXECUTION_TIME, BloodQuickeningMinutes); break; case DONE: - BloodQuickeningTimer = 0; + Events.CancelEvent(EVENT_UPDATE_EXECUTION_TIME); BloodQuickeningMinutes = 0; DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0); break; @@ -1050,32 +1136,103 @@ class instance_icecrown_citadel : public InstanceMapScript void Update(uint32 diff) { - if (BloodQuickeningState == IN_PROGRESS) + if (BloodQuickeningState != IN_PROGRESS && GetBossState(DATA_THE_LICH_KING) != IN_PROGRESS) + return; + + Events.Update(diff); + + while (uint32 eventId = Events.ExecuteEvent()) { - if (BloodQuickeningTimer <= diff) + switch (eventId) { - --BloodQuickeningMinutes; - BloodQuickeningTimer = 60000; - if (BloodQuickeningMinutes) + case EVENT_UPDATE_EXECUTION_TIME: { - DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1); - DoUpdateWorldState(WORLDSTATE_EXECUTION_TIME, BloodQuickeningMinutes); + --BloodQuickeningMinutes; + if (BloodQuickeningMinutes) + { + Events.ScheduleEvent(EVENT_UPDATE_EXECUTION_TIME, 60000); + DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 1); + DoUpdateWorldState(WORLDSTATE_EXECUTION_TIME, BloodQuickeningMinutes); + } + else + { + BloodQuickeningState = DONE; + DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0); + if (Creature* bq = instance->GetCreature(BloodQueenLanaThelGUID)) + bq->AI()->DoAction(ACTION_KILL_MINCHAR); + } + SaveToDB(); + break; } - else + case EVENT_QUAKE_SHATTER: { - BloodQuickeningState = DONE; - DoUpdateWorldState(WORLDSTATE_SHOW_TIMER, 0); - if (Creature* bq = instance->GetCreature(BloodQueenLanaThelGUID)) - bq->AI()->DoAction(ACTION_KILL_MINCHAR); + if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID)) + platform->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED); + if (GameObject* edge = instance->GetGameObject(FrozenThroneEdgeGUID)) + edge->SetGoState(GO_STATE_ACTIVE); + if (GameObject* wind = instance->GetGameObject(FrozenThroneWindGUID)) + wind->SetGoState(GO_STATE_READY); + if (GameObject* warning = instance->GetGameObject(FrozenThroneWarningGUID)) + warning->SetGoState(GO_STATE_READY); + if (Creature* theLichKing = instance->GetCreature(TheLichKingGUID)) + theLichKing->AI()->DoAction(ACTION_RESTORE_LIGHT); + break; } - SaveToDB(); + case EVENT_REBUILD_PLATFORM: + if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID)) + platform->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING); + if (GameObject* edge = instance->GetGameObject(FrozenThroneEdgeGUID)) + edge->SetGoState(GO_STATE_READY); + if (GameObject* wind = instance->GetGameObject(FrozenThroneWindGUID)) + wind->SetGoState(GO_STATE_ACTIVE); + break; + default: + break; } - else - BloodQuickeningTimer -= diff; + } + } + + void ProcessEvent(WorldObject* /*source*/, uint32 eventId) + { + switch (eventId) + { + case EVENT_QUAKE: + if (GameObject* warning = instance->GetGameObject(FrozenThroneWarningGUID)) + warning->SetGoState(GO_STATE_ACTIVE); + Events.ScheduleEvent(EVENT_QUAKE_SHATTER, 5000); + break; + case EVENT_SECOND_REMORSELESS_WINTER: + if (GameObject* platform = instance->GetGameObject(ArthasPlatformGUID)) + { + platform->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED); + Events.ScheduleEvent(EVENT_REBUILD_PLATFORM, 1500); + } + break; + case EVENT_TELEPORT_TO_FROSMOURNE: // Harvest Soul (normal mode) + if (Creature* terenas = instance->SummonCreature(NPC_TERENAS_MENETHIL_FROSTMOURNE, TerenasSpawn, NULL, 63000)) + { + terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO); + std::list<Creature*> triggers; + GetCreatureListWithEntryInGrid(triggers, terenas, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f); + if (!triggers.empty()) + { + triggers.sort(Trinity::ObjectDistanceOrderPred(terenas, false)); + Unit* visual = triggers.front(); + visual->CastSpell(visual, SPELL_FROSTMOURNE_TELEPORT_VISUAL, true); + } + + if (Creature* warden = instance->SummonCreature(NPC_SPIRIT_WARDEN, SpiritWardenSpawn, NULL, 63000)) + { + terenas->AI()->AttackStart(warden); + warden->AddThreat(terenas, 300000.0f); + } + } + break; } } protected: + EventMap Events; uint64 LadyDeathwisperElevatorGUID; uint64 DeathbringerSaurfangGUID; uint64 DeathbringerSaurfangDoorGUID; @@ -1105,8 +1262,17 @@ class instance_icecrown_citadel : public InstanceMapScript uint64 SpinestalkerGUID; uint64 RimefangGUID; uint64 TheLichKingGUID; + uint64 HighlordTirionFordringGUID; + uint64 TerenasMenethilGUID; + uint64 ArthasPlatformGUID; + uint64 ArthasPrecipiceGUID; + uint64 FrozenThroneEdgeGUID; + uint64 FrozenThroneWindGUID; + uint64 FrozenThroneWarningGUID; + uint64 FrozenBolvarGUID; + uint64 PillarsChainedGUID; + uint64 PillarsUnchainedGUID; uint32 TeamInInstance; - uint32 BloodQuickeningTimer; uint32 ColdflameJetsState; uint32 FrostwyrmCount; uint32 SpinestalkerTrashCount; |