aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/3.3.5/2016_99_99_00_world.sql120
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp1184
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp7
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h13
4 files changed, 975 insertions, 349 deletions
diff --git a/sql/updates/world/3.3.5/2016_99_99_00_world.sql b/sql/updates/world/3.3.5/2016_99_99_00_world.sql
new file mode 100644
index 00000000000..46d4dc131b5
--- /dev/null
+++ b/sql/updates/world/3.3.5/2016_99_99_00_world.sql
@@ -0,0 +1,120 @@
+-- Skadi the ruthless
+SET @PATH := 2689300; -- Do not change this value without updating the following values in boss_skadi.cpp: GRAUF_PATH_INITIAL,GRAUF_PATH_RIGHT,GRAUF_PATH_LEFT.
+DELETE FROM `waypoint_data` WHERE `id` IN(@PATH, @PATH+1, @PATH+2);
+INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
+(@PATH, 0, 310.2165, -510.5302, 120.5487, 0, 0, 1, 0, 100, 0), -- Initial
+(@PATH, 1, 300.8685, -520.3249, 133.3664, 0, 0, 1, 0, 100, 0),
+(@PATH, 2, 298.3447, -529.4818, 137.2831, 0, 0, 1, 0, 100, 0),
+(@PATH, 3, 309.0959, -540.3195, 134.9774, 0, 0, 1, 0, 100, 0),
+(@PATH, 4, 323.6415, -547.9715, 130.3106, 0, 0, 1, 0, 100, 0),
+(@PATH, 5, 357.078, -549.1597, 116.3105, 0, 0, 1, 0, 100, 0),
+(@PATH, 6, 401.2573, -550.2768, 114.9216, 0, 0, 1, 0, 100, 0),
+(@PATH, 7, 464.5062, -555.9442, 114.4494, 0, 0, 1, 0, 100, 0),
+(@PATH, 8, 496.192, -556.9628, 114.8661, 0, 0, 1, 0, 100, 0),
+(@PATH, 9, 523.2011, -548.9916, 114.8661, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 0, 453.1242, -517.17, 120.0273, 0, 0, 1, 0, 100, 0), -- Right
+(@PATH+1, 1, 388.3312, -514.3768, 121.1193, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 2, 340.2752, -512.0926, 122.3138, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 3, 313.0756, -509.138, 125.175, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 4, 296.6964, -522.6705, 133.7026, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 5, 301.2957, -549.4583, 137.4249, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 6, 335.0746, -552.1211, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 7, 397.6237, -553.9203, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 8, 459.6321, -558.0078, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 9, 505.5458, -568.7815, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 10, 518.099, -560.8499, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+1, 11, 520.4827, -541.5633, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 0, 451.9824, -509.2508, 120.0273, 0, 0, 1, 0, 100, 0), -- Left
+(@PATH+2, 1, 399.2607, -510.0719, 121.1193, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 2, 350.6099, -508.3901, 122.3138, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 3, 325.8217, -506.7769, 125.175, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 4, 301.2941, -516.6706, 133.7026, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 5, 301.2957, -549.4583, 137.4249, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 6, 335.0746, -552.1211, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 7, 397.6237, -553.9203, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 8, 459.6321, -558.0078, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 9, 505.5458, -568.7815, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 10, 518.099, -560.8499, 119.8416, 0, 0, 1, 0, 100, 0),
+(@PATH+2, 11, 520.4827, -541.5633, 119.8416, 0, 0, 1, 0, 100, 0);
+
+UPDATE `creature_template` SET `InhabitType`=4, `HoverHeight`='3.75' WHERE `entry` IN(26893,30775);
+UPDATE `creature_template` SET `unit_flags`=320 WHERE `entry` IN(26693,30807);
+UPDATE `creature_template` SET `ScriptName`='npc_grauf' WHERE `entry`IN(26893);
+UPDATE `creature_template` SET `unit_flags`=320 WHERE `entry`IN(26893,30775);
+UPDATE `creature` SET `MovementType`=0, `spawndist`=0 WHERE `guid` IN(126125,126126,126127);
+UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_ymirjar_warrior' WHERE `entry`=26690;
+UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_ymirjar_witch_doctor' WHERE `entry`=26691;
+UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_ymirjar_harpooner' WHERE `entry`=26692;
+UPDATE `gameobject_template` SET `ScriptName`='' WHERE `entry` IN (192175,192176,192177);
+
+DELETE FROM `areatrigger_scripts` WHERE `ScriptName`='at_skadi_gaunlet';
+INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES
+(4991,'at_skadi_gaunlet');
+
+DELETE FROM `creature_text` WHERE `entry` IN (26893);
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `TextRange`, `BroadcastTextID`) VALUES
+(26893, 0, 0, '%s takes a deep breath!', 41, 0, 100, 0, 0, 0, 'Grauf - Emote', 1, 20774),
+(26893, 1, 0, 'Skadi the Ruthless is within range of the harpoon launchers!', 41, 0, 100, 0, 0, 0, 'Skadi Emote', 1, 27809);
+
+DELETE FROM `disables` WHERE `sourceType`=0 AND `entry` IN (49308);
+INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `params_0`, `params_1`, `comment`) VALUES
+(0,49308,64,0,0,'Disable LoS for spell Utgard Pinacle Reset Check');
+
+-- Conditions
+UPDATE `conditions` SET `ConditionValue2`=19871 WHERE `SourceTypeOrReferenceId`=13 and`SourceGroup`=1 and`SourceEntry`=48641;
+DELETE FROM `conditions` WHERE `SourceEntry` IN (47593,47594,47563,48642,47547,49308) and `SourceTypeOrReferenceId`=13;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 1, 47593, 0, 0, 31, 0, 3, 28351, 0, 0, 0, 0, '', ''),
+(13, 1, 47594, 0, 0, 31, 0, 3, 28351, 0, 0, 0, 0, '', ''),
+(13, 1, 47563, 0, 0, 31, 0, 3, 28351, 0, 0, 0, 0, '', ''),
+(13, 1, 48642, 0, 0, 31, 0, 3, 26893, 0, 0, 0, 0, '', ''),
+(13, 1, 48642, 0, 1, 31, 0, 3, 22515, 0, 0, 0, 0, '', ''),
+(13, 1, 47547, 0, 0, 31, 0, 3, 28351, 0, 0, 0, 0, '', ''),
+(13, 1, 49308, 0, 0, 31, 0, 3, 28351, 0, 0, 0, 0, '', ''),
+(13, 2, 49308, 0, 0, 31, 0, 3, 26693, 0, 0, 0, 0, '', '');
+
+DELETE FROM `spell_area` WHERE `spell`=47546;
+INSERT INTO `spell_area`(`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES
+(47546,1196,0,0,0,0,0,1,64,11);
+
+UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry` IN(23472,19871,28351);
+UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=28351;
+DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid` IN (28351,26690,26691,26692);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(28351, 0, 0, 0, 8, 0, 100, 0, 47563, 0, 0, 0, 11, 47574, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Flame Breath Trigger - Cast Freezing Trap AoE'),
+(28351, 0, 1, 0, 8, 0, 100, 0, 47593, 0, 0, 0, 11, 47594, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Flame Breath Trigger - Cast Freezing Trap AoE');
+
+DELETE FROM `spelldifficulty_dbc` WHERE `id` IN (50225,50255,50228,50258,59334,47579,49089,49084,49091);
+INSERT INTO `spelldifficulty_dbc` (`id`, `spellid0`, `spellid1`) VALUES
+(49084, 49084, 59246),
+(49089, 49089, 59247),
+(49091, 49091, 59249),
+(50255, 50255, 59331),
+(50258, 50258, 59334),
+(50228, 50228, 59322),
+(47579, 47579, 60020);
+
+DELETE FROM `spell_custom_attr` WHERE `entry`=48642;
+INSERT INTO `spell_custom_attr` (`entry`, `attributes`) VALUES
+(48642, 32768); -- SPELL_ATTR0_CU_IGNORE_ARMOR
+
+DELETE FROM `spell_script_names` where `ScriptName` IN ('spell_skadi_poisoned_spear','spell_freezing_cloud_area_right','spell_freezing_cloud_area_left','spell_summon_gauntlet_mobs_periodic','spell_skadi_launch_harpoon','spell_skadi_reset_check','spell_freezing_cloud_damage');
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(50255, 'spell_skadi_poisoned_spear'),
+(59331, 'spell_skadi_poisoned_spear'),
+(47594, 'spell_freezing_cloud_area_right'),
+(47574, 'spell_freezing_cloud_area_left'),
+(47579, 'spell_freezing_cloud_damage'),
+(60020, 'spell_freezing_cloud_damage'),
+(59275, 'spell_summon_gauntlet_mobs_periodic'),
+(48642, 'spell_skadi_launch_harpoon'),
+(49308, 'spell_skadi_reset_check');
+
+DELETE FROM `spell_target_position` where `id`=61790;
+INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `VerifiedBuild`) VALUES
+(61790, 0, 575, 476.799, -511.167, 104.723, 3.14159, 20779);
+
+DELETE FROM `disables` WHERE `sourceType`=4 AND `entry`=7595;
+DELETE FROM `achievement_criteria_data` where `criteria_id` = 7595 and `type` = 11;
+INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `ScriptName`) VALUES
+(7595, 11, 'achievement_girl_love_to_skadi');
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp
index 7615217a794..b0aa886612a 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp
@@ -15,144 +15,124 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* Script Data Start
-SDName: Boss_Skadi
-SDAuthor: LordVanMartin, JohnHoliver
-SD%Complete: 90%
-SDComment: <Known Bugs>
- After Unmount() he appears to still be flying even with SetFlying(false)
- </Known Bugs>
-SDCategory: Utgarde Pinnacle
-Script Data End */
-
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
#include "utgarde_pinnacle.h"
+#include "GridNotifiers.h"
#include "Player.h"
-#include "SpellInfo.h"
+#include "MoveSplineInit.h"
+
+enum Spells
+{
+ // Skadi Spells
+ SPELL_CRUSH = 50234,
+ SPELL_POISONED_SPEAR = 50255,
+ SPELL_POISONED_SPEAR_PERIODIC = 50258,
+ SPELL_WHIRLWIND = 50228,
+ SPELL_SKADI_TELEPORT = 61790,
+ SPELL_LAUNCH_HARPOON = 48642,
+ SPELL_SUMMON_GAUNLET_MOBS_PERIODIC = 59275,
+ SPELL_FREEZING_CLOUD = 47579,
+ SPELL_RIDE_GRAUF = 61791,
+ SPELL_FREEZING_CLOUD_RIGHT_PERIODIC = 47592,
+ SPELL_FREEZING_CLOUD_LEFT_PERIODIC = 47590,
+ SPELL_FREEZING_CLOUD_RIGHT = 47593,
+ SPELL_FREEZING_CLOUD_LEFT = 47563,
+ SPELL_FREEZING_CLOUD_RIGHT_AREA = 47594,
+ SPELL_FREEZING_CLOUD_LEFT_AREA = 47574,
+ SPELL_SUMMON_YMIRJAR_WARRIOR_W = 48631,
+ SPELL_SUMMON_YMIRJAR_WARRIOR_E = 48632,
+ SPELL_SUMMON_YMIRJAR_HARPOONER_W = 48633,
+ SPELL_SUMMON_YMIRJAR_HARPOONER_E = 48634,
+ SPELL_SUMMON_YMIRJAR_WITCH_DOCTOR_W = 48635,
+ SPELL_SUMMON_YMIRJAR_WITCH_DOCTOR_E = 48636,
+ SPELL_UTGARDE_PINNACLE_GAUNTLET_EFFECT = 47547,
+ SPELL_UTGARDE_PINNACLE_GUANTLET_RESET_CHECK = 49308,
+ // Trash
+ SPELL_HAMSTRING = 48639,
+ SPELL_STRIKE = 48640,
+ SPELL_SHADOW_BOLT = 49084,
+ SPELL_SHRINK = 49089,
+ SPELL_NET = 49092,
+ SPELL_THROW = 49091,
+ SPELL_SUMMON_HARPOON = 56789,
+};
enum Yells
{
SAY_AGGRO = 0,
SAY_KILL = 1,
- EMOTE_RANGE = 2,
SAY_DEATH = 3,
- SAY_DRAKE_DEATH = 4,
- EMOTE_BREATH = 5,
+ SAY_DRAKE_DEATH = 5,
SAY_DRAKE_BREATH = 6
};
-static Position SpawnLoc = {468.931f, -513.555f, 104.723f, 0};
-static Position Location[]=
+enum Emotes
{
- // Boss
- {341.740997f, -516.955017f, 104.66900f, 0}, // 0
- {293.299f, -505.95f, 142.03f, 0}, // 1
- {301.664f, -535.164f, 146.097f, 0}, // 2
- {521.031006f, -544.667847f, 128.80064f, 0}, // 3
- {477.311981f, -509.296814f, 104.72308f, 0}, // 4
- {341.740997f, -516.955017f, 104.66900f, 0}, // 5
- {341.740997f, -516.955017f, 104.66900f, 0}, // 6
- {341.740997f, -516.955017f, 104.66900f, 0}, // 7
- // Triggers Left
- {469.661f, -484.546f, 104.712f, 0}, // 8
- {483.315f, -485.028f, 104.718f, 0}, // 9
- {476.87f, -487.994f, 104.735f, 0}, //10
- {477.512f, -497.772f, 104.728f, 0}, //11
- {486.287f, -500.759f, 104.722f, 0}, //12
- {480.1f, -503.895f, 104.722f, 0}, //13
- {472.391f, -505.103f, 104.723f, 0}, //14
- {478.885f, -510.803f, 104.723f, 0}, //15
- {489.529f, -508.615f, 104.723f, 0}, //16
- {484.272f, -508.589f, 104.723f, 0}, //17
- {465.328f, -506.495f, 104.427f, 0}, //18
- {456.885f, -508.104f, 104.447f, 0}, //19
- {450.177f, -507.989f, 105.247f, 0}, //20
- {442.273f, -508.029f, 104.813f, 0}, //21
- {434.225f, -508.19f, 104.787f, 0}, //22
- {423.902f, -508.525f, 104.274f, 0}, //23
- {414.551f, -508.645f, 105.136f, 0}, //24
- {405.787f, -508.755f, 104.988f, 0}, //25
- {398.812f, -507.224f, 104.82f, 0}, //26
- {389.702f, -506.846f, 104.729f, 0}, //27
- {381.856f, -506.76f, 104.756f, 0}, //28
- {372.881f, -507.254f, 104.779f, 0}, //29
- {364.978f, -508.182f, 104.673f, 0}, //30
- {357.633f, -508.075f, 104.647f, 0}, //31
- {350.008f, -506.826f, 104.588f, 0}, //32
- {341.69f, -506.77f, 104.499f, 0}, //33
- {335.31f, -505.745f, 105.18f, 0}, //34
- {471.178f, -510.74f, 104.723f, 0}, //35
- {461.759f, -510.365f, 104.199f, 0}, //36
- {424.07287f, -510.082916f, 104.711082f, 0}, //37
- // Triggers Right
- {489.46f, -513.297f, 105.413f, 0}, //38
- {485.706f, -517.175f, 104.724f, 0}, //39
- {480.98f, -519.313f, 104.724f, 0}, //40
- {475.05f, -520.52f, 104.724f, 0}, //41
- {482.97f, -512.099f, 104.724f, 0}, //42
- {477.082f, -514.172f, 104.724f, 0}, //43
- {468.991f, -516.691f, 104.724f, 0}, //44
- {461.722f, -517.063f, 104.627f, 0}, //45
- {455.88f, -517.681f, 104.707f, 0}, //46
- {450.499f, -519.099f, 104.701f, 0}, //47
- {444.889f, -518.963f, 104.82f, 0}, //48
- {440.181f, -518.893f, 104.861f, 0}, //49
- {434.393f, -518.758f, 104.891f, 0}, //50
- {429.328f, -518.583f, 104.904f, 0}, //51
- {423.844f, -518.394f, 105.004f, 0}, //52
- {418.707f, -518.266f, 105.135f, 0}, //53
- {413.377f, -518.085f, 105.153f, 0}, //54
- {407.277f, -517.844f, 104.893f, 0}, //55
- {401.082f, -517.443f, 104.723f, 0}, //56
- {394.933f, -514.64f, 104.724f, 0}, //57
- {388.917f, -514.688f, 104.734f, 0}, //58
- {383.814f, -515.834f, 104.73f, 0}, //59
- {377.887f, -518.653f, 104.777f, 0}, //60
- {371.376f, -518.289f, 104.781f, 0}, //61
- {365.669f, -517.822f, 104.758f, 0}, //62
- {359.572f, -517.314f, 104.706f, 0}, //63
- {353.632f, -517.146f, 104.647f, 0}, //64
- {347.998f, -517.038f, 104.538f, 0}, //65
- {341.803f, -516.98f, 104.584f, 0}, //66
- {335.879f, -516.674f, 104.628f, 0}, //67
- {329.871f, -515.92f, 104.711f, 0}, //68
- // Breach Zone
- {485.4577f, -511.2515f, 115.3011f, 0}, //69
- {435.1892f, -514.5232f, 118.6719f, 0}, //70
- {413.9327f, -540.9407f, 138.2614f, 0}, //71
+ EMOTE_BREATH = 0,
+ EMOTE_ON_RANGE
};
-enum CombatPhase
+enum Data
{
- FLYING,
- SKADI
+
+ DATA_LOVE_TO_SKADI = 0,
+ FIRST_WAVE_MAX_WARRIORS = 10,
+ FIRST_WAVE_SIZE = 13,
+ GRAUF_PATH_INITIAL = 2689300,
+ GRAUF_PATH_RIGHT = 2689301,
+ GRAUF_PATH_LEFT = 2689302,
+ ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI = 17726,
};
-enum Spells
+enum Points
{
- // Skadi Spells
- SPELL_CRUSH = 50234,
- SPELL_POISONED_SPEAR = 50225, //isn't being cast
- SPELL_WHIRLWIND = 50228, //random target, but not the tank approx. every 20s
- SPELL_RAPID_FIRE = 56570,
- SPELL_HARPOON_DAMAGE = 56578,
- SPELL_FREEZING_CLOUD = 47579,
+ POINT_0 = 0,
+ POINT_1 = 1,
+ POINT_9 = 9,
+ POINT_11 = 11,
+ POINT_LEFT = 21,
+ POINT_RIGHT = 22
};
-enum Creatures
+enum Actions
{
- NPC_YMIRJAR_WARRIOR = 26690,
- NPC_YMIRJAR_WITCH_DOCTOR = 26691,
- NPC_YMIRJAR_HARPOONER = 26692,
- NPC_GRAUF = 26893,
- NPC_TRIGGER = 28351,
- DATA_MOUNT = 27043,
+ ACTION_START_ENCOUNTER = 0,
+ ACTION_FLAME,
+ ACTION_GAUNTLET_END,
+ ACTION_HARPOON_HIT,
};
-enum Achievments
+enum CombatPhase
{
- ACHIEV_TIMED_START_EVENT = 17726,
+ PHASE_FLYING = 0,
+ PHASE_GROUND
+};
+
+Position const BreachPoint = { 0.0f, 0.0f, 0.0f, 2.670354f };
+Position const SecondaryWavesInitialPoint = { 478.7434f, -505.5758f, 104.7237f };
+Position const SecondaryWavesFinalPoint = { 318.177f, -503.8898f, 104.5326f };
+Position const SpawnLoc = { 477.5808f, -484.5591f, 104.8221f, 4.677482f };
+Position const GraufLoc = { 341.7411f, -516.9545f, 104.6695f, 3.124139f };
+Position const BreathPointRight = { 496.434f, -517.578f, 120.0f, 3.124139f };
+Position const BreathPointLeft = { 500.243f, -501.693f, 120.0f, 3.228859f };
+Position const FirstWaveLocations[FIRST_WAVE_SIZE] =
+{
+ { 458.5323f, -516.2537f, 104.617f },
+ { 429.4242f, -517.5624f, 104.8936f },
+ { 394.4955f, -514.6144f, 104.7235f },
+ { 362.2862f, -515.8771f, 104.7539f },
+ { 333.5374f, -514.7942f, 104.4779f },
+ { 457.6105f, -508.8362f, 104.4013f },
+ { 427.4026f, -510.7716f, 104.8802f },
+ { 392.5114f, -507.9429f, 104.7433f },
+ { 362.9511f, -508.4115f, 104.7218f },
+ { 333.536f, -506.0805f, 104.4258f },
+ { 478.31f, -511.049f, 104.7242f, 3.263766f },
+ { 482.25f, -514.1273f, 104.7234f, 3.263766f },
+ { 481.3883f, -507.1089f, 104.7241f, 3.263766f },
};
class boss_skadi : public CreatureScript
@@ -160,329 +140,837 @@ class boss_skadi : public CreatureScript
public:
boss_skadi() : CreatureScript("boss_skadi") { }
- CreatureAI* GetAI(Creature* creature) const override
+ struct boss_skadiAI : public BossAI
{
- return GetInstanceAI<boss_skadiAI>(creature);
- }
-
- struct boss_skadiAI : public ScriptedAI
- {
- boss_skadiAI(Creature* creature) : ScriptedAI(creature), Summons(me)
+ boss_skadiAI(Creature* creature) : BossAI(creature, DATA_SKADI_THE_RUTHLESS)
{
Initialize();
- instance = creature->GetInstanceScript();
- m_uiMovementTimer = 0;
- m_uiSummonTimer = 0;
}
void Initialize()
{
- m_uiCrushTimer = 8000;
- m_uiPoisonedSpearTimer = 10000;
- m_uiWhirlwindTimer = 20000;
- m_uiMountTimer = 3000;
- m_uiWaypointId = 0;
- m_bSaidEmote = false;
- m_uiSpellHitCount = 0;
-
- Phase = SKADI;
+ firstWaveSummoned = false;
+ harpoonHit = 0;
+ loveSkadi = 0;
+ _phase = PHASE_GROUND;
+ scheduler.SetValidator([this]
+ {
+ return !me->HasUnitState(UNIT_STATE_CASTING);
+ });
}
- InstanceScript* instance;
- SummonList Summons;
- ObjectGuid m_uiGraufGUID;
-
- uint32 m_uiCrushTimer;
- uint32 m_uiPoisonedSpearTimer;
- uint32 m_uiWhirlwindTimer;
- uint32 m_uiWaypointId;
- uint32 m_uiMovementTimer;
- uint32 m_uiMountTimer;
- uint32 m_uiSummonTimer;
- uint8 m_uiSpellHitCount;
- bool m_bSaidEmote;
-
- CombatPhase Phase;
-
void Reset() override
{
+ _Reset();
Initialize();
+ me->SetReactState(REACT_PASSIVE);
+ if (!ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GRAUF)))
+ me->SummonCreature(NPC_GRAUF, GraufLoc);
- Summons.DespawnAll();
- me->SetSpeedRate(MOVE_FLIGHT, 3.0f);
- if ((ObjectAccessor::GetCreature(*me, m_uiGraufGUID) == NULL) && !me->IsMounted())
- me->SummonCreature(NPC_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f);
- instance->SetBossState(DATA_SKADI_THE_RUTHLESS, NOT_STARTED);
- instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
+ instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI);
}
- void JustReachedHome() override
+ void EnterEvadeMode(EvadeReason /*why*/)
{
- me->SetCanFly(false);
- me->Dismount();
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- if (!ObjectAccessor::GetCreature(*me, m_uiGraufGUID))
- me->SummonCreature(NPC_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f);
+ summons.DespawnAll();
+ _DespawnAtEvade();
}
- void EnterCombat(Unit* /*who*/) override
+ void JustSummoned(Creature* summon) override
{
- Talk(SAY_AGGRO);
+ switch (summon->GetEntry())
+ {
+ case NPC_YMIRJAR_WARRIOR:
+ case NPC_YMIRJAR_WITCH_DOCTOR:
+ case NPC_YMIRJAR_HARPOONER:
+ if (firstWaveSummoned)
+ summon->GetMotionMaster()->MovePoint(POINT_1, SecondaryWavesInitialPoint);
+ break;
+ default:
+ break;
+ }
+ summons.Summon(summon);
+ }
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
+ void SpawnFirstWave()
+ {
+ for (uint8 i = 0; i < FIRST_WAVE_MAX_WARRIORS; i++)
+ if (Creature* summon = me->SummonCreature(NPC_YMIRJAR_WARRIOR, SpawnLoc, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
+ summon->GetMotionMaster()->MovePoint(POINT_0, FirstWaveLocations[i]);
+
+ if (Creature* crea = me->SummonCreature(NPC_YMIRJAR_WITCH_DOCTOR, SpawnLoc, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
+ crea->GetMotionMaster()->MovePoint(POINT_0, FirstWaveLocations[10]);
+ if (Creature* crea = me->SummonCreature(NPC_YMIRJAR_HARPOONER, SpawnLoc, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
+ crea->GetMotionMaster()->MovePoint(POINT_0, FirstWaveLocations[11]);
+ if (Creature* crea = me->SummonCreature(NPC_YMIRJAR_HARPOONER, SpawnLoc, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
+ crea->GetMotionMaster()->MovePoint(POINT_0, FirstWaveLocations[12]);
+
+ firstWaveSummoned = true;
+ }
- Phase = FLYING;
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_DEATH);
+ }
- m_uiMovementTimer = 1000;
- m_uiSummonTimer = 10000;
- me->SetInCombatWithZone();
- instance->SetBossState(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS);
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
- me->GetMotionMaster()->MoveJump(Location[0], 5.0f, 10.0f);
- me->SetWalk(false);
- m_uiMountTimer = 1000;
- Summons.DespawnEntry(NPC_GRAUF);
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_KILL);
}
- void JustSummoned(Creature* summoned) override
+ void DoAction(int32 action) override
{
- switch (summoned->GetEntry())
+ switch (action)
{
- case NPC_GRAUF:
- m_uiGraufGUID = summoned->GetGUID();
+ case ACTION_START_ENCOUNTER:
+ instance->SetBossState(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ me->setActive(true);
+ SpawnFirstWave();
+ Talk(SAY_AGGRO);
+ _phase = PHASE_FLYING;
+ instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_LODI_DODI_WE_LOVES_THE_SKADI);
+
+ scheduler
+ .Schedule(Seconds(6), [this](TaskContext resetCheck)
+ {
+ if (Creature* resetTrigger = me->FindNearestCreature(NPC_TRIGGER_RESET, 200.0f))
+ resetTrigger->CastSpell(resetTrigger, SPELL_UTGARDE_PINNACLE_GUANTLET_RESET_CHECK, true);
+ resetCheck.Repeat();
+ })
+ .Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ if (Creature* grauf = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GRAUF)))
+ DoCast(grauf, SPELL_RIDE_GRAUF);
+ });
+
+ if (Creature* summonTrigger = me->SummonCreature(NPC_WORLD_TRIGGER, SpawnLoc))
+ summonTrigger->CastSpell(summonTrigger, SPELL_SUMMON_GAUNLET_MOBS_PERIODIC, true);
+
+ if (Creature* combatTrigger = me->SummonCreature(NPC_COMBAT_TRIGGER, SpawnLoc))
+ combatTrigger->AI()->DoZoneInCombat();
break;
- case NPC_YMIRJAR_WARRIOR:
- case NPC_YMIRJAR_WITCH_DOCTOR:
- case NPC_YMIRJAR_HARPOONER:
- summoned->setActive(true);
- summoned->SetInCombatWithZone();
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
- summoned->AI()->AttackStart(target);
+ case ACTION_FLAME:
+ if (loveSkadi == 1)
+ loveSkadi++;
+ Talk(SAY_DRAKE_BREATH);
break;
- case NPC_TRIGGER:
- summoned->CastSpell((Unit*)NULL, SPELL_FREEZING_CLOUD, true);
- summoned->DespawnOrUnsummon(10*IN_MILLISECONDS);
+ case ACTION_GAUNTLET_END:
+ me->ExitVehicle();
+ Talk(SAY_DRAKE_DEATH);
+ DoCast(me, SPELL_SKADI_TELEPORT, true);
+ summons.DespawnEntry(NPC_WORLD_TRIGGER);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC);
+ me->SetReactState(REACT_AGGRESSIVE);
+ _phase = PHASE_GROUND;
+
+ scheduler
+ .Schedule(Seconds(8), [this](TaskContext crush)
+ {
+ DoCastVictim(SPELL_CRUSH);
+ crush.Repeat();
+ })
+ .Schedule(Seconds(11), [this](TaskContext poisonedSpear)
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(target, SPELL_POISONED_SPEAR);
+ poisonedSpear.Repeat();
+ })
+ .Schedule(Seconds(23), [this](TaskContext whirlwind)
+ {
+ DoCast(SPELL_WHIRLWIND);
+ whirlwind.Repeat();
+ });
+ break;
+ case ACTION_HARPOON_HIT:
+ harpoonHit++;
+ if (harpoonHit == 1)
+ loveSkadi = 1;
break;
}
- Summons.Summon(summoned);
}
- void SummonedCreatureDespawn(Creature* summoned) override
+ uint32 GetData(uint32 id) const override
{
- if (summoned->GetEntry() == NPC_GRAUF)
- m_uiGraufGUID.Clear();
- Summons.Despawn(summoned);
+ if (id == DATA_LOVE_TO_SKADI)
+ return loveSkadi;
+
+ return 0;
}
- void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override
+ void UpdateAI(uint32 diff) override
{
- if (spell->Id == SPELL_HARPOON_DAMAGE)
+ scheduler.Update(diff);
+
+ if (_phase == PHASE_GROUND)
{
- m_uiSpellHitCount++;
- if (m_uiSpellHitCount >= 3)
- {
- Phase = SKADI;
- me->SetCanFly(false);
- me->Dismount();
- if (Creature* pGrauf = me->SummonCreature(NPC_GRAUF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3*IN_MILLISECONDS))
- {
- pGrauf->GetMotionMaster()->MoveFall();
- pGrauf->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
- }
- me->GetMotionMaster()->MoveJump(Location[4], 5.0f, 10.0f);
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- Talk(SAY_DRAKE_DEATH);
- m_uiCrushTimer = 8000;
- m_uiPoisonedSpearTimer = 10000;
- m_uiWhirlwindTimer = 20000;
- AttackStart(SelectTarget(SELECT_TARGET_RANDOM));
- }
+ if (!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
}
}
- void UpdateAI(uint32 diff) override
+ private:
+ CombatPhase _phase;
+ uint8 harpoonHit;
+ uint8 loveSkadi;
+ bool firstWaveSummoned;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<boss_skadiAI>(creature);
+ }
+};
+
+class npc_grauf : public CreatureScript
+{
+public:
+ npc_grauf() : CreatureScript("npc_grauf") { }
+
+ struct npc_graufAI : public ScriptedAI
+ {
+ npc_graufAI(Creature* creature) : ScriptedAI(creature)
{
- switch (Phase)
- {
- case FLYING:
- if (!UpdateVictim())
- return;
+ _isFirstFly = true;
+ _instance = me->GetInstanceScript();
+ }
- if (me->GetPositionX() >= 519)
- {
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- if (!m_bSaidEmote)
- {
- Talk(EMOTE_RANGE);
- m_bSaidEmote = true;
- }
- }
- else
- {
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
- m_bSaidEmote = false;
- }
+ void Reset() override
+ {
+ me->SetReactState(REACT_PASSIVE);
+ me->setRegeneratingHealth(false);
+ }
- if (m_uiMountTimer && m_uiMountTimer <= diff)
- {
- me->Mount(DATA_MOUNT);
- me->SetCanFly(true);
- m_uiMountTimer = 0;
- } else m_uiMountTimer -= diff;
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
+ skadi->AI()->DoAction(ACTION_GAUNTLET_END);
- if (m_uiSummonTimer <= diff)
- {
- SpawnMobs();
- m_uiSummonTimer = 25000;
- } else m_uiSummonTimer -= diff;
+ me->DespawnOrUnsummon(6000);
+ }
- if (m_uiMovementTimer <= diff)
- {
- switch (m_uiWaypointId)
- {
- case 0:
- me->GetMotionMaster()->MovePoint(0, Location[1].GetPositionX(), Location[1].GetPositionY(), Location[1].GetPositionZ());
- m_uiMovementTimer = 5000;
- break;
- case 1:
- me->GetMotionMaster()->MovePoint(0, Location[2].GetPositionX(), Location[2].GetPositionY(), Location[2].GetPositionZ());
- m_uiMovementTimer = 2000;
- break;
- case 2:
- me->GetMotionMaster()->MovePoint(0, Location[3].GetPositionX(), Location[3].GetPositionY(), Location[3].GetPositionZ());
- m_uiMovementTimer = 15000;
- break;
- case 3:
- me->GetMotionMaster()->MovePoint(0, Location[69].GetPositionX(), Location[69].GetPositionY(), Location[69].GetPositionZ());
- Talk(SAY_DRAKE_BREATH);
- Talk(EMOTE_BREATH);
- m_uiMovementTimer = 2500;
- break;
- case 4:
- me->GetMotionMaster()->MovePoint(0, Location[70].GetPositionX(), Location[70].GetPositionY(), Location[70].GetPositionZ());
- m_uiMovementTimer = 2000;
- SpawnTrigger();
- break;
- case 5:
- me->GetMotionMaster()->MovePoint(0, Location[71].GetPositionX(), Location[71].GetPositionY(), Location[71].GetPositionZ());
- m_uiMovementTimer = 3000;
- break;
- case 6:
- me->GetMotionMaster()->MovePoint(0, Location[3].GetPositionX(), Location[3].GetPositionY(), Location[3].GetPositionZ());
- m_uiWaypointId = 2;
- m_uiMovementTimer = 15000;
- break;
- }
- m_uiWaypointId++;
- } else m_uiMovementTimer -= diff;
- break;
- case SKADI:
- //Return since we have no target
- if (!UpdateVictim())
- return;
+ void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
+ {
+ if (!apply)
+ return;
- if (m_uiCrushTimer <= diff)
- {
- DoCastVictim(SPELL_CRUSH);
- m_uiCrushTimer = 8000;
- } else m_uiCrushTimer -= diff;
+ Movement::MoveSplineInit init(who);
+ init.DisableTransportPathTransformations();
+ init.MoveTo(0.3320355f, 0.05355075f, 5.196949f, false);
+ init.Launch();
- if (m_uiPoisonedSpearTimer <= diff)
- {
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
- DoCast(target, SPELL_POISONED_SPEAR);
- m_uiPoisonedSpearTimer = 10000;
- } else m_uiPoisonedSpearTimer -= diff;
+ me->setActive(true);
+ me->SetCanFly(true);
+ me->SetDisableGravity(true);
+ me->SetByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
- if (m_uiWhirlwindTimer <= diff)
- {
- DoCastAOE(SPELL_WHIRLWIND);
- m_uiWhirlwindTimer = 20000;
- } else m_uiWhirlwindTimer -= diff;
+ _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->GetMotionMaster()->MovePath(GRAUF_PATH_INITIAL, false);
+ });
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != POINT_MOTION_TYPE && type != WAYPOINT_MOTION_TYPE)
+ return;
- DoMeleeAttackIfReady();
+ switch (pointId)
+ {
+ case POINT_9:
+ if (!_isFirstFly)
+ break;
+ _isFirstFly = false;
+ // no break
+ case POINT_11:
+ _scheduler
+ .Schedule(Milliseconds(1), [this](TaskContext /*context*/)
+ {
+ me->SetFacingTo(BreachPoint.GetOrientation());
+ Talk(EMOTE_ON_RANGE);
+ })
+ .Schedule(Seconds(10), [this](TaskContext /*context*/)
+ {
+ if (RAND(POINT_LEFT,POINT_RIGHT) == POINT_LEFT)
+ me->GetMotionMaster()->MovePoint(POINT_LEFT, BreathPointLeft);
+ else
+ me->GetMotionMaster()->MovePoint(POINT_RIGHT, BreathPointRight);
+ });
+ break;
+ case POINT_LEFT:
+ _scheduler
+ .Schedule(Milliseconds(1), [this](TaskContext /*context*/)
+ {
+ me->SetFacingTo(BreathPointLeft.GetOrientation());
+ Talk(EMOTE_BREATH);
+ })
+ .Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->GetMotionMaster()->MovePath(GRAUF_PATH_LEFT, false);
+ DoCast(SPELL_FREEZING_CLOUD_LEFT_PERIODIC);
+ if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
+ skadi->AI()->DoAction(ACTION_FLAME);
+ })
+ .Schedule(Seconds(10), [this](TaskContext /*context*/)
+ {
+ me->RemoveAurasDueToSpell(SPELL_FREEZING_CLOUD_LEFT_PERIODIC);
+ });
+ break;
+ case POINT_RIGHT:
+ _scheduler
+ .Schedule(Milliseconds(1), [this](TaskContext /*context*/)
+ {
+ me->SetFacingTo(BreathPointRight.GetOrientation());
+ Talk(EMOTE_BREATH);
+ })
+ .Schedule(Seconds(2), [this](TaskContext /*context*/)
+ {
+ me->GetMotionMaster()->MovePath(GRAUF_PATH_RIGHT, false);
+ DoCast(SPELL_FREEZING_CLOUD_RIGHT_PERIODIC);
+ if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
+ skadi->AI()->DoAction(ACTION_FLAME);
+ })
+ .Schedule(Seconds(10), [this](TaskContext /*context*/)
+ {
+ me->RemoveAurasDueToSpell(SPELL_FREEZING_CLOUD_RIGHT_PERIODIC);
+ });
break;
+ default:
+ break;
}
}
+ void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override
+ {
+ if (spell->Id == SPELL_LAUNCH_HARPOON)
+ if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
+ skadi->AI()->DoAction(ACTION_HARPOON_HIT);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _scheduler.Update(diff);
+ }
+
+ private:
+ TaskScheduler _scheduler;
+ InstanceScript* _instance;
+ bool _isFirstFly;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_graufAI>(creature);
+ }
+};
+
+struct npc_skadi_trashAI : public ScriptedAI
+{
+ npc_skadi_trashAI(Creature* creature) : ScriptedAI(creature)
+ {
+ _instance = me->GetInstanceScript();
+
+ _scheduler.SetValidator([this]
+ {
+ return !me->HasUnitState(UNIT_STATE_CASTING);
+ });
+ }
+
+ void EnterCombat(Unit* who) override
+ {
+ CreatureAI::EnterCombat(who);
+ ScheduleTasks();
+ }
+
+ void IsSummonedBy(Unit* /*summoner*/) override
+ {
+ if (Creature* skadi = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
+ skadi->AI()->JustSummoned(me);
+ }
+
+ void MovementInform(uint32 type, uint32 pointId) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ switch (pointId)
+ {
+ case POINT_0:
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, me->GetEntry() == NPC_YMIRJAR_WARRIOR ? EMOTE_STATE_READY1H : EMOTE_STATE_READY2HL);
+ break;
+ case POINT_1:
+ _scheduler.Schedule(Seconds(1), [this](TaskContext /*context*/)
+ {
+ me->GetMotionMaster()->MovePoint(POINT_9, SecondaryWavesFinalPoint);
+ });
+ break;
+ case POINT_9:
+ DoZoneInCombat(me, 200);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ UpdateVictim();
+
+ _scheduler.Update(diff, [this]
+ {
+ DoMeleeAttackIfReady();
+ });
+ }
+
+ virtual void ScheduleTasks() = 0;
+
+protected:
+ InstanceScript* _instance;
+ TaskScheduler _scheduler;
+};
+
+class npc_ymirjar_warrior : public CreatureScript
+{
+public:
+ npc_ymirjar_warrior() : CreatureScript("npc_ymirjar_warrior") { }
+
+ struct npc_ymirjar_warriorAI : public npc_skadi_trashAI
+ {
+ npc_ymirjar_warriorAI(Creature* creature) : npc_skadi_trashAI(creature) { }
+
+ void ScheduleTasks() override
+ {
+ _scheduler
+ .Schedule(Seconds(2), [this](TaskContext context)
+ {
+ DoCastVictim(SPELL_HAMSTRING);
+ context.Repeat(Seconds(11), Seconds(18));
+ })
+ .Schedule(Seconds(9), [this](TaskContext context)
+ {
+ DoCastVictim(SPELL_STRIKE);
+ context.Repeat(Seconds(10), Seconds(13));
+ });
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ymirjar_warriorAI>(creature);
+ }
+};
+
+class npc_ymirjar_witch_doctor : public CreatureScript
+{
+public:
+ npc_ymirjar_witch_doctor() : CreatureScript("npc_ymirjar_witch_doctor") { }
+
+ struct npc_ymirjar_witch_doctorAI : public npc_skadi_trashAI
+ {
+ npc_ymirjar_witch_doctorAI(Creature* creature) : npc_skadi_trashAI(creature) { }
+
+ void ScheduleTasks() override
+ {
+ _scheduler
+ .Schedule(Seconds(2), [this](TaskContext shadowBolt)
+ {
+ DoCastVictim(SPELL_SHADOW_BOLT);
+ shadowBolt.Repeat();
+ })
+ .Schedule(Seconds(20), Seconds(34), [this](TaskContext shrink)
+ {
+ DoCastVictim(SPELL_SHRINK);
+ shrink.Repeat();
+ });
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ymirjar_witch_doctorAI>(creature);
+ }
+};
+
+class npc_ymirjar_harpooner : public CreatureScript
+{
+public:
+ npc_ymirjar_harpooner() : CreatureScript("npc_ymirjar_harpooner") { }
+
+ struct npc_ymirjar_harpoonerAI : public npc_skadi_trashAI
+ {
+ npc_ymirjar_harpoonerAI(Creature* creature) : npc_skadi_trashAI(creature) { }
+
+ void ScheduleTasks() override
+ {
+ _scheduler
+ .Schedule(Seconds(13), [this](TaskContext net)
+ {
+ if (Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0, 30, true))
+ DoCast(target, SPELL_NET);
+ net.Repeat();
+ })
+ .Schedule(Seconds(2), [this](TaskContext castThrow)
+ {
+ DoCastVictim(SPELL_THROW);
+ castThrow.Repeat();
+ });
+ }
+
void JustDied(Unit* /*killer*/) override
{
- Talk(SAY_DEATH);
- Summons.DespawnAll();
- instance->SetBossState(DATA_SKADI_THE_RUTHLESS, DONE);
+ DoCast(SPELL_SUMMON_HARPOON);
}
+ };
- void KilledUnit(Unit* who) override
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI<npc_ymirjar_harpoonerAI>(creature);
+ }
+};
+
+class spell_freezing_cloud_area_right : public SpellScriptLoader
+{
+public:
+ spell_freezing_cloud_area_right() : SpellScriptLoader("spell_freezing_cloud_area_right") { }
+
+ class spell_freezing_cloud_area_right_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_freezing_cloud_area_right_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
{
- if (who->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_KILL);
+ if (!sSpellMgr->GetSpellInfo(SPELL_FREEZING_CLOUD))
+ return false;
+ return true;
+ }
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if([](WorldObject* obj) { return obj->GetPositionY() > -511.0f; });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZING_CLOUD, true);
}
- void SpawnMobs()
+ void Register() override
{
- for (uint8 i = 0; i < DUNGEON_MODE(5, 6); ++i)
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_freezing_cloud_area_right_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_freezing_cloud_area_right_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_freezing_cloud_area_right_SpellScript();
+ }
+};
+
+class spell_freezing_cloud_area_left : public SpellScriptLoader
+{
+public:
+ spell_freezing_cloud_area_left() : SpellScriptLoader("spell_freezing_cloud_area_left") { }
+
+ class spell_freezing_cloud_area_left_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_freezing_cloud_area_left_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_FREEZING_CLOUD))
+ return false;
+ return true;
+ }
+
+ void FilterTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if([](WorldObject* obj) { return obj->GetPositionY() < -511.0f; });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZING_CLOUD, true);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_freezing_cloud_area_left_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_freezing_cloud_area_left_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_freezing_cloud_area_left_SpellScript();
+ }
+};
+
+class spell_freezing_cloud_damage : public SpellScriptLoader
+{
+ public:
+ spell_freezing_cloud_damage() : SpellScriptLoader("spell_freezing_cloud_damage") { }
+
+ class spell_freezing_cloud_damage_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_freezing_cloud_damage_AuraScript);
+
+ bool CanBeAppliedOn(Unit* target)
{
- switch (urand(0, 2))
- {
- case 0:
- me->SummonCreature(NPC_YMIRJAR_WARRIOR, SpawnLoc.GetPositionX() + rand32() % 5, SpawnLoc.GetPositionY() + rand32() % 5, SpawnLoc.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
- break;
+ if (Aura* aur = target->GetAura(GetId()))
+ if (aur->GetOwner() != GetOwner())
+ return false;
- case 1:
- me->SummonCreature(NPC_YMIRJAR_WITCH_DOCTOR, SpawnLoc.GetPositionX() + rand32() % 5, SpawnLoc.GetPositionY() + rand32() % 5, SpawnLoc.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
- break;
+ return true;
+ }
- case 2:
- me->SummonCreature(NPC_YMIRJAR_HARPOONER, SpawnLoc.GetPositionX() + rand32() % 5, SpawnLoc.GetPositionY() + rand32() % 5, SpawnLoc.GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
- break;
- }
+ void Register() override
+ {
+ DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_freezing_cloud_damage_AuraScript::CanBeAppliedOn);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_freezing_cloud_damage_AuraScript();
+ }
+};
+
+class spell_skadi_reset_check : public SpellScriptLoader
+{
+ public:
+ spell_skadi_reset_check() : SpellScriptLoader("spell_skadi_reset_check") { }
+
+ class spell_skadi_reset_check_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_skadi_reset_check_SpellScript);
+
+ void CountTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if(Trinity::UnitAuraCheck(false, SPELL_UTGARDE_PINNACLE_GAUNTLET_EFFECT));
+ _targetCount = targets.size();
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (_targetCount)
+ return;
+
+ Creature* target = GetHitCreature();
+ if (!target)
+ return;
+
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (instance->GetBossState(DATA_SKADI_THE_RUTHLESS) == IN_PROGRESS)
+ target->AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skadi_reset_check_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_skadi_reset_check_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY);
}
+
+ private:
+ uint32 _targetCount = 0;
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_skadi_reset_check_SpellScript();
}
+};
- void SpawnTrigger()
+class spell_skadi_launch_harpoon : public SpellScriptLoader
+{
+ public:
+ spell_skadi_launch_harpoon() : SpellScriptLoader("spell_skadi_launch_harpoon") { }
+
+ class spell_skadi_launch_harpoon_SpellScript : public SpellScript
{
- uint8 iStart = 0, iEnd = 0;
- switch (urand(0, 1))
+ PrepareSpellScript(spell_skadi_launch_harpoon_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& targets)
{
- case 0:
- iStart = 8;
- iEnd = 37;
- break;
- case 1:
- iStart = 38;
- iEnd = 68;
- break;
- default:
- break;
+ if (targets.size() >= 2)
+ targets.remove_if([](WorldObject* obj) { return obj->GetEntry() != NPC_GRAUF; });
}
- for (uint32 i = iStart; i < iEnd; ++i)
- me->SummonCreature(NPC_TRIGGER, Location[i]);
+
+ void HandleDamageCalc()
+ {
+ if (Unit* target = GetHitUnit())
+ SetHitDamage(target->CountPctFromMaxHealth(35));
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skadi_launch_harpoon_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CONE_ENTRY);
+ OnHit += SpellHitFn(spell_skadi_launch_harpoon_SpellScript::HandleDamageCalc);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_skadi_launch_harpoon_SpellScript();
}
- };
+};
+
+class spell_skadi_poisoned_spear : public SpellScriptLoader
+{
+ public:
+ spell_skadi_poisoned_spear() : SpellScriptLoader("spell_skadi_poisoned_spear") { }
+
+ class spell_skadi_poisoned_spear_left_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_skadi_poisoned_spear_left_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_POISONED_SPEAR_PERIODIC))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_POISONED_SPEAR_PERIODIC, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_skadi_poisoned_spear_left_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_skadi_poisoned_spear_left_SpellScript();
+ }
+};
+
+class spell_summon_gauntlet_mobs_periodic : public SpellScriptLoader
+{
+ public:
+ spell_summon_gauntlet_mobs_periodic() : SpellScriptLoader("spell_summon_gauntlet_mobs_periodic") { }
+
+ class spell_summon_gauntlet_mobs_periodic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_summon_gauntlet_mobs_periodic_AuraScript);
+
+ void CastTheNextTwoSpells()
+ {
+ for (uint8 i = 0; i < 2; ++i)
+ {
+ uint32 spellId = SummonSpellsList.front();
+ GetTarget()->CastSpell((Unit*)nullptr, spellId, true);
+ SummonSpellsList.push_back(spellId);
+ SummonSpellsList.pop_front();
+ }
+ }
+ void PushBackTheNextTwoSpells()
+ {
+ for (uint8 j = 0; j < 2; ++j)
+ {
+ SummonSpellsList.push_back(SummonSpellsList.front());
+ SummonSpellsList.pop_front();
+ }
+ }
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (RAND(0, 1))
+ {
+ CastTheNextTwoSpells();
+ PushBackTheNextTwoSpells();
+ }
+ else
+ {
+ PushBackTheNextTwoSpells();
+ CastTheNextTwoSpells();
+ }
+ }
+ private:
+ std::deque<uint32> SummonSpellsList =
+ {
+ SPELL_SUMMON_YMIRJAR_WARRIOR_E,
+ SPELL_SUMMON_YMIRJAR_HARPOONER_W,
+ SPELL_SUMMON_YMIRJAR_WARRIOR_W,
+ SPELL_SUMMON_YMIRJAR_HARPOONER_E,
+ SPELL_SUMMON_YMIRJAR_WARRIOR_W,
+ SPELL_SUMMON_YMIRJAR_WITCH_DOCTOR_E,
+ SPELL_SUMMON_YMIRJAR_WARRIOR_E,
+ SPELL_SUMMON_YMIRJAR_WITCH_DOCTOR_W
+ };
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_summon_gauntlet_mobs_periodic_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_summon_gauntlet_mobs_periodic_AuraScript();
+ }
};
-class go_harpoon_launcher : public GameObjectScript
+class achievement_girl_love_to_skadi : public AchievementCriteriaScript
{
public:
- go_harpoon_launcher() : GameObjectScript("go_harpoon_launcher") { }
+ achievement_girl_love_to_skadi() : AchievementCriteriaScript("achievement_girl_love_to_skadi") { }
- bool OnGossipHello(Player* player, GameObject* go) override
+ bool OnCheck(Player* /*player*/, Unit* target) override
{
- InstanceScript* instance = go->GetInstanceScript();
- if (!instance)
+ if (!target)
return false;
- if (Creature* pSkadi = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
- player->CastSpell(pSkadi, SPELL_RAPID_FIRE, true);
+ if (Creature* skadi = target->ToCreature())
+ if (skadi->AI()->GetData(DATA_LOVE_TO_SKADI) == 1)
+ return true;
return false;
}
+};
+
+class at_skadi_gaunlet : public AreaTriggerScript
+{
+ public:
+ at_skadi_gaunlet() : AreaTriggerScript("at_skadi_gaunlet") { }
+ bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ {
+ if (instance->GetBossState(DATA_SKADI_THE_RUTHLESS) == NOT_STARTED)
+ if (Creature* skadi = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SKADI_THE_RUTHLESS)))
+ {
+ skadi->AI()->DoAction(ACTION_START_ENCOUNTER);
+ return true;
+ }
+ }
+
+ return true;
+ }
};
void AddSC_boss_skadi()
{
new boss_skadi();
- new go_harpoon_launcher();
+ new npc_grauf();
+ new npc_ymirjar_warrior();
+ new npc_ymirjar_witch_doctor();
+ new npc_ymirjar_harpooner();
+ new spell_freezing_cloud_area_left();
+ new spell_freezing_cloud_area_right();
+ new spell_freezing_cloud_damage();
+ new spell_skadi_reset_check();
+ new spell_skadi_launch_harpoon();
+ new spell_skadi_poisoned_spear();
+ new spell_summon_gauntlet_mobs_periodic();
+ new achievement_girl_love_to_skadi();
+ new at_skadi_gaunlet();
}
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp
index 28ca7f4ef3b..23778b4db5d 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp
@@ -80,6 +80,9 @@ class instance_utgarde_pinnacle : public InstanceMapScript
case NPC_PALEHOOF_ORB:
PalehoofOrbGUID = creature->GetGUID();
break;
+ case NPC_GRAUF:
+ GraufGUID = creature->GetGUID();
+ break;
default:
break;
}
@@ -164,6 +167,8 @@ class instance_utgarde_pinnacle : public InstanceMapScript
return SvalaGUID;
case DATA_SACRIFICED_PLAYER:
return SacrificedPlayerGUID;
+ case DATA_GRAUF:
+ return GraufGUID;
default:
break;
}
@@ -189,6 +194,8 @@ class instance_utgarde_pinnacle : public InstanceMapScript
ObjectGuid SvalaGUID;
ObjectGuid SacrificedPlayerGUID;
+
+ ObjectGuid GraufGUID;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h
index 2265bc03b03..b02792745f7 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h
@@ -41,7 +41,8 @@ enum DataTypes
DATA_MASSIVE_JORMUNGAR = 9,
DATA_FEROCIOUS_RHINO = 10,
DATA_GORTOK_ORB = 11,
- DATA_GORTOK_PALEHOOF_SPHERE = 12
+ DATA_GORTOK_PALEHOOF_SPHERE = 12,
+ DATA_GRAUF = 13
};
enum CreatureIds
@@ -61,6 +62,16 @@ enum CreatureIds
NPC_FEROCIOUS_RHINO = 26686,
NPC_PALEHOOF_ORB = 26688,
+ // Skadi
+ NPC_GRAUF = 26893,
+ NPC_YMIRJAR_WARRIOR = 26690,
+ NPC_YMIRJAR_WITCH_DOCTOR = 26691,
+ NPC_YMIRJAR_HARPOONER = 26692,
+ NPC_TRIGGER_RESET = 23472,
+ NPC_TRIGGER2 = 19871,
+ NPC_WORLD_TRIGGER = 22515,
+ NPC_COMBAT_TRIGGER = 38667,
+
// Ymiron
NPC_BJORN = 27303,
NPC_BJORN_VISUAL = 27304,