From eef2222171caf4fbd07e8fdd9735a93884fea273 Mon Sep 17 00:00:00 2001 From: AlterEgo Date: Sat, 15 Aug 2026 10:23:00 -0500 Subject: [PATCH] Port Gilneas zone scripts and support data Adds Gilneas quest, creature, vehicle, spellclick, creature text, and stagecoach support for local testing. --- .../2026_08_15_world_gilneas_support.sql | 200 + .../EasternKingdoms/Gilneas/gilneas.cpp | 4066 +++++++++++++---- 2 files changed, 3284 insertions(+), 982 deletions(-) create mode 100644 sql/pending_updates/world/2026_08_15_world_gilneas_support.sql diff --git a/sql/pending_updates/world/2026_08_15_world_gilneas_support.sql b/sql/pending_updates/world/2026_08_15_world_gilneas_support.sql new file mode 100644 index 0000000000..6aea435d86 --- /dev/null +++ b/sql/pending_updates/world/2026_08_15_world_gilneas_support.sql @@ -0,0 +1,200 @@ +-- Gilneas zone script and database support. + +DELETE FROM `smart_scripts` +WHERE (`source_type` = 0 AND `entryorguid` IN (34884, 35077, 35378, 35463, 35550, 35631, 35905, 35907, 36459, 36540, 36555, 43336, 44928, 50260)) + OR (`source_type` = 9 AND `entryorguid` IN (3488400, 3507700, 3537800, 3546300, 3555000, 3563100, 3590500, 3590700, 3645900, 3654000, 3655500, 4333600, 4492800, 5026000)); + +UPDATE `creature_template` SET `npcflag` = 3, `unit_flags` = 33280, `unit_flags2` = 2048, `flags_extra` = 2, `AIName` = '', `ScriptName` = 'npc_prince_liam_greymane' WHERE `entry` = 34850; +UPDATE `creature_template` SET `npcflag` = 0, `unit_flags` = 32768, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_gilneas_city_guard_gate' WHERE `entry` = 34864; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_rampaging_worgen' WHERE `entry` = 34884; +UPDATE `creature_template` SET `npcflag` = 2, `AIName` = '', `ScriptName` = 'npc_lord_darius_crowley_35077' WHERE `entry` = 35077; +UPDATE `creature_template` SET `npcflag` = 2, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 35112; +UPDATE `creature_template` SET `npcflag` = 2, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 35115; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 35118; +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 35124; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `flags_extra` = 64, `AIName` = '', `ScriptName` = 'npc_worgen_alpha_35167' WHERE `entry` = 35167; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `flags_extra` = 64, `AIName` = '', `ScriptName` = 'npc_worgen_alpha_35170' WHERE `entry` = 35170; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `flags_extra` = 64, `AIName` = '', `ScriptName` = 'npc_worgen_runt_35188' WHERE `entry` = 35188; +UPDATE `creature_template` SET `npcflag` = 2, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_josiah_avery' WHERE `entry` = 35369; +UPDATE `creature_template` SET `npcflag` = 0, `unit_flags` = 33024, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_josiah_avery_worgen_form' WHERE `entry` = 35370; +UPDATE `creature_template` SET `npcflag` = 2, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_lorna_crowley_basement' WHERE `entry` = 35378; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `flags_extra` = 64, `AIName` = '', `ScriptName` = 'npc_worgen_runt' WHERE `entry` = 35456; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 8599, `unit_flags` = 32768, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_bloodfang_lurker' WHERE `entry` = 35463; +UPDATE `creature_template` SET `npcflag` = 3, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_king_genn_greymane' WHERE `entry` = 35550; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 67805, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_gilnean_mastiff' WHERE `entry` = 35631; +UPDATE `creature_template` SET `npcflag` = 0, `InhabitType` = 4, `AIName` = '', `ScriptName` = '' WHERE `entry` = 35753; +UPDATE `creature_template` SET `npcflag` = 16777216, `spell1` = 68219, `VehicleId` = 494, `unit_flags` = 33536, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_vehicle_genn_horse' WHERE `entry` = 35905; +UPDATE `creature_template` SET `npcflag` = 0, `unit_flags` = 33280, `unit_flags2` = 2080, `AIName` = '', `ScriptName` = 'npc_saved_aranas' WHERE `entry` = 35907; +UPDATE `creature_template` SET `npcflag` = 16777216, `AIName` = '', `ScriptName` = 'npc_cynthia' WHERE `entry` = 36287; +UPDATE `creature_template` SET `npcflag` = 16777216, `AIName` = '', `ScriptName` = 'npc_ashley' WHERE `entry` = 36288; +UPDATE `creature_template` SET `npcflag` = 16777216, `AIName` = '', `ScriptName` = 'npc_james' WHERE `entry` = 36289; +UPDATE `creature_template` SET `npcflag` = 2, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_wahl' WHERE `entry` = 36458; +UPDATE `creature_template` SET `npcflag` = 16777216, `AIName` = '', `ScriptName` = 'npc_chance_the_cat' WHERE `entry` = 36459; +UPDATE `creature_template` SET `npcflag` = 0, `spell1` = 41440, `unit_flags` = 33280, `unit_flags2` = 2048, `AIName` = '', `ScriptName` = 'npc_lucius_the_cruel' WHERE `entry` = 36461; +UPDATE `creature_template` SET `npcflag` = 1, `spell1` = 68903, `VehicleId` = 527, `AIName` = '', `ScriptName` = 'npc_mountain_horse' WHERE `entry` = 36540; +UPDATE `creature_template` SET `speed_walk` = 1, `speed_run` = 1.71429, `AIName` = '', `ScriptName` = 'npc_mountain_horse_summoned' WHERE `entry` = 36555; +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` IN (36452, 36606, 38765); +UPDATE `creature_template` SET `VehicleId` = 958, `unit_flags2` = 268437504, `AIName` = '', `ScriptName` = 'npc_stagecoach_harness' WHERE `entry` = 43336; +UPDATE `creature_template` SET `npcflag` = 1, `VehicleId` = 959, `AIName` = '', `ScriptName` = 'npc_stagecoach_carriage_exodus' WHERE `entry` = 44928; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_gilneas_crow' WHERE `entry` = 50260; + +DELETE FROM `smart_scripts` +WHERE (`source_type` = 0 AND `entryorguid` IN (35112, 35118, 36452, 36606, 38765)) + OR (`source_type` = 9 AND `entryorguid` IN (3511200)); + +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`, `event_param5`, `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 +(35112, 0, 0, 0, 19, 0, 100, 0, 14157, 0, 0, 0, 0, 80, 3511200, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'King Genn Greymane - On Quest Accept - Start Script'), +(35118, 0, 0, 1, 2, 0, 100, 0, 0, 30, 0, 0, 0, 11, 8599, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - At 30% HP - Cast Enrage'), +(35118, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - At 30% HP - Say Text Line 0'), +(35118, 0, 2, 0, 8, 0, 100, 0, 100, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Charge - Give Quest Credit'), +(35118, 0, 3, 0, 8, 0, 100, 0, 56641, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Steady Shot - Give Quest Credit'), +(35118, 0, 4, 0, 8, 0, 100, 0, 2098, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Eviscerate - Give Quest Credit'), +(35118, 0, 5, 0, 8, 0, 100, 0, 122, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Frost Nova - Give Quest Credit'), +(35118, 0, 6, 0, 8, 0, 100, 0, 172, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Corruption - Give Quest Credit'), +(35118, 0, 7, 0, 8, 0, 100, 0, 589, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Shadow Word: Pain - Give Quest Credit'), +(35118, 0, 8, 0, 8, 0, 100, 0, 8921, 0, 0, 0, 0, 33, 44175, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Spellhit - Moonfire - Give Quest Credit'), +(35118, 0, 9, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 35232, 35, 0, 0, 0, 0, 0, 'Bloodfang Worgen - On Reset - Attack Gilneas City Guard'), +(35118, 0, 10, 0, 1, 0, 100, 0, 10000, 10000, 10000, 10000, 0, 49, 0, 0, 0, 0, 0, 0, 19, 35232, 35, 0, 0, 0, 0, 0, 'Bloodfang Worgen - Out of Combat - Attack Gilneas City Guard'), +(36452, 0, 0, 0, 19, 0, 100, 0, 14465, 0, 0, 0, 0, 85, 72772, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Gwen Armstead - On Quest Accept - Summon Horse'), +(36606, 0, 0, 0, 20, 0, 100, 0, 14465, 0, 0, 0, 0, 85, 68709, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 'Queen Mia Greymane - On Quest Rewarded - Cataclysm'), +(38765, 0, 0, 0, 27, 0, 100, 0, 0, 0, 0, 0, 0, 53, 1, 38765, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Stout Mountain Horse - On Passenger Boarded - Start Waypoint'), +(38765, 0, 1, 0, 40, 0, 100, 0, 15, 0, 0, 0, 0, 28, 46598, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Stout Mountain Horse - On Waypoint 15 - Remove Passenger'), +(38765, 0, 2, 0, 40, 0, 100, 0, 3, 0, 0, 0, 0, 54, 1000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Stout Mountain Horse - On Waypoint 3 - Pause'), +(38765, 0, 3, 0, 40, 0, 100, 0, 3, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 14, 166783, 196863, 0, 0, 0, 0, 0, 'Stout Mountain Horse - On Waypoint 3 - Open Gate'), +(38765, 0, 5, 0, 40, 0, 100, 0, 13, 0, 0, 0, 0, 54, 1000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Stout Mountain Horse - On Waypoint 13 - Pause'), +(38765, 0, 6, 0, 40, 0, 100, 0, 13, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 14, 166784, 196864, 0, 0, 0, 0, 0, 'Stout Mountain Horse - On Waypoint 13 - Open Gate'), +(3511200, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'King Genn Greymane - Remove Questgiver Flag'), +(3511200, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 35115, 30, 0, 0, 0, 0, 0, 'King Genn Greymane - Lord Godfrey Says Text Line 0'), +(3511200, 9, 2, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'King Genn Greymane - Say Text Line 0'), +(3511200, 9, 3, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 81, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'King Genn Greymane - Restore Questgiver Flag'); + +UPDATE `quest_template` SET `Flags` = 0 WHERE `Id` = 14204; +UPDATE `quest_template` SET `Flags` = 8 WHERE `Id` = 14465; + +DELETE FROM `spell_script_names` +WHERE `spell_id` IN (66853, 66914, 67357, 67805, 69257) + OR `ScriptName` IN ('spell_gen_gilneas_prison_periodic_dummy', 'spell_gilneas_prison_periodic_dummy', 'spell_gilneas_pull_to', 'spell_attack_lurker', 'spell_gilneas_test_telescope'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(66853, 'spell_gen_gilneas_prison_periodic_dummy'), +(66914, 'spell_gilneas_prison_periodic_dummy'), +(67357, 'spell_gilneas_pull_to'), +(67805, 'spell_attack_lurker'), +(69257, 'spell_gilneas_test_telescope'); + +DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (35905, 36459, 36540, 43336, 44928); +INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES +(35905, 63151, 1, 0), +(36459, 68743, 1, 0), +(43336, 46598, 0, 0), +(44928, 46598, 0, 0); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceGroup` = 1 AND `SourceEntry` = 93275; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 1, 93275, 0, 0, 31, 0, 3, 50260, 0, 0, 0, 0, '', 'Ping Gilnean Crow - Target Gilnean Crow'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 18 AND `SourceGroup` = 36459 AND `SourceEntry` = 68743; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(18, 36459, 68743, 0, 0, 9, 0, 14401, 0, 0, 0, 0, 0, '', 'Requires Grandma''s Cat to enable spellclick'); + +DELETE FROM `vehicle_template_accessory` WHERE `entry` IN (43336, 44928); +INSERT INTO `vehicle_template_accessory` (`entry`, `accessory_entry`, `seat_id`, `minion`, `description`, `summontype`, `summontimer`) VALUES +(43336, 43338, 0, 1, 'Stagecoach Harness - Horse', 8, 0), +(43336, 43338, 1, 1, 'Stagecoach Harness - Horse', 8, 0), +(43336, 44928, 2, 1, 'Stagecoach Harness - Caravan', 8, 0), +(44928, 38853, 0, 1, 'Stagecoach Carriage', 8, 0), +(44928, 44460, 2, 1, 'Stagecoach Carriage', 8, 0), +(44928, 36138, 3, 1, 'Stagecoach Carriage', 8, 0), +(44928, 43907, 4, 1, 'Stagecoach Carriage', 8, 0), +(44928, 43907, 5, 1, 'Stagecoach Carriage', 8, 0), +(44928, 51409, 6, 1, 'Stagecoach Carriage', 8, 0); + +DELETE FROM `script_waypoint` WHERE `entry` = 43336; +INSERT INTO `script_waypoint` (`entry`, `pointid`, `location_x`, `location_y`, `location_z`, `waittime`, `point_comment`) VALUES +(43336, 1, -1681.45, 2508.27, 97.84, 0, 'Stagecoach Harness'), +(43336, 2, -1695.46, 2486.82, 92.64, 0, 'Stagecoach Harness'), +(43336, 3, -1704.99, 2468.26, 84.84, 0, 'Stagecoach Harness'), +(43336, 4, -1698.38, 2447.65, 80.77, 0, 'Stagecoach Harness'), +(43336, 5, -1698.42, 2432.73, 76.52, 0, 'Stagecoach Harness'), +(43336, 6, -1725.88, 2390.50, 60.80, 0, 'Stagecoach Harness'), +(43336, 7, -1735.64, 2362.27, 63.15, 0, 'Stagecoach Harness'), +(43336, 8, -1745.18, 2343.69, 67.34, 0, 'Stagecoach Harness'), +(43336, 9, -1746.53, 2329.92, 69.60, 0, 'Stagecoach Harness'), +(43336, 10, -1757.21, 2300.38, 75.77, 0, 'Stagecoach Harness'), +(43336, 11, -1776.38, 2271.80, 82.11, 0, 'Stagecoach Harness'), +(43336, 12, -1799.38, 2251.48, 87.64, 0, 'Stagecoach Harness'), +(43336, 13, -1826.19, 2238.05, 89.31, 0, 'Stagecoach Harness'), +(43336, 14, -1868.50, 2174.60, 89.31, 0, 'Stagecoach Harness'), +(43336, 15, -1872.45, 2135.71, 89.31, 0, 'Stagecoach Harness'), +(43336, 16, -1872.96, 2075.18, 89.31, 0, 'Stagecoach Harness'), +(43336, 17, -1881.14, 2046.58, 89.31, 0, 'Stagecoach Harness'), +(43336, 18, -1885.72, 2019.56, 89.31, 0, 'Stagecoach Harness'), +(43336, 19, -1876.85, 1970.16, 89.17, 0, 'Stagecoach Harness'), +(43336, 20, -1878.35, 1921.33, 89.13, 0, 'Stagecoach Harness'), +(43336, 21, -1890.52, 1904.26, 89.15, 0, 'Stagecoach Harness'), +(43336, 22, -1990.23, 1901.42, 89.28, 0, 'Stagecoach Harness'), +(43336, 23, -2036.81, 1914.56, 83.23, 0, 'Stagecoach Harness'), +(43336, 24, -2061.07, 1905.41, 73.95, 0, 'Stagecoach Harness'), +(43336, 25, -2093.23, 1881.99, 53.77, 0, 'Stagecoach Harness'), +(43336, 26, -2103.06, 1870.42, 46.52, 0, 'Stagecoach Harness'), +(43336, 27, -2122.61, 1831.95, 29.18, 0, 'Stagecoach Harness'), +(43336, 28, -2146.32, 1814.97, 19.03, 0, 'Stagecoach Harness'), +(43336, 29, -2186.33, 1808.11, 12.11, 0, 'Stagecoach Harness'), +(43336, 30, -2217.77, 1809.60, 11.78, 0, 'Stagecoach Harness'), +(43336, 31, -2239.38, 1805.10, 11.94, 0, 'Stagecoach Harness'), +(43336, 32, -2310.30, 1774.33, 11.05, 0, 'Stagecoach Harness'), +(43336, 33, -2376.50, 1704.52, 11.15, 0, 'Stagecoach Harness'); + +DELETE FROM `waypoints` WHERE `entry` = 38765; +INSERT INTO `waypoints` (`entry`, `pointid`, `position_x`, `position_y`, `position_z`, `point_comment`) VALUES +(38765, 1, -1870.36, 2282.73, 42.32, 'Stout Mountain Horse'), +(38765, 2, -1852.05, 2302.51, 41.83, 'Stout Mountain Horse'), +(38765, 3, -1829.29, 2323.74, 37.55, 'Stout Mountain Horse'), +(38765, 4, -1818.32, 2332.80, 36.37, 'Stout Mountain Horse'), +(38765, 5, -1801.58, 2344.71, 35.77, 'Stout Mountain Horse'), +(38765, 6, -1792.48, 2352.44, 36.52, 'Stout Mountain Horse'), +(38765, 7, -1787.74, 2359.60, 38.00, 'Stout Mountain Horse'), +(38765, 8, -1781.81, 2383.18, 43.27, 'Stout Mountain Horse'), +(38765, 9, -1777.55, 2423.56, 55.68, 'Stout Mountain Horse'), +(38765, 10, -1770.01, 2447.47, 62.25, 'Stout Mountain Horse'), +(38765, 11, -1754.47, 2464.13, 69.36, 'Stout Mountain Horse'), +(38765, 12, -1710.82, 2466.15, 82.81, 'Stout Mountain Horse'), +(38765, 13, -1691.46, 2493.66, 95.20, 'Stout Mountain Horse'), +(38765, 14, -1682.62, 2507.22, 97.79, 'Stout Mountain Horse'), +(38765, 15, -1669.61, 2519.56, 97.89, 'Stout Mountain Horse'); + +DELETE FROM `creature_template_addon` WHERE `entry` IN (35753, 50260); +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(35753, 0, 0, 0, 1, 0, '78037'), +(50260, 0, 0, 50331649, 1, 0, NULL); + +DELETE FROM `creature_text` WHERE `entry` IN (34850, 34864, 34884, 35112, 35115, 35118, 35369, 35378, 35550, 35753, 35905, 35907, 36287, 36288, 36289, 36458, 36461, 51409); +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`) VALUES +(34850, 0, 0, 'Stand ready, guards! We don''t know how many intruders we''re dealing with, but the Headlands are overrun and we''re cut off from the harbor towns. Expect to be outnumbered.', 12, 0, 100, 1, 0, 19614, 'Prince Liam Greymane - Say 0'), +(34850, 1, 0, 'I want the perimeter secured and the gates manned by two guards at all times. No one gets in, no one gets out.', 12, 0, 100, 1, 0, 19615, 'Prince Liam Greymane - Say 1'), +(34850, 2, 0, 'We protected Gilneas from the Scourge. We protected Gilneas during the Northgate rebellion. We will protect Gilneas from whatever this new threat may be.', 12, 0, 100, 25, 0, 19616, 'Prince Liam Greymane - Say 2'), +(34864, 0, 0, 'No one''s allowed to leave. Prince Liam''s orders.', 12, 0, 100, 1, 0, 0, 'Gilneas City Guard'), +(34864, 0, 1, 'It isn''t safe to leave, there''s something lurking out there in the woods.', 12, 0, 100, 1, 0, 0, 'Gilneas City Guard'), +(34864, 0, 2, 'Stay calm. We have everything under control.', 12, 0, 100, 25, 0, 0, 'Gilneas City Guard'), +(34884, 0, 0, '%s becomes enraged!', 16, 0, 100, 0, 0, 0, 'Rampaging Worgen'), +(35112, 0, 0, 'Enough! I''ve made up my mind. We need Crowley on our side.', 12, 0, 100, 0, 0, 0, 'King Genn Greymane to Player'), +(35115, 0, 0, 'We ought to leave Crowley in prison with those beasts!', 12, 0, 100, 0, 0, 0, 'Lord Godfrey to Player'), +(35118, 0, 0, '%s becomes enraged!', 16, 0, 100, 0, 0, 0, 'Bloodfang Worgen'), +(35369, 0, 0, 'What''s wrong with me??!', 14, 0, 100, 0, 0, 0, 'Josiah Avery'), +(35369, 1, 0, 'My face! What''s wrong with my face!', 14, 0, 100, 0, 0, 0, 'Josiah Avery'), +(35369, 2, 0, 'My hands... don''t look at my hands!', 14, 0, 100, 0, 0, 0, 'Josiah Avery'), +(35369, 3, 0, 'The pain is unbearable!', 14, 0, 100, 0, 0, 0, 'Josiah Avery'), +(35369, 4, 0, 'Make it stop!', 14, 0, 100, 0, 0, 0, 'Josiah Avery'), +(35369, 5, 0, 'I can''t fight it!', 14, 0, 100, 0, 0, 0, 'Josiah Avery'), +(35378, 0, 0, 'This mastiff will help you find the hidden worgen.', 12, 0, 100, 0, 0, 19696, 'Lorna Crowley to Player'), +(35550, 0, 0, 'Keep them back!', 14, 0, 100, 0, 0, 19712, 'King Genn Greymane'), +(35550, 0, 1, 'Fire!', 14, 0, 100, 0, 0, 19710, 'King Genn Greymane'), +(35550, 0, 2, 'Hold the barricades! Do not give them an inch!', 14, 0, 100, 0, 0, 19709, 'King Genn Greymane'), +(35753, 0, 0, 'Help! Up here!', 14, 0, 100, 0, 0, 0, 'Krennan Aranas to Player'), +(35905, 0, 0, 'Rescue Krennan Aranas by using your vehicle''s ability.$B|TInterface\\Icons\\inv_misc_groupneedmore.blp:64|t', 42, 0, 100, 0, 0, 0, 'King Greymane''s Horse to Player'), +(35907, 0, 0, 'Thank you! I owe you my life.', 12, 0, 100, 0, 0, 20922, 'Krennan Aranas to King Greymane''s Horse'), +(36287, 0, 0, 'You are scary! I just want my mommy!', 12, 0, 100, 0, 0, 0, 'Cynthia to Player'), +(36288, 0, 0, 'Are you one of the good worgen, $g mister:ma''am;? Did you see Cynthia hiding in the sheds outside?', 12, 0, 100, 0, 0, 0, 'Ashley to Player'), +(36289, 0, 0, 'Don''t hurt me! I was just looking for my sisters! I think Ashley''s inside that house!', 12, 0, 100, 0, 0, 0, 'James to Player'), +(36458, 0, 0, 'You do not mess with my kitty you son of a mongrel!', 14, 0, 100, 0, 0, 0, 'Grandma Wahl to Lucius the Cruel'), +(36461, 0, 0, 'I''ll be taking this cat. It seems to work as the perfect bait. Prepare to die now, fool!', 12, 0, 100, 16, 0, 0, 'Lucius the Cruel to Player'), +(51409, 0, 0, 'Look out! We''re under attack!', 14, 0, 100, 0, 0, 0, 'Lorna Crowley to Stagecoach Carriage'); diff --git a/src/server/scripts/EasternKingdoms/Gilneas/gilneas.cpp b/src/server/scripts/EasternKingdoms/Gilneas/gilneas.cpp index 4ae614f97b..9adf1e7bdb 100644 --- a/src/server/scripts/EasternKingdoms/Gilneas/gilneas.cpp +++ b/src/server/scripts/EasternKingdoms/Gilneas/gilneas.cpp @@ -5,1157 +5,3259 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "GameObjectAI.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" +#include "ScriptedEscortAI.h" +#include "PassiveAI.h" +#include "Vehicle.h" +#include "DBCStores.h" +#include "EventProcessor.h" #include "ObjectAccessor.h" #include "Player.h" #include "SharedDefines.h" -#include "TemporarySummon.h" +#include "SpellMgr.h" +#include "SpellScript.h" #include "Util.h" -#include +#include +#include -enum GilneasMerchantSquare -{ - NPC_FRIGHTENED_CITIZEN = 35836, - NPC_RAMPAGING_WORGEN = 34884, - NPC_MARKET_HOMES_EVACUATED = 35830, - - EVENT_SUMMON_TTL = 300000, - EVENT_CITIZEN_TTL = 6000, - EVENT_WORGEN_DELAY = 2500, - EVENT_DOOR_TIMER = 8000, -}; - -// Centroid of every Merchant Square Door spawn (gameobject entry 195327) - a -// real, open plaza point every citizen can reliably path to, regardless of -// which door they came out of. -float const MerchantSquareCenterX = -1507.74f; -float const MerchantSquareCenterY = 1381.43f; -float const MerchantSquareCenterZ = 36.58f; - -char const* const FrightenedCitizenShouts[] = -{ - "Flee! They're everywhere!", - "It's coming right for me!", - "Protect me, please!", - "This place isn't safe. Let's leave!", - "Worgen! Worgen everywhere!", -}; - -/*###### -## go_merchant_square_door -######*/ - -class go_merchant_square_door : public GameObjectScript +template +class gilneas_creature_script : public CreatureScript { public: - go_merchant_square_door() : GameObjectScript("go_merchant_square_door") { } + gilneas_creature_script(char const* name) : CreatureScript(name) { } - struct go_merchant_square_doorAI : public GameObjectAI + CreatureAI* GetAI(Creature* creature) const override { - go_merchant_square_doorAI(GameObject* gameObject) : GameObjectAI(gameObject), - _doorCloseTimer(0), _worgenTimer(0), _eventPending(false), _chaseActive(false), _chaseRefreshTimer(0), - _playerGUID(0), _citizenGUID(0), _worgenGUID(0), _worgenX(0), _worgenY(0), _worgenZ(0), _angle(0) { } - - void UpdateAI(uint32 diff) OVERRIDE - { - if (_doorCloseTimer) - { - if (_doorCloseTimer <= diff) - { - if (go->GetGoState() == GOState::GO_STATE_ACTIVE) - go->SetGoState(GOState::GO_STATE_READY); - _doorCloseTimer = 0; - } - else - _doorCloseTimer -= diff; - } - - if (_eventPending) - { - if (_worgenTimer <= diff) - { - _eventPending = false; - - if (Player* player = ObjectAccessor::GetPlayer(*go, _playerGUID)) - { - player->KilledMonsterCredit(NPC_MARKET_HOMES_EVACUATED); - - Creature* citizen = ObjectAccessor::GetCreature(*go, _citizenGUID); - if (!citizen) - SF_LOG_ERROR("scripts", "go_merchant_square_door: citizen (guid %u) not found when spawning worgen.", GUID_LOPART(_citizenGUID)); - - if (Creature* worgen = player->SummonCreature(NPC_RAMPAGING_WORGEN, _worgenX, _worgenY, _worgenZ, _angle, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, EVENT_SUMMON_TTL)) - { - if (citizen) - { - worgen->GetMotionMaster()->MoveChase(citizen); - _worgenGUID = worgen->GetGUID(); - _chaseActive = true; - _chaseRefreshTimer = 2000; - } - } - else - SF_LOG_ERROR("scripts", "go_merchant_square_door: SummonCreature(%u) for Rampaging Worgen failed at (%f, %f, %f).", uint32(NPC_RAMPAGING_WORGEN), _worgenX, _worgenY, _worgenZ); - } - else - SF_LOG_ERROR("scripts", "go_merchant_square_door: player (guid %u) not found when worgen timer expired.", GUID_LOPART(_playerGUID)); - } - else - _worgenTimer -= diff; - } - - // ChaseMovementGenerator can settle once the worgen reaches contact - // range and then never re-path as the citizen keeps wandering off - - // keep re-issuing the chase for the life of the encounter. - if (_chaseActive) - { - if (_chaseRefreshTimer <= diff) - { - Creature* citizen = ObjectAccessor::GetCreature(*go, _citizenGUID); - Creature* worgen = ObjectAccessor::GetCreature(*go, _worgenGUID); - if (citizen && worgen && worgen->IsAlive()) - { - worgen->GetMotionMaster()->MoveChase(citizen); - _chaseRefreshTimer = 2000; - } - else - _chaseActive = false; - } - else - _chaseRefreshTimer -= diff; - } - } - - bool GossipHello(Player* player) OVERRIDE - { - // One evacuation credit per player per door - otherwise a player - // could just farm the same door 3 times instead of visiting 3. - if (_usedByPlayers.count(player->GetGUID())) - { - SF_LOG_ERROR("scripts", "go_merchant_square_door: player %u already used this door (guid low %u), ignoring.", GUID_LOPART(player->GetGUID()), go->GetGUIDLow()); - return false; - } - - if (_eventPending) - { - SF_LOG_ERROR("scripts", "go_merchant_square_door: player %u used door (guid low %u) while an event was already pending.", GUID_LOPART(player->GetGUID()), go->GetGUIDLow()); - return false; - } - - if (go->GetGoState() != GOState::GO_STATE_READY) - { - SF_LOG_ERROR("scripts", "go_merchant_square_door: player %u used door (guid low %u) while not GO_STATE_READY (state=%u).", GUID_LOPART(player->GetGUID()), go->GetGUIDLow(), uint32(go->GetGoState())); - return false; - } - - _usedByPlayers.insert(player->GetGUID()); - - go->SetGoState(GOState::GO_STATE_ACTIVE); - _doorCloseTimer = EVENT_DOOR_TIMER; - - float angle = go->GetOrientation(); - float x = go->GetPositionX() - cos(angle) * 2.0f; - float y = go->GetPositionY() - sin(angle) * 2.0f; - float z = go->GetPositionZ(); - - // Spawned via the player (not the door) so the summons inherit the - // player's phase - a GameObject summoner always resolves to the - // default phase, which left prior citizen/worgen spawns invisible. - if (Creature* citizen = player->SummonCreature(NPC_FRIGHTENED_CITIZEN, x, y, z, angle, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, EVENT_CITIZEN_TTL)) - { - // Passive and immune to the worgen chasing it - the chase is for - // show, the citizen should never fight back or take damage. - citizen->SetReactState(REACT_PASSIVE); - citizen->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC); - - // MoveRandom moves in a straight line with no pathfinding (it - // can clip through walls), so flee toward the open square - // instead - MovePoint pathfinds around obstacles by default. - citizen->GetMotionMaster()->MovePoint(0, MerchantSquareCenterX, MerchantSquareCenterY, MerchantSquareCenterZ); - citizen->MonsterYell(FrightenedCitizenShouts[uint32(rand32()) % 5], Language::LANG_UNIVERSAL, NULL); - - _citizenGUID = citizen->GetGUID(); - _playerGUID = player->GetGUID(); - _worgenX = x - cos(angle) * 2.0f; - _worgenY = y - sin(angle) * 2.0f; - _worgenZ = z; - _angle = angle; - _worgenTimer = EVENT_WORGEN_DELAY; - _eventPending = true; - } - else - SF_LOG_ERROR("scripts", "go_merchant_square_door: SummonCreature(%u) for Frightened Citizen failed at (%f, %f, %f).", uint32(NPC_FRIGHTENED_CITIZEN), x, y, z); - - return false; - } - - private: - uint32 _doorCloseTimer; - uint32 _worgenTimer; - bool _eventPending; - bool _chaseActive; - uint32 _chaseRefreshTimer; - uint64 _playerGUID; - uint64 _citizenGUID; - uint64 _worgenGUID; - float _worgenX, _worgenY, _worgenZ, _angle; - std::unordered_set _usedByPlayers; - }; - - GameObjectAI* GetAI(GameObject* go) const OVERRIDE - { - return new go_merchant_square_doorAI(go); + return new AI(creature); } }; -/*###### -## Quest 14154 - By the Skin of His Teeth -######*/ - -enum BySkinOfHisTeeth -{ - NPC_LORD_DARIUS_CROWLEY_C1 = 35077, - NPC_SEAN_DEMPSEY = 35081, - NPC_WORGEN_ALPHA_C1 = 35170, - NPC_WORGEN_ALPHA_C2 = 35167, - NPC_WORGEN_RUNT_C1 = 35188, - NPC_WORGEN_RUNT_C2 = 35456, - - QUEST_BY_THE_SKIN_OF_HIS_TEETH = 14154, - - SPELL_BSOHT_BUFF = 66914, - SPELL_BSOHT_ENRAGE = 8599, - SPELL_BSOHT_LEFT_HOOK = 67825, - SPELL_BSOHT_DEMORALIZING_SHOUT = 61044, - SPELL_BSOHT_SNAP_KICK = 67827, - - EVENT_BSOHT_DURATION = 118500, - EVENT_BSOHT_SPAWN_TTL = 20000, - EVENT_BSOHT_ENRAGE_CD = 30000, -}; - -struct BsohtPoint -{ - float x, y, z; -}; - -float const BsohtPlatformZ = 52.29f; - -BsohtPoint const BsohtNWWaypointLoc1[2] = -{ - { -1630.62f, 1480.55f, 70.40f }, - { -1636.01f, 1475.81f, 64.51f } -}; - -BsohtPoint const BsohtNWWaypointLoc2[2] = -{ - { -1637.26f, 1488.86f, 69.95f }, - { -1642.45f, 1482.23f, 64.30f } -}; - -BsohtPoint const BsohtSWWaypointLoc1[2] = -{ - { -1718.31f, 1526.62f, 55.91f }, - { -1717.86f, 1490.77f, 56.61f } -}; - -BsohtPoint const BsohtSWWaypointLoc2[2] = -{ - { -1718.31f, 1526.62f, 55.91f }, - { -1717.86f, 1487.00f, 57.07f } -}; - -BsohtPoint const BsohtNWaypointLoc[1] = -{ - { -1593.38f, 1408.02f, 72.64f } -}; - -uint32 BsohtRand(uint32 min, uint32 max) -{ - return min + (uint32(rand32()) % (max - min + 1)); -} - -int32 BsohtIRand(int32 min, int32 max) -{ - return min + int32(uint32(rand32()) % uint32(max - min + 1)); -} - -/*###### -## npc_sean_dempsey - controls the worgen wave-spawning for the duration of the event -######*/ - -class npc_sean_dempsey : public CreatureScript +template +class gilneas_spell_script : public SpellScriptLoader { public: - npc_sean_dempsey() : CreatureScript("npc_sean_dempsey") { } + gilneas_spell_script(char const* name) : SpellScriptLoader(name) { } - struct npc_sean_dempseyAI : public ScriptedAI + SpellScript* GetSpellScript() const override { - npc_sean_dempseyAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 _spawnTimer; - uint32 _eventTimer; - uint32 _waveInterval; - uint64 _playerGUID; - bool _eventActive; - bool _firstWave; - - void Reset() OVERRIDE - { - _eventActive = false; - _firstWave = true; - _spawnTimer = 0; - _eventTimer = 0; - _playerGUID = 0; - _waveInterval = BsohtRand(9000, 15000); - } - - void StartEvent(uint64 playerGUID) - { - _eventActive = true; - _eventTimer = EVENT_BSOHT_DURATION; - _playerGUID = playerGUID; - } - - void SummonNextWave() - { - if (_firstWave) - { - me->SummonCreature(NPC_WORGEN_ALPHA_C2, -1732.81f, 1526.34f, 55.39f, 0.01f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - me->SummonCreature(NPC_WORGEN_ALPHA_C1, -1618.86f, 1505.68f, 70.24f, 3.91f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - _firstWave = false; - return; - } - - switch (BsohtRand(1, 5)) - { - case 1: // Alphas on the NW and SW roofs - me->SummonCreature(NPC_WORGEN_ALPHA_C2, -1732.81f, 1526.34f, 55.39f, 0.01f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - me->SummonCreature(NPC_WORGEN_ALPHA_C1, -1618.86f, 1505.68f, 70.24f, 3.91f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - break; - case 2: // 8 runts on the NW roof - for (uint8 i = 0; i < 4; ++i) - { - me->SummonCreature(NPC_WORGEN_RUNT_C1, -1611.40f, 1498.49f, 69.82f, 3.79f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - me->SummonCreature(NPC_WORGEN_RUNT_C1, -1618.86f, 1505.68f, 70.24f, 3.91f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - } - break; - case 3: // 8 runts on the SW roof - for (uint8 i = 0; i < 4; ++i) - { - me->SummonCreature(NPC_WORGEN_RUNT_C2, -1732.81f, 1526.34f, 55.39f, 0.01f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - me->SummonCreature(NPC_WORGEN_RUNT_C2, -1737.49f, 1526.11f, 55.51f, 0.01f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - } - break; - case 4: // Alphas on the N and SW roofs - me->SummonCreature(NPC_WORGEN_ALPHA_C2, -1732.81f, 1526.34f, 55.39f, 0.01f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - me->SummonCreature(NPC_WORGEN_ALPHA_C1, -1562.59f, 1409.35f, 71.66f, 3.16f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - break; - case 5: // 8 runts split across the NW and SW roofs - for (uint8 i = 0; i < 4; ++i) - { - me->SummonCreature(NPC_WORGEN_RUNT_C2, -1732.81f, 1526.34f, 55.39f, 0.01f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - me->SummonCreature(NPC_WORGEN_RUNT_C1, -1618.86f, 1505.68f, 70.24f, 3.91f, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, EVENT_BSOHT_SPAWN_TTL); - } - break; - } - } - - void UpdateAI(uint32 diff) OVERRIDE - { - if (!_eventActive) - return; - - if (_eventTimer <= diff) - { - _eventActive = false; - if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) - player->AreaExploredOrEventHappens(QUEST_BY_THE_SKIN_OF_HIS_TEETH); - return; - } - _eventTimer -= diff; - - if (_spawnTimer <= diff) - { - SummonNextWave(); - _spawnTimer = _waveInterval; - } - else - _spawnTimer -= diff; - } - }; - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_sean_dempseyAI(creature); + return new Spell(); } }; -/*###### -## npc_lord_darius_crowley_c1 - starts the event on quest accept, fights the worgen -######*/ - -class npc_lord_darius_crowley_c1 : public CreatureScript +class GilneasDelayedEvent : public BasicEvent { public: - npc_lord_darius_crowley_c1() : CreatureScript("npc_lord_darius_crowley_c1") { } + explicit GilneasDelayedEvent(std::function callback) : _callback(callback) { } - bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) OVERRIDE + bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override { - if (quest->GetQuestId() != QUEST_BY_THE_SKIN_OF_HIS_TEETH) - return true; - - creature->CastSpell(player, SPELL_BSOHT_BUFF, true); - - if (Creature* dempsey = creature->FindNearestCreature(NPC_SEAN_DEMPSEY, 100.0f)) - CAST_AI(npc_sean_dempsey::npc_sean_dempseyAI, dempsey->AI())->StartEvent(player->GetGUID()); - + _callback(); return true; } - struct npc_lord_darius_crowley_c1AI : public ScriptedAI +private: + std::function _callback; +}; + +template +void AddGilneasDelayedEvent(Unit* owner, uint32 delay, Callable callback) +{ + owner->m_Events.AddEvent(new GilneasDelayedEvent(std::function(callback)), owner->m_Events.CalculateTime(delay)); +} + +static int32 irand(int32 min, int32 max) +{ + if (max <= min) + return min; + + return min + int32(rand32() % uint32(max - min + 1)); +} + +static uint32 urand(uint32 min, uint32 max) +{ + if (max <= min) + return min; + + return min + rand32() % (max - min + 1); +} + +void MoveGilneasPointPath(Creature* creature, uint32 pointId, Position const* path, uint32 count, bool generatePath = false) +{ + if (!creature || !path || !count) + return; + + creature->GetMotionMaster()->MovePoint(pointId, path[count - 1], generatePath); +} + +enum Gilneas +{ + SPELL_PING_GILNEAN_CROW = 93275, + SPELL_SUMMON_RAVENOUS_WORGEN_1 = 66836, + SPELL_SUMMON_RAVENOUS_WORGEN_2 = 66925, + SPELL_SHOOT_INSTAKILL = 67593, // Visual problem + SPELL_COSMETIC_ATTACK = 69873, + SPELL_PULL_TO = 67357, + SPELL_GET_SHOT = 67349, + + EVENT_START_TALK_WITH_CITIZEN = 1, + EVENT_TALK_WITH_CITIZEN_1 = 2, + EVENT_TALK_WITH_CITIZEN_2 = 3, + EVENT_TALK_WITH_CITIZEN_3 = 4, + + EVENT_START_DIALOG = 1, + EVENT_START_TALK_TO_GUARD = 2, + EVENT_TALK_TO_GUARD_1 = 3, + EVENT_TALK_TO_GUARD_2 = 4, + EVENT_RESET_DIALOG = 5, + + PRINCE_LIAM_GREYMANE_TEXT_00 = 0, + PRINCE_LIAM_GREYMANE_TEXT_01 = 1, + PRINCE_LIAM_GREYMANE_TEXT_02 = 2, + + EVENT_JUMP_TO_PRISON = 1, + EVENT_AGGRO_PLAYER = 2, + EVENT_FORCE_DESPAWN = 3, + + EVENT_COSMETIC_ATTACK = 1, + EVENT_JUMP_TO_PLAYER = 2, + EVENT_SHOOT_JOSIAH = 3, + + PHASE_ROOF = 0, + PHASE_COMBAT = 1, + + WORGEN_ID_ROOF_1 = 0, + WORGEN_ID_ROOF_2 = 1, + WORGEN_ID_ROOF_3 = 2, + WORGEN_ID_ROOF_4 = 3, + WORGEN_ID_ROOF_5 = 4, + WORGEN_ID_ROOF_6 = 5, + WORGEN_ID_ROOF_7 = 6, + + WORGEN_ID_CATHEDRAL_1 = 7, + WORGEN_ID_CATHEDRAL_2 = 8, + WORGEN_ID_CATHEDRAL_3 = 9, + WORGEN_ID_CATHEDRAL_4 = 10, + WORGEN_ID_CATHEDRAL_5 = 11, + WORGEN_ID_CATHEDRAL_6 = 12, + WORGEN_ID_CATHEDRAL_7 = 13, + WORGEN_ID_CATHEDRAL_8 = 14, + WORGEN_ID_CATHEDRAL_9 = 15, + + NPC_PANICKED_CITIZEN_GATE = 44086, + NPC_WORGEN_RUNT = 35456, + NPC_WORGEN_RUNT_2 = 35188, + NPC_WORGEN_ALPHA = 35170, + NPC_WORGEN_ALPHA_2 = 35167, + NPC_LORNA_CROWLEY = 35378, + NPC_GENERIC_TRIGGER_LAB = 35374, + + SAY_JOSIAH_AVERY_1 = 0, + SAY_JOSIAH_AVERY_2 = 1, + SAY_JOSIAH_AVERY_3 = 2, + SAY_JOSIAH_AVERY_4 = 3, + SAY_JOSIAH_AVERY_5 = 4, + SAY_JOSIAH_AVERY_6 = 5, + + QUEST_FROM_THE_SHADOWS = 14204, + + NPC_GILNEAS_MASTIFF = 35631, + NPC_BLOODFANG_LURKER = 35463, + + SPELL_SUMMON_MASTIFF = 67807, + SPELL_ATTACK_LURKER = 67805, + SPELL_SHADOWSTALKER_STEALTH = 5916, + SPELL_UNDYING_FRENZY = 80515, + SPELL_ENRAGE = 8599, + + WORGEN_ENRAGE_EMOTE = 0, + + QUEST_SAVE_KRENNAN_ARANAS = 14293, + + NPC_KRENNAN_ARANAS = 35753, + NPC_KING_GREYMANES_HORSE = 35905, + NPC_BLOODFANG_RIPPER = 35505, + NPC_GILNEAS_CITY_GUARD = 35509, + NPC_KRENNAN_ARANAS_KILL_CREDIT = 35753, + + TEXT_KRENNAN_ARANAS = 0, + EMOTE_SAVE_KRENNAN_ARANAS = 0, + TEXT_SAVED_KRENNAN_ARANAS = 0, + + SPELL_GUARD_SHOOT = 48424, + + SPELL_SAVE_CYNTHIA = 68597, + SPELL_SAVE_ASHLEY = 68598, + SPELL_SAVE_JAMES = 68596, + + PLAYER_SAY_CYNTHIA = 0, + PLAYER_SAY_ASHLEY = 1, + PLAYER_SAY_JAMES = 2, + + NPC_JAMES = 36289, + NPC_CYNTHIA = 36287, + NPC_ASHLEY = 36288, + + EVENT_TALK_TO_PLAYER = 1, + EVENT_START_RUN = 2, + EVENT_OPEN_DOOR = 3, + EVENT_RESUME_RUN = 4, + EVENT_CRY = 5, + + CHILDREN_TEXT_ID = 0, + + GO_DOOR_TO_THE_BASEMENT = 196411, + + SPELL_CATCH_CAT = 68743, + SPELL_LUCIUS_SHOOT = 41440, + + NPC_WAHL = 36458, + NPC_WAHL_WORGEN = 36852, + NPC_LUCIUS_THE_CRUEL = 36461, + + SAY_THIS_CAT_IS_MINE = 0, + YELL_DONT_MESS = 0, + + ACTION_SUMMON_LUCIUS = 1, + ACTION_CHANCE_DESPAWN = 2, + ACTION_CONTINUE_SCENE = 3, + + POINT_CATCH_CHANCE = 4, + + SPELL_ROUND_UP_HORSE = 68908, + SPELL_ROPE_CHANNEL = 68940, + + EVENT_CHECK_LORNA = 1, + EVENT_CHECK_OWNER = 2, + + NPC_LORNA_CROWLEY_2 = 36457, + + QUEST_THE_HUNGRY_ETTIN = 14416, + + QUEST_CREDIT_HORSE = 36560, + + MUSIC_ENTRY_TELESCOPE = 23539, + PLAY_CINEMATIC_TELESCOPE = 167, + + QUEST_ENTRY_EXODUS = 24438, + + NPC_STAGECOACH_HARNESS = 38755, + NPC_HARNESS_SUMMONED = 43336, + + EVENT_BOARD_HARNESS_OWNER = 1, + + ACTION_START_WP = 1, + + GO_FIRST_GATE = 196401, + GO_KINGS_GATE = 196412 +}; + +Position const runt2SummonJumpPos = { -1671.915f, 1446.734f, 52.28712f }; +Position const alphaSummonJumpPos = { -1656.723f, 1405.647f, 52.74205f }; +Position const alpha2SummonJumpPos = { -1675.44f, 1447.495f, 52.28762f }; + +Position const josiahJumpPos = { -1796.63f, 1427.73f, 12.4624f }; + +uint32 const runtHousePathSize1 = 13; + +Position const worgenRuntHousePath1[runtHousePathSize1] = +{ + { -1734.77f, 1527.007f, 55.2133f }, + { -1729.345f, 1526.495f, 55.4231f }, + { -1723.921f, 1525.982f, 55.6329f }, + { -1718.885f, 1525.88f, 55.89785f }, + { -1718.002f, 1516.054f, 55.36457f }, + { -1718.162f, 1512.458f, 55.41572f }, + { -1717.852f, 1508.871f, 55.64134f }, + { -1717.868f, 1507.03f, 55.78084f }, + { -1717.939f, 1498.912f, 56.2076f }, + { -1717.975f, 1494.827f, 56.34147f }, + { -1717.666f, 1491.978f, 56.46574f }, + { -1717.708f, 1491.591f, 56.51286f }, + { -1717.708f, 1491.591f, 56.51286f }, +}; + +uint32 const runtHousePathSize2 = 11; + +Position const worgenRuntHousePath2[runtHousePathSize2] = +{ + {-1705.29f, 1527.974f, 57.49218f }, + {-1709.63f, 1527.464f, 56.81163f }, + {-1713.971f, 1526.953f, 56.13107f }, + {-1718.249f, 1525.915f, 55.91631f }, + {-1718.002f, 1516.054f, 55.36457f }, + {-1718.162f, 1512.458f, 55.41572f }, + {-1717.852f, 1508.871f, 55.64134f }, + {-1717.866f, 1507.038f, 55.7804f }, + {-1717.928f, 1498.872f, 56.20963f }, + {-1717.947f, 1496.298f, 56.29393f }, + {-1717.947f, 1496.298f, 56.29393f }, +}; + +uint32 const runtHousePathSize3 = 8; + +Position const worgenRuntHousePath3[runtHousePathSize3] = +{ + {-1717.74f, 1514.99f, 55.37629f }, + {-1717.75f, 1513.727f, 55.39608f }, + {-1717.76f, 1512.465f, 55.41587f }, + {-1717.787f, 1508.872f, 55.64124f }, + {-1717.799f, 1507.277f, 55.74761f }, + {-1717.864f, 1498.657f, 56.22049f }, + {-1717.887f, 1495.557f, 56.31728f }, + {-1717.887f, 1495.557f, 56.31728f }, +}; + +uint32 const runtHousePathSize4 = 11; + +Position const worgenRuntHousePath4[runtHousePathSize4] = +{ + { -1727.101f, 1527.078f, 55.5045f }, + { -1724.719f, 1526.731f, 55.60394f }, + { -1722.337f, 1526.383f, 55.70337f }, + { -1718.885f, 1525.88f, 55.89785f }, + { -1718.002f, 1516.054f, 55.36457f }, + { -1718.162f, 1512.458f, 55.41572f }, + { -1717.852f, 1508.871f, 55.64134f }, + { -1717.845f, 1507.113f, 55.77633f }, + { -1717.81f, 1498.482f, 56.22932f }, + { -1717.793f, 1494.123f, 56.37141f }, + { -1717.793f, 1494.123f, 56.37141f }, +}; + +uint32 const runtHousePathSize5 = 11; + +Position const worgenRuntHousePath5[runtHousePathSize5] = +{ + { -1709.699f, 1527.335f, 56.34836f }, + { -1713.974f, 1526.625f, 56.13234f }, + { -1718.249f, 1525.915f, 55.91631f }, + { -1718.002f, 1516.054f, 55.36457f }, + { -1718.162f, 1512.458f, 55.41572f }, + { -1717.852f, 1508.871f, 55.64134f }, + { -1717.891f, 1506.948f, 55.78529f }, + { -1718.047f, 1499.267f, 56.18964f }, + { -1718.125f, 1495.405f, 56.31914f }, + { -1717.693f, 1492.178f, 56.45717f }, + { -1717.693f, 1492.178f, 56.45717f }, +}; + +uint32 const runtHousePathSize6 = 9; + +Position const worgenRuntHousePath6[runtHousePathSize6] = +{ + { -1718.083f, 1532.09f, 56.25435f }, + { -1718.104f, 1524.071f, 55.80854f }, + { -1718.125f, 1516.053f, 55.36273f }, + { -1718.134f, 1512.459f, 55.41573f }, + { -1718.143f, 1508.866f, 55.64067f }, + { -1718.151f, 1506.013f, 55.83052f }, + { -1718.167f, 1499.665f, 56.16953f }, + { -1718.172f, 1497.578f, 56.24289f }, + { -1718.172f, 1497.578f, 56.24289f }, +}; + +uint32 const runtHousePathSize7 = 9; + +Position const worgenRuntHousePath7[runtHousePathSize7] = +{ + { -1718.083f, 1532.09f, 56.25435f }, + { -1718.104f, 1524.071f, 55.80854f }, + { -1718.125f, 1516.053f, 55.36273f }, + { -1718.134f, 1512.459f, 55.41573f }, + { -1718.143f, 1508.866f, 55.64067f }, + { -1718.151f, 1506.013f, 55.83052f }, + { -1718.167f, 1499.665f, 56.16953f }, + { -1718.172f, 1497.578f, 56.24289f }, + { -1718.172f, 1497.578f, 56.24289f }, +}; + +uint32 const runtCathedralPathSize1 = 10; + +Position const worgenRuntCathedralPath1[runtCathedralPathSize1] = +{ + { -1612.885f, 1492.154f, 67.03599f }, + { -1618.054f, 1489.644f, 68.5475f }, + { -1623.222f, 1487.134f, 70.05901f }, + { -1629.727f, 1483.976f, 72.59077f }, + { -1630.914f, 1483.4f, 72.92308f }, + { -1632.244f, 1482.754f, 72.91827f }, + { -1636.865f, 1480.51f, 68.61356f }, + { -1638.087f, 1479.916f, 67.58314f }, + { -1638.852f, 1479.545f, 66.56925f }, + { -1638.852f, 1479.545f, 66.56925f }, +}; + +uint32 const runtCathedralPathSize2 = 7; + +Position const worgenRuntCathedralPath2[runtCathedralPathSize2] = +{ + { -1618.982f, 1489.76f, 68.56043f }, + { -1625.62f, 1487.033f, 71.4378f }, + { -1632.258f, 1484.306f, 74.31516f }, + { -1634.6f, 1483.343f, 72.61462f }, + { -1636.067f, 1482.741f, 70.69682f }, + { -1639.282f, 1481.42f, 66.99659f }, + { -1639.282f, 1481.42f, 66.99659f }, +}; + +uint32 const runtCathedralPathSize3 = 6; + +Position const worgenRuntCathedralPath3[runtCathedralPathSize3] = +{ + { -1637.957f, 1493.445f, 67.77746f }, + { -1638.569f, 1489.736f, 68.47077f }, + { -1639.182f, 1486.027f, 69.16409f }, + { -1640.578f, 1477.564f, 64.01109f }, + { -1640.676f, 1476.976f, 63.45144f }, + { -1640.676f, 1476.976f, 63.45144f }, +}; + +uint32 const runtCathedralPathSize4 = 5; + +Position const worgenRuntCathedralPath4[runtCathedralPathSize4] = +{ + { -1628.66f, 1482.281f, 71.34027f }, + { -1630.399f, 1481.66f, 71.33196f }, + { -1632.139f, 1481.039f, 71.32365f }, + { -1639.006f, 1478.586f, 65.77306f }, + { -1639.006f, 1478.586f, 65.77306f }, +}; + + +uint32 const runtCathedralPathSize5 = 9; + +Position const worgenRuntCathedralPath5[runtCathedralPathSize5] = +{ + { -1620.279f, 1484.46f, 67.03528f }, + { -1622.424f, 1483.882f, 68.05564f }, + { -1624.568f, 1483.304f, 69.076f }, + { -1628.933f, 1482.127f, 70.91297f }, + { -1632.153f, 1481.259f, 71.52889f }, + { -1637.776f, 1479.743f, 67.45475f }, + { -1638.956f, 1479.425f, 66.41499f }, + { -1639.354f, 1479.318f, 65.98292f }, + { -1639.354f, 1479.318f, 65.98292f }, +}; + +uint32 const runtCathedralPathSize6 = 10; + +Position const worgenRuntCathedralPath6[runtCathedralPathSize6] = +{ + { -1633.998f, 1495.233f, 68.24403f }, + { -1634.344f, 1491.3f, 70.41303f }, + { -1634.689f, 1487.368f, 72.58203f }, + { -1634.735f, 1486.842f, 72.91134f }, + { -1634.837f, 1485.684f, 73.20835f }, + { -1634.987f, 1483.981f, 72.29824f }, + { -1635.084f, 1482.868f, 71.9163f }, + { -1635.166f, 1481.939f, 70.77574f }, + { -1635.809f, 1474.621f, 63.4636f }, + { -1635.809f, 1474.621f, 63.4636f }, +}; + +uint32 const runtCathedralPathSize7 = 7; + +Position const worgenRuntCathedralPath7[runtCathedralPathSize7] = +{ + { -1629.975f, 1494.066f, 70.64719f }, + { -1631.979f, 1491.585f, 71.31316f }, + { -1633.984f, 1489.104f, 71.97912f }, + { -1634.991f, 1487.856f, 72.09129f }, + { -1636.631f, 1485.826f, 71.53807f }, + { -1640.601f, 1480.912f, 65.49457f }, + { -1640.601f, 1480.912f, 65.49457f }, +}; + +uint32 const runtCathedralPathSize8 = 8; + +Position const worgenRuntCathedralPath8[runtCathedralPathSize8] = +{ + { -1620.879f, 1491.133f, 70.67613f }, + { -1622.665f, 1489.818f, 71.04526f }, + { -1624.451f, 1488.503f, 71.41438f }, + { -1630.469f, 1484.073f, 73.09648f }, + { -1631.376f, 1483.405f, 73.20229f }, + { -1632.245f, 1482.765f, 72.92912f }, + { -1635.605f, 1480.292f, 68.99215f }, + { -1635.605f, 1480.292f, 68.99215f }, +}; + +Position const worgenRuntJumpPos[] = +{ + { -1694.03f, 1466.33f, 52.2872f }, + { -1688.92f, 1455.69f, 52.2871f }, + { -1699.46f, 1468.43f, 52.2871f }, + { -1697.73f, 1469.52f, 52.2871f }, + { -1701.65f, 1470.94f, 52.2871f }, + { -1693.91f, 1468.46f, 52.2872f }, + { -1697.30f, 1464.65f, 52.2871f }, + + { -1681.57f, 1455.77f, 52.2871f }, + { -1677.47f, 1454.94f, 52.2871f }, + { -1677.71f, 1452.2f, 52.2871f }, + { -1677.66f, 1450.93f, 52.2871f }, + { -1672.56f, 1448.06f, 52.2871f }, + { -1683.13f, 1455.39f, 52.2871f }, + { -1669.81f, 1442.34f, 52.2871f }, + { -1674.15f, 1448.9f, 52.2871f }, +}; + +Position const WorgenRuntHousePos[] = +{ + { -1729.345f, 1526.495f, 55.47962f, 6.188943f }, + { -1709.63f, 1527.464f, 56.86086f, 3.258752f }, + { -1717.75f, 1513.727f, 55.47941f, 4.704845f }, + { -1724.719f, 1526.731f, 55.66177f, 6.138319f }, + { -1713.974f, 1526.625f, 56.21981f, 3.306195f }, + { -1718.104f, 1524.071f, 55.81641f, 4.709816f }, + { -1718.262f, 1518.557f, 55.55954f, 4.726997f }, + + { -1618.054f, 1489.644f, 68.45153f, 3.593639f }, + { -1625.62f, 1487.033f, 71.27762f, 3.531424f }, + { -1638.569f, 1489.736f, 68.55273f, 4.548815f }, + { -1630.399f, 1481.66f, 71.41516f, 3.484555f }, + { -1622.424f, 1483.882f, 67.67381f, 3.404875f }, + { -1634.344f, 1491.3f, 70.10101f, 4.6248f }, + { -1631.979f, 1491.585f, 71.11481f, 4.032866f }, + { -1627.273f, 1499.689f, 68.89395f, 4.251452f }, + { -1622.665f, 1489.818f, 71.03797f, 3.776179f }, +}; + +uint8 const JamesPathLenght = 6; +Position const JamesPath[][JamesPathLenght] = +{ { - npc_lord_darius_crowley_c1AI(Creature* creature) : ScriptedAI(creature) { } + { -1925.925049f, 2539.176514f, 1.392833f, 0.0f }, + { -1913.658203f, 2545.986328f, 1.465530f, 0.0f }, + { -1904.370728f, 2552.793213f, 1.132485f, 0.0f }, + { -1900.970459f, 2550.849365f, 0.714445f, 0.0f }, + { -1886.868774f, 2540.282471f, 1.706371f, 0.0f }, + { -1882.739746f, 2543.941865f, 1.628683f, 0.0f }, + }, +}; - uint32 _attackTimer; +uint8 const CynthiaPathLenght = 6; +Position const CynthiaPath[][CynthiaPathLenght] = +{ + { + { -1947.965088f, 2518.669434f, 1.826697f, 0.0f }, + { -1923.350830f, 2521.841553f, 1.586985f, 0.0f }, + { -1917.197632f, 2520.494385f, 2.297501f, 0.0f }, + { -1890.082031f, 2519.952148f, 1.425827f, 0.0f }, + { -1886.868774f, 2540.282471f, 1.706371f, 0.0f }, + { -1882.739746f, 2543.941865f, 1.628683f, 0.0f }, + }, +}; - void Reset() OVERRIDE +uint8 const AshleyPathLenght = 13; +Position const AshleyPath[][AshleyPathLenght] = +{ + { + { -1928.023682f, 2558.467285f, 12.733648f, 0.0f }, + { -1928.248901f, 2553.930176f, 12.734390f, 0.0f }, + { -1923.981567f, 2552.113770f, 12.736046f, 0.0f }, + { -1919.301514f, 2563.295166f, 3.579522f, 0.0f }, + { -1930.442017f, 2562.145996f, 3.579824f, 0.0f }, + { -1941.160156f, 2566.118896f, 1.392157f, 0.0f }, + { -1940.852295f, 2543.049072f, 1.392157f, 0.0f }, + { -1919.504517f, 2543.273926f, 1.392157f, 0.0f }, + { -1913.658203f, 2545.986328f, 1.465530f, 0.0f }, + { -1904.370728f, 2552.793213f, 1.132485f, 0.0f }, + { -1900.970459f, 2550.849365f, 0.714445f, 0.0f }, + { -1886.868774f, 2540.282471f, 1.706371f, 0.0f }, + { -1882.739746f, 2543.941865f, 1.628683f, 0.0f }, + }, +}; + +uint8 const childrenBasementPathLenght = 3; +Position const childrenBasementPath[][childrenBasementPathLenght] = +{ + { + { -1879.062378f, 2546.958984f, -0.130342f, 0.0f }, + { -1873.854980f, 2550.903564f, -5.898719f, 0.0f }, + { -1868.589844f, 2536.521240f, -6.365717f, 0.0f }, + }, +}; + +const std::string PlayerText[3] = +{ + "It's not safe here. Go to the Allens' basement.", + "Join the others inside the basement next door. Hurry!", + "Your mother's in the basement next door. Get to her now!", +}; + +class npc_gilnean_crow : public CreatureScript +{ +public: + npc_gilnean_crow() : CreatureScript("npc_gilneas_crow") {} + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_gilnean_crowAI(creature); + } + + struct npc_gilnean_crowAI : public ScriptedAI + { + npc_gilnean_crowAI(Creature* creature) : ScriptedAI(creature) {} + + uint32 tSpawn; + bool Move; + + void Reset() { - _attackTimer = BsohtRand(1700, 2400); + Move = false; + tSpawn = 0; + me->SetPosition(me->GetCreatureData()->posX, me->GetCreatureData()->posY, me->GetCreatureData()->posZ, me->GetCreatureData()->orientation); } - void UpdateAI(uint32 diff) OVERRIDE + void SpellHit(Unit* /*caster*/, const SpellInfo* spell) { - if (!UpdateVictim()) + if (spell->Id == SPELL_PING_GILNEAN_CROW) + { + if (!Move) + { + me->SetUInt32Value(UNIT_FIELD_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); // Change our emote state to allow flight + me->SetDisableGravity(true); + Move = true; + } + } + } + + void UpdateAI(const uint32 diff) + { + if (!Move) return; - if (_attackTimer <= diff) + if (tSpawn <= diff) { - if (me->IsWithinMeleeRange(me->GetVictim())) - { - switch (BsohtRand(0, 2)) - { - case 0: - DoCast(me->GetVictim(), SPELL_BSOHT_LEFT_HOOK, true); - break; - case 1: - DoCast(me->GetVictim(), SPELL_BSOHT_DEMORALIZING_SHOUT, true); - break; - case 2: - DoCast(me->GetVictim(), SPELL_BSOHT_SNAP_KICK, true); - break; - } - _attackTimer = BsohtRand(1700, 2400); - } - else - me->GetMotionMaster()->MoveChase(me->GetVictim()); + me->GetMotionMaster()->MovePoint(0, (me->GetPositionX() + irand(-15, 15)), (me->GetPositionY() + irand(-15, 15)), (me->GetPositionZ() + irand(5, 15))); + tSpawn = urand(500, 1000); } - else + else tSpawn -= diff; + + if ((me->GetPositionZ() - me->GetCreatureData()->posZ) >= 20.0f) { - _attackTimer -= diff; - DoMeleeAttackIfReady(); + me->DisappearAndDie(); + me->RemoveCorpse(true); + Move = false; } } }; +}; - CreatureAI* GetAI(Creature* creature) const OVERRIDE +struct npc_gilneas_city_guard_gate : public ScriptedAI +{ + npc_gilneas_city_guard_gate(Creature* creature) : ScriptedAI(creature) { } + + EventMap m_events; + uint8 m_say; + uint8 m_emote; + ObjectGuid m_citizenGUID; + + void Reset() override { - return new npc_lord_darius_crowley_c1AI(creature); + if (me->GetDistance2d(-1430.47f, 1345.55f) < 10.0f) + m_events.ScheduleEvent(EVENT_START_TALK_WITH_CITIZEN, urand(10000, 30000)); + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + while (uint32 eventId = m_events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_START_TALK_WITH_CITIZEN: + { + m_citizenGUID = GetRandomCitizen(); + m_emote = RAND(EMOTE_ONESHOT_COWER, EMOTE_STATE_TALK, EMOTE_ONESHOT_CRY, EMOTE_ONESHOT_BEG, EMOTE_ONESHOT_EXCLAMATION, EMOTE_ONESHOT_POINT); + m_say = 0; + + if (Creature* npc = ObjectAccessor::GetCreature(*me, m_citizenGUID)) + npc->HandleEmoteCommand(m_emote); + + m_events.ScheduleEvent(EVENT_TALK_WITH_CITIZEN_1, urand(2200, 3000)); + break; + } + case EVENT_TALK_WITH_CITIZEN_1: + { + if (Creature* npc = ObjectAccessor::GetCreature(*me, m_citizenGUID)) + npc->AI()->Talk(m_say); + + m_events.ScheduleEvent(EVENT_TALK_WITH_CITIZEN_2, 5000); + break; + } + case EVENT_TALK_WITH_CITIZEN_2: + { + Talk(m_say); + m_events.ScheduleEvent(EVENT_TALK_WITH_CITIZEN_3, 5000); + break; + } + case EVENT_TALK_WITH_CITIZEN_3: + { + if (Creature* npc = ObjectAccessor::GetCreature(*me, m_citizenGUID)) + npc->HandleEmoteCommand(EMOTE_STATE_NONE); + + m_events.ScheduleEvent(EVENT_START_TALK_WITH_CITIZEN, urand(5000, 30000)); + break; + } + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void FillCitizenList() + { + listOfCitizenGUID.clear(); + std::list listOfCitizen; + me->GetCreatureListWithEntryInGrid(listOfCitizen, NPC_PANICKED_CITIZEN_GATE, 35.0f); + + for (std::list::iterator itr = listOfCitizen.begin(); itr != listOfCitizen.end(); ++itr) + listOfCitizenGUID.push_back((*itr)->GetGUID()); + } + + ObjectGuid GetRandomCitizen() + { + if (listOfCitizenGUID.empty()) + FillCitizenList(); + + uint8 rol = urand(0, listOfCitizenGUID.size() - 1); + std::list::iterator itr = listOfCitizenGUID.begin(); + std::advance(itr, rol); + return (*itr); + } + +private: + std::list listOfCitizenGUID; +}; + +struct npc_prince_liam_greymane : public ScriptedAI +{ + npc_prince_liam_greymane(Creature* c) : ScriptedAI(c) { } + + EventMap _events; + + void Reset() override + { + _events.RescheduleEvent(EVENT_START_DIALOG, 1000); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_START_DIALOG: + { + _events.ScheduleEvent(EVENT_RESET_DIALOG, 120000); + _events.ScheduleEvent(EVENT_START_TALK_TO_GUARD, 1000); + break; + } + case EVENT_START_TALK_TO_GUARD: + { + Talk(PRINCE_LIAM_GREYMANE_TEXT_00); + _events.ScheduleEvent(EVENT_TALK_TO_GUARD_1, 15000); + break; + } + case EVENT_TALK_TO_GUARD_1: + { + Talk(PRINCE_LIAM_GREYMANE_TEXT_01); + _events.ScheduleEvent(EVENT_TALK_TO_GUARD_2, 18000); + break; + } + case EVENT_TALK_TO_GUARD_2: + { + Talk(PRINCE_LIAM_GREYMANE_TEXT_02); + break; + } + case EVENT_RESET_DIALOG: + { + Reset(); + break; + } + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); } }; -/*###### -## npc_worgen_runt_c1/c2, npc_worgen_alpha_c1/c2 - run rooftop waypoints to a jump-off -## point, land on the platform below, then fight whoever is closest -######*/ - -struct BsohtRoofFighterAI : public ScriptedAI +struct npc_worgen_runt : public ScriptedAI { - BsohtRoofFighterAI(Creature* creature, - float spawnX1, float spawnY1, BsohtPoint const* waypoints1, uint8 waypointCount1, float jumpX1, float jumpY1, - float spawnX2, float spawnY2, BsohtPoint const* waypoints2, uint8 waypointCount2, float jumpX2, float jumpY2, - float jumpSpeedXY, float jumpSpeedZ, float chaseRange) - : ScriptedAI(creature), - _spawnX1(spawnX1), _spawnY1(spawnY1), _waypoints1(waypoints1), _waypointCount1(waypointCount1), _jumpX1(jumpX1), _jumpY1(jumpY1), - _spawnX2(spawnX2), _spawnY2(spawnY2), _waypoints2(waypoints2), _waypointCount2(waypointCount2), _jumpX2(jumpX2), _jumpY2(jumpY2), - _jumpSpeedXY(jumpSpeedXY), _jumpSpeedZ(jumpSpeedZ), _chaseRange(chaseRange) { } - - void Reset() OVERRIDE + npc_worgen_runt(Creature* creature) : ScriptedAI(creature) { - _running = _jumping = _fighting = false; - _atLoc1 = _atLoc2 = false; - _waypointId = 0; - _issuedWaypointId = uint8(-1); - _enrageTimer = 0; - _willEnrage = BsohtRand(0, 1) != 0; + Initialize(); } - void EnterCombat(Unit* /*who*/) OVERRIDE + void Initialize() { - if (_fighting) - return; - - me->GetMotionMaster()->Clear(); - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - _running = false; - _jumping = false; - _fighting = true; + _worgenID = 0; + _wayPointCounter = 0; + _jumped = false; + _playerGuid = 0; } - void UpdateAI(uint32 diff) OVERRIDE + void EnterCombat(Unit* /*who*/) override { - if (!_running && !_jumping && !_fighting) + _events.SetPhase(PHASE_COMBAT); + } + + void IsSummonedBy(Unit* summoner) override + { + me->setActive(true); + _events.SetPhase(PHASE_ROOF); + _events.ScheduleEvent(EVENT_FORCE_DESPAWN, 70000, 0, PHASE_ROOF); + _playerGuid = summoner->GetGUID(); + + if (me->GetEntry() == NPC_WORGEN_RUNT_2) + me->GetMotionMaster()->MoveJump(runt2SummonJumpPos, 16.0f, 4.371286f); + + if (me->GetEntry() == NPC_WORGEN_ALPHA) { - if (me->GetPositionX() == _spawnX1 && me->GetPositionY() == _spawnY1) - { - _atLoc1 = true; - _running = true; - } - else if (_waypoints2 && me->GetPositionX() == _spawnX2 && me->GetPositionY() == _spawnY2) - { - _atLoc2 = true; - _running = true; - } - } + me->GetMotionMaster()->MoveJump(alphaSummonJumpPos, 14.0f, 5.395287f); - if (_running) - { - if (_waypointId == _issuedWaypointId) - return; - - if (_atLoc1 && _waypointId < _waypointCount1) - me->GetMotionMaster()->MovePoint(_waypointId, _waypoints1[_waypointId].x, _waypoints1[_waypointId].y, _waypoints1[_waypointId].z); - else if (_atLoc2 && _waypointId < _waypointCount2) - me->GetMotionMaster()->MovePoint(_waypointId, _waypoints2[_waypointId].x, _waypoints2[_waypointId].y, _waypoints2[_waypointId].z); - _issuedWaypointId = _waypointId; - return; - } - - if (_jumping) - return; - - if (_fighting) - { - if (!me->GetVictim()) - { - if (Player* player = me->SelectNearestPlayer(_chaseRange)) - AttackStart(player); - else if (Creature* crowley = me->FindNearestCreature(NPC_LORD_DARIUS_CROWLEY_C1, _chaseRange)) - AttackStart(crowley); - } - - if (!UpdateVictim()) - return; - - if (_enrageTimer <= diff) - { - if (_willEnrage && me->GetHealthPct() <= 30.0f) + AddGilneasDelayedEvent(me, 2500, [this]() { - DoCast(me, SPELL_BSOHT_ENRAGE); - _enrageTimer = EVENT_BSOHT_ENRAGE_CD; + me->GetMotionMaster()->MovePoint(0, -1676.767944f, 1442.418457f, 52.287319f, true); + }); + } + + if (me->GetEntry() == NPC_WORGEN_ALPHA_2) + me->GetMotionMaster()->MoveJump(alpha2SummonJumpPos, 17.0f, 4.937166f); + } + + void DoAction(int32 action) override + { + _worgenID = action; + + switch (_worgenID) + { + case WORGEN_ID_ROOF_1: + _wayPointCounter = runtHousePathSize1; + MoveGilneasPointPath(me, runtHousePathSize1, worgenRuntHousePath1, runtHousePathSize1); + break; + case WORGEN_ID_ROOF_2: + _wayPointCounter = runtHousePathSize2; + MoveGilneasPointPath(me, runtHousePathSize2, worgenRuntHousePath2, runtHousePathSize2); + break; + case WORGEN_ID_ROOF_3: + _wayPointCounter = runtHousePathSize3; + MoveGilneasPointPath(me, runtHousePathSize3, worgenRuntHousePath3, runtHousePathSize3); + break; + case WORGEN_ID_ROOF_4: + _wayPointCounter = runtHousePathSize4; + MoveGilneasPointPath(me, runtHousePathSize4, worgenRuntHousePath4, runtHousePathSize4); + break; + case WORGEN_ID_ROOF_5: + _wayPointCounter = runtHousePathSize5; + MoveGilneasPointPath(me, runtHousePathSize5, worgenRuntHousePath5, runtHousePathSize5); + break; + case WORGEN_ID_ROOF_6: + _wayPointCounter = runtHousePathSize6; + MoveGilneasPointPath(me, runtHousePathSize6, worgenRuntHousePath6, runtHousePathSize6); + break; + case WORGEN_ID_ROOF_7: + _wayPointCounter = runtHousePathSize7; + MoveGilneasPointPath(me, runtHousePathSize7, worgenRuntHousePath7, runtHousePathSize7); + break; + case WORGEN_ID_CATHEDRAL_1: + _wayPointCounter = runtCathedralPathSize1; + MoveGilneasPointPath(me, runtCathedralPathSize1, worgenRuntCathedralPath1, runtCathedralPathSize1); + break; + case WORGEN_ID_CATHEDRAL_2: + _wayPointCounter = runtCathedralPathSize2; + MoveGilneasPointPath(me, runtCathedralPathSize2, worgenRuntCathedralPath2, runtCathedralPathSize2); + break; + case WORGEN_ID_CATHEDRAL_3: + _wayPointCounter = runtCathedralPathSize3; + MoveGilneasPointPath(me, runtCathedralPathSize3, worgenRuntCathedralPath3, runtCathedralPathSize3); + break; + case WORGEN_ID_CATHEDRAL_4: + _wayPointCounter = runtCathedralPathSize4; + MoveGilneasPointPath(me, runtCathedralPathSize4, worgenRuntCathedralPath4, runtCathedralPathSize4); + break; + case WORGEN_ID_CATHEDRAL_5: + _wayPointCounter = runtCathedralPathSize5; + MoveGilneasPointPath(me, runtCathedralPathSize5, worgenRuntCathedralPath5, runtCathedralPathSize5); + break; + case WORGEN_ID_CATHEDRAL_6: + _wayPointCounter = runtCathedralPathSize6; + MoveGilneasPointPath(me, runtCathedralPathSize6, worgenRuntCathedralPath6, runtCathedralPathSize6); + break; + case WORGEN_ID_CATHEDRAL_7: + _wayPointCounter = runtCathedralPathSize7; + MoveGilneasPointPath(me, runtCathedralPathSize7, worgenRuntCathedralPath7, runtCathedralPathSize7); + break; + case WORGEN_ID_CATHEDRAL_8: + _wayPointCounter = runtCathedralPathSize8; + MoveGilneasPointPath(me, runtCathedralPathSize8, worgenRuntCathedralPath8, runtCathedralPathSize8); + break; + } + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(5 * IN_MILLISECONDS); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if ((type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE) && pointId == _wayPointCounter && !_jumped) + { + _jumped = true; + _events.ScheduleEvent(EVENT_JUMP_TO_PRISON, 1000); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !_events.IsInPhase(PHASE_ROOF)) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FORCE_DESPAWN: + me->DespawnOrUnsummon(); + break; + case EVENT_JUMP_TO_PRISON: + me->GetMotionMaster()->MoveJump(worgenRuntJumpPos[_worgenID], 16.0f, _worgenID < WORGEN_ID_CATHEDRAL_1 ? 19.2911f : frand(3.945607f, 4.852813f)); + me->SetHomePosition(worgenRuntJumpPos[_worgenID]); + _events.ScheduleEvent(EVENT_AGGRO_PLAYER, 2000); + break; + case EVENT_AGGRO_PLAYER: + if (Unit* player = ObjectAccessor::GetPlayer(*me, _playerGuid)) + if (me->IsAIEnabled && me->GetHomePosition().IsInDist(player, 100.0f)) + me->AI()->AttackStart(player); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + uint32 _worgenID; + uint32 _wayPointCounter; + bool _jumped; + ObjectGuid _playerGuid; + EventMap _events; +}; + +class spell_gen_gilneas_prison_periodic_dummy : public SpellScript +{ + PrepareSpellScript(spell_gen_gilneas_prison_periodic_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_RAVENOUS_WORGEN_1) || + !sSpellMgr->GetSpellInfo(SPELL_SUMMON_RAVENOUS_WORGEN_2)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + switch (RAND(0, 1)) + { + case 0: + caster->CastSpell(caster, SPELL_SUMMON_RAVENOUS_WORGEN_1, true); + for (uint8 i = 0; i < 7; i++) + if (Creature* runt = caster->SummonCreature(NPC_WORGEN_RUNT, WorgenRuntHousePos[i])) + runt->AI()->DoAction(i); + break; + case 1: + caster->CastSpell(caster, SPELL_SUMMON_RAVENOUS_WORGEN_2, true); + for (uint8 i = 7; i < 16; i++) + if (Creature* runt = caster->SummonCreature(NPC_WORGEN_RUNT, WorgenRuntHousePos[i])) + runt->AI()->DoAction(i); + if (RAND(0, 1) == 1) + for (uint8 i = 0; i < RAND(1, 3); i++) + if (Creature* runt = caster->SummonCreature(NPC_WORGEN_RUNT, WorgenRuntHousePos[i])) + runt->AI()->DoAction(i); + break; + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_gilneas_prison_periodic_dummy::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +struct npc_josiah_avery : public ScriptedAI +{ + npc_josiah_avery(Creature* creature) : ScriptedAI(creature) { } + + uint32 _text_timer; + uint32 _current_text; + + void Reset() override + { + _text_timer = 20 * IN_MILLISECONDS; + _current_text = 1; + } + + void UpdateAI(uint32 diff) override + { + if (!me->GetVictim() && me->SelectNearestPlayer(20.0f)) + { + if (_text_timer <= diff) + { + switch (_current_text) + { + case 1: + Talk(SAY_JOSIAH_AVERY_1); + _current_text++; + break; + case 2: + Talk(SAY_JOSIAH_AVERY_2); + _current_text++; + break; + case 3: + Talk(SAY_JOSIAH_AVERY_3); + _current_text++; + break; + case 4: + Talk(SAY_JOSIAH_AVERY_4); + _current_text++; + break; + case 5: + Talk(SAY_JOSIAH_AVERY_5); + _current_text++; + break; + case 6: + Talk(SAY_JOSIAH_AVERY_6); + _current_text = 1; + break; } + + _text_timer = 20 * IN_MILLISECONDS; } else - _enrageTimer -= diff; - - DoMeleeAttackIfReady(); + { + _text_timer -= diff; + } + return; } } +}; - void MovementInform(uint32 type, uint32 id) OVERRIDE +struct npc_josiah_avery_worgen_form : public PassiveAI +{ + npc_josiah_avery_worgen_form(Creature* creature) : PassiveAI(creature) { } + + void IsSummonedBy(Unit* summoner) override { - if (type == EFFECT_MOTION_TYPE && id == EVENT_JUMP) + _playerGuid = summoner->GetGUID(); + + AddGilneasDelayedEvent(me, 200, [this, summoner]() + { + me->SetFacingToObject(summoner); + _events.ScheduleEvent(EVENT_COSMETIC_ATTACK, 500); + }); + } + + void SpellHit(Unit* /*caster*/, const SpellInfo* spell) + { + if (spell->Id == SPELL_SHOOT_INSTAKILL) + me->CastSpell(me, SPELL_GET_SHOT); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(5 * IN_MILLISECONDS); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) { - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - _jumping = false; - _fighting = true; - return; - } + switch (eventId) + { + case EVENT_COSMETIC_ATTACK: + if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGuid)) + { + DoCast(player, SPELL_COSMETIC_ATTACK); - if (type != POINT_MOTION_TYPE) - return; + AddGilneasDelayedEvent(me, 400, [this, player]() + { + if (Creature* lorna = me->FindNearestCreature(NPC_LORNA_CROWLEY, 30.0f, true)) + player->GetMotionMaster()->MoveKnockbackFrom(lorna->GetPositionX(), lorna->GetPositionY(), 30, 30); + }); - _waypointId = id + 1; + if (Creature* lorna = me->FindNearestCreature(NPC_LORNA_CROWLEY, 30.0f, true)) + if (Creature* labTrigger = lorna->FindNearestCreature(NPC_GENERIC_TRIGGER_LAB, 5.0f, true)) + labTrigger->CastSpell(player, SPELL_PULL_TO); - uint8 count = _atLoc1 ? _waypointCount1 : _waypointCount2; - if (_waypointId >= count) - { - float jumpX = _atLoc1 ? _jumpX1 : _jumpX2; - float jumpY = _atLoc1 ? _jumpY1 : _jumpY2; - me->GetMotionMaster()->MoveJump(jumpX + float(BsohtIRand(-3, 3)), jumpY + float(BsohtIRand(-3, 3)), BsohtPlatformZ, _jumpSpeedXY, _jumpSpeedZ); - _running = false; - _jumping = true; + _events.ScheduleEvent(EVENT_JUMP_TO_PLAYER, 1000); + } + break; + case EVENT_JUMP_TO_PLAYER: + me->GetMotionMaster()->MoveJump(josiahJumpPos, 10.0f, 14.18636f); + _events.ScheduleEvent(EVENT_SHOOT_JOSIAH, 1200); + break; + case EVENT_SHOOT_JOSIAH: + if (Creature* lorna = me->FindNearestCreature(NPC_LORNA_CROWLEY, 30.0f, true)) + lorna->CastSpell(me, SPELL_SHOOT_INSTAKILL, true); + break; + default: + break; + } } } private: - float _spawnX1, _spawnY1; - BsohtPoint const* _waypoints1; - uint8 _waypointCount1; - float _jumpX1, _jumpY1; - float _spawnX2, _spawnY2; - BsohtPoint const* _waypoints2; - uint8 _waypointCount2; - float _jumpX2, _jumpY2; - float _jumpSpeedXY, _jumpSpeedZ, _chaseRange; - - bool _running, _jumping, _fighting; - bool _atLoc1, _atLoc2; - uint8 _waypointId; - uint8 _issuedWaypointId; - uint32 _enrageTimer; - bool _willEnrage; + ObjectGuid _playerGuid; + EventMap _events; }; -class npc_worgen_runt_c1 : public CreatureScript +class spell_gilneas_pull_to : public SpellScript { -public: - npc_worgen_runt_c1() : CreatureScript("npc_worgen_runt_c1") { } + PrepareSpellScript(spell_gilneas_pull_to); - CreatureAI* GetAI(Creature* creature) const OVERRIDE + void HandPullEffect(SpellEffIndex effIndex) { - return new BsohtRoofFighterAI(creature, - -1611.40f, 1498.49f, BsohtNWWaypointLoc1, 2, -1668.52f, 1439.69f, - -1618.86f, 1505.68f, BsohtNWWaypointLoc2, 2, -1678.04f, 1450.88f, - 20.0f, 22.0f, 40.0f); + PreventHitDefaultEffect(effIndex); + + if (Unit* playerTarget = GetHitPlayer()) + { + if (Unit* trigger = GetCaster()) + { + float angle = playerTarget->GetAngle(trigger); + playerTarget->SendMoveKnockBack(playerTarget->ToPlayer(), 30.0f, -7.361481f, cos(angle), sin(angle)); + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gilneas_pull_to::HandPullEffect, EFFECT_0, SPELL_EFFECT_PULL_TOWARDS); } }; -class npc_worgen_runt_c2 : public CreatureScript +class npc_lorna_crowley_basement : public CreatureScript { public: - npc_worgen_runt_c2() : CreatureScript("npc_worgen_runt_c2") { } + npc_lorna_crowley_basement(const char* ScriptName) : CreatureScript(ScriptName) { } - CreatureAI* GetAI(Creature* creature) const OVERRIDE + bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) { - return new BsohtRoofFighterAI(creature, - -1732.81f, 1526.34f, BsohtSWWaypointLoc1, 2, -1685.521f, 1458.48f, - -1737.49f, 1526.11f, BsohtSWWaypointLoc2, 2, -1681.81f, 1445.54f, - 20.0f, 22.0f, 50.0f); + if (quest->GetQuestId() == QUEST_FROM_THE_SHADOWS) + { + if (player->getClass() == CLASS_HUNTER) + player->UnsummonPetTemporaryIfAny(); + + player->CastSpell(player, SPELL_SUMMON_MASTIFF, false); + creature->AI()->Talk(0); + } + return true; } -}; -class npc_worgen_alpha_c1 : public CreatureScript -{ -public: - npc_worgen_alpha_c1() : CreatureScript("npc_worgen_alpha_c1") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE + bool OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 /*opt*/) { - return new BsohtRoofFighterAI(creature, - -1618.86f, 1505.68f, BsohtNWWaypointLoc1, 2, -1668.52f, 1439.69f, - -1562.59f, 1409.35f, BsohtNWaypointLoc, 1, -1660.17f, 1429.55f, - 22.0f, 20.0f, 40.0f); - } -}; + if (quest->GetQuestId() == QUEST_FROM_THE_SHADOWS) + if (Unit* charm = Unit::GetCreature(*creature, player->GetMinionGUID())) + if (charm->GetEntry() == NPC_GILNEAS_MASTIFF) + if (Creature* mastiff = charm->ToCreature()) + mastiff->DespawnOrUnsummon(); -class npc_worgen_alpha_c2 : public CreatureScript -{ -public: - npc_worgen_alpha_c2() : CreatureScript("npc_worgen_alpha_c2") { } - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new BsohtRoofFighterAI(creature, - -1732.81f, 1526.34f, BsohtSWWaypointLoc1, 2, -1685.52f, 1458.48f, - 0.0f, 0.0f, nullptr, 0, 0.0f, 0.0f, - 20.0f, 22.0f, 40.0f); - } -}; - -/*###### -## Quest 14159 - The Rebel Lord's Arsenal -######*/ - -enum RebelLordsArsenal -{ - NPC_JOSIAH_AVERY_P2 = 35369, - NPC_JOSIAH_AVERY_P4 = 35370, - NPC_JOSIAH_AVERY_TRIGGER = 50415, - NPC_LORNA_CROWLEY_P4 = 35378, - - QUEST_REBEL_LORDS_ARSENAL = 14159, - - SPELL_ARSENAL_COSMETIC_ATTACK = 69873, - SPELL_ARSENAL_SHOOT = 6660, - SPELL_WORGEN_BITE = 72870, - SPELL_SUMMON_JOSIAH_AVERY = 67350, - SPELL_GET_SHOT = 67349, - SPELL_PHASE_QUEST_2 = 59073, - - PHASE_JOSIAH_AVERY_REVEAL = 171, - - SAY_JOSIAH_AVERY_TRIGGER_BITTEN = 0, -}; - -/*###### -## npc_josiah_avery - quest 14159 turn-in; marks the player as bitten and -## summons his phase-4 double for the worgen-reveal cutscene -######*/ - -class npc_josiah_avery : public CreatureScript -{ -public: - npc_josiah_avery() : CreatureScript("npc_josiah_avery") { } - - bool OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 /*opt*/) OVERRIDE - { - if (quest->GetQuestId() != QUEST_REBEL_LORDS_ARSENAL) - return true; - - creature->AddAura(SPELL_WORGEN_BITE, player); - player->RemoveAura(SPELL_PHASE_QUEST_2); - player->SetPhased(PHASE_JOSIAH_AVERY_REVEAL, true, true); - - creature->SetPhased(PHASE_JOSIAH_AVERY_REVEAL, true, true); - creature->CastSpell(creature, SPELL_SUMMON_JOSIAH_AVERY, true); - creature->SetPhased(PHASE_JOSIAH_AVERY_REVEAL, true, false); + if (player->getClass() == CLASS_HUNTER) + player->ResummonPetTemporaryUnSummonedIfAny(); return true; } -}; -/*###### -## npc_josiah_avery_trigger - waits for a bitten player to approach both Lorna -## Crowley and the phase-4 Josiah Avery double, then runs the reveal: Avery -## "attacks" the player, gets knocked back, and is shot down by Lorna. -######*/ - -class npc_josiah_avery_trigger : public CreatureScript -{ -public: - npc_josiah_avery_trigger() : CreatureScript("npc_josiah_avery_trigger") { } - - struct npc_josiah_avery_triggerAI : public ScriptedAI + CreatureAI* GetAI(Creature* creature) const override { - npc_josiah_avery_triggerAI(Creature* creature) : ScriptedAI(creature) { } + return new npc_lorna_crowley_basementAI(creature); + } - uint8 _step; - uint32 _stepTimer; - uint64 _playerGUID; - - void Reset() OVERRIDE + struct npc_lorna_crowley_basementAI : public ScriptedAI + { + npc_lorna_crowley_basementAI(Creature* creature) : ScriptedAI(creature) { - _step = 0; - _stepTimer = 0; - _playerGUID = 0; + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void UpdateAI(uint32 diff) OVERRIDE + void UpdateAI(uint32 diff) override { - if (_step == 0) - { - Creature* lorna = me->FindNearestCreature(NPC_LORNA_CROWLEY_P4, 60.0f); - Creature* avery = me->FindNearestCreature(NPC_JOSIAH_AVERY_P4, 80.0f); - if (!lorna || !avery) - return; - - Player* player = me->SelectNearestPlayer(50.0f); - if (!player || !player->HasAura(SPELL_WORGEN_BITE)) - return; - - _playerGUID = player->GetGUID(); - _stepTimer = 200; - _step = 1; + if (!UpdateVictim()) return; - } - - if (_stepTimer > diff) - { - _stepTimer -= diff; - return; - } - - Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID); - Creature* lorna = me->FindNearestCreature(NPC_LORNA_CROWLEY_P4, 60.0f); - Creature* avery = me->FindNearestCreature(NPC_JOSIAH_AVERY_P4, 80.0f); - if (!player || !lorna || !avery) - { - Reset(); - return; - } - - switch (_step) - { - case 1: - Talk(SAY_JOSIAH_AVERY_TRIGGER_BITTEN, player); - _stepTimer = 1200; - break; - case 2: - avery->SetOrientation(avery->GetAngle(player)); - avery->CastSpell(player, SPELL_ARSENAL_COSMETIC_ATTACK, true); - player->GetMotionMaster()->MoveKnockbackFrom(avery->GetPositionX(), avery->GetPositionY(), 22.0f, 8.0f); - avery->getThreatManager().resetAllAggro(); - _stepTimer = 600; - break; - case 3: - avery->GetMotionMaster()->MoveJump(-1791.94f, 1427.29f, 12.4584f, 18.0f, 7.0f); - _stepTimer = 200; - break; - case 4: - lorna->CastSpell(avery, SPELL_ARSENAL_SHOOT, true); - _stepTimer = 200; - break; - case 5: - avery->CastSpell(avery, SPELL_GET_SHOT, true); - avery->setDeathState(DeathState::JUST_DIED); - player->SaveToDB(); - avery->DespawnOrUnsummon(1000); - me->DespawnOrUnsummon(1000); - Reset(); - return; - } - - ++_step; } }; +}; - CreatureAI* GetAI(Creature* creature) const OVERRIDE +struct npc_gilnean_mastiff : public ScriptedAI +{ + npc_gilnean_mastiff(Creature* creature) : ScriptedAI(creature) { - return new npc_josiah_avery_triggerAI(creature); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_ATTACK_LURKER, true); + } + + void Reset() override + { + me->GetCharmInfo()->InitEmptyActionBar(false); + me->GetCharmInfo()->SetActionBar(0, SPELL_ATTACK_LURKER, ACT_PASSIVE); + me->SetReactState(REACT_DEFENSIVE); + me->GetCharmInfo()->SetIsFollowing(true); + } + + void UpdateAI(uint32 /*diff*/) override + { + Player* player = me->GetOwner()->ToPlayer(); + + if (player->GetQuestStatus(QUEST_FROM_THE_SHADOWS) == QUEST_STATUS_REWARDED) + me->DespawnOrUnsummon(1); + + if (!UpdateVictim()) + { + me->GetCharmInfo()->SetIsFollowing(true); + me->SetReactState(REACT_DEFENSIVE); + return; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(1); + } + + void KilledUnit(Unit* /*victim*/) override + { + Reset(); } }; -/*###### -## Quest 14204 - From the Shadows -######*/ - -enum FromTheShadows +struct npc_bloodfang_lurker : public ScriptedAI { - NPC_GILNEAN_MASTIFF = 35631, - NPC_BLOODFANG_LURKER = 35463, + npc_bloodfang_lurker(Creature* creature) : ScriptedAI(creature) { } - QUEST_FROM_THE_SHADOWS = 14204, + bool _enrage; + bool _frenzy; - ITEM_GILNEAN_MASTIFF_COLLAR = 48707, + void Reset() override + { + _enrage = false; + _frenzy = false; + DoCast(me, SPELL_SHADOWSTALKER_STEALTH); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + } - SPELL_SUMMON_GILNEAN_MASTIFF = 67807, - SPELL_MASTIFF_ATTACK_LURKER = 67805, - SPELL_LURKER_SHADOWSTALKER_STEALTH = 34189, - SPELL_LURKER_ENRAGE = 8599, + void StartAttack(Unit* who) + { + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWith(who); + who->SetInCombatWith(me); + } - CD_LURKER_ENRAGE = 30000, + void DamageTaken(Unit* attacker, uint32& damage) override + { + if (me->HasReactState(REACT_PASSIVE)) + StartAttack(attacker); + } + + void SpellHit(Unit* caster, const SpellInfo* spell) override + { + if (spell->Id == SPELL_ATTACK_LURKER) + StartAttack(caster); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (!_frenzy && me->HealthBelowPct(45)) + { + _frenzy = true; + DoCast(SPELL_UNDYING_FRENZY); + } + + if (!_enrage && me->HealthBelowPct(30)) + { + _enrage = true; + DoCast(SPELL_ENRAGE); + Talk(WORGEN_ENRAGE_EMOTE); + } + + DoMeleeAttackIfReady(); + } }; -/*###### -## npc_lorna_crowley_p4 - quest 14204 accept; clears a hunter's active pet and -## charms the tracking mastiff to the player immediately. The collar item -## (granted natively via the quest's SourceItemId) is then used to command -## the mastiff to expose and attack the nearest stealthed Bloodfang Lurker. -######*/ +class spell_attack_lurker : public SpellScript +{ + PrepareSpellScript(spell_attack_lurker); -class npc_lorna_crowley_p4 : public CreatureScript + void HandleDummy() + { + Unit* caster = GetCaster(); + + if (Creature* target = caster->FindNearestCreature(NPC_BLOODFANG_LURKER, 30.0f)) + { + float x, y, z, o; + target->GetContactPoint(caster, x, y, z, CONTACT_DISTANCE); + o = caster->GetOrientation(); + float speedXY, speedZ; + speedZ = 10.0f; + speedXY = caster->GetExactDist2d(x, y) * 30.0f / speedZ; + caster->GetMotionMaster()->MoveCharge(x, y, z, speedXY, speedZ); + target->RemoveAura(SPELL_SHADOWSTALKER_STEALTH); + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + target->SetReactState(REACT_AGGRESSIVE); + target->AI()->AttackStart(caster); + } + } + + void Register() override + { + AfterCast += SpellCastFn(spell_attack_lurker::HandleDummy); + } +}; + +class npc_king_genn_greymane : public CreatureScript { public: - npc_lorna_crowley_p4() : CreatureScript("npc_lorna_crowley_p4") { } + npc_king_genn_greymane() : CreatureScript("npc_king_genn_greymane") { } - bool OnQuestAccept(Player* player, Creature* /*creature*/, Quest const* quest) OVERRIDE + bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) { - if (quest->GetQuestId() != QUEST_FROM_THE_SHADOWS) - return true; + if (quest->GetQuestId() == QUEST_SAVE_KRENNAN_ARANAS) + { + float x, y; + creature->GetNearPoint2D(x, y, 2.0f, player->GetOrientation() + M_PI / 2); - if (player->getClass() == CLASS_HUNTER && player->GetPet()) - player->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - - player->CastSpell(player, SPELL_SUMMON_GILNEAN_MASTIFF, true); + if (Creature* horse = player->SummonCreature(NPC_KING_GREYMANES_HORSE, x, y, creature->GetPositionZ(), creature->GetOrientation())) + { + if (npc_escortAI* escort = CAST_AI(npc_escortAI, horse->AI())) + { + escort->AddWaypoint(1, -1799.37f, 1400.21f, 19.8951f); + escort->AddWaypoint(2, -1798.23f, 1396.9f, 19.8993f); + escort->AddWaypoint(3, -1795.03f, 1388.01f, 19.8898f); + escort->AddWaypoint(4, -1790.16f, 1378.7f, 19.8016f); + escort->AddWaypoint(5, -1786.41f, 1372.97f, 19.8406f); + escort->AddWaypoint(6, -1779.72f, 1364.88f, 19.8131f); + escort->AddWaypoint(7, -1774.43f, 1359.87f, 19.7021f); + escort->AddWaypoint(8, -1769.0f, 1356.76f, 19.7439f); + escort->AddWaypoint(9, -1762.64f, 1356.02f, 19.7979f); + escort->AddWaypoint(10, -1758.91f, 1356.08f, 19.8635f); + escort->AddWaypoint(11, -1751.95f, 1356.8f, 19.8273f); + escort->AddWaypoint(12, -1745.66f, 1357.21f, 19.7993f); + escort->AddWaypoint(13, -1738.7f, 1356.64f, 19.7822f); + escort->AddWaypoint(14, -1731.79f, 1355.51f, 19.7149f); + escort->AddWaypoint(15, -1724.89f, 1354.29f, 19.8661f); + escort->AddWaypoint(16, -1718.03f, 1352.93f, 19.7824f); + escort->AddWaypoint(17, -1707.68f, 1351.16f, 19.7811f); // Jump + escort->AddWaypoint(18, -1673.04f, 1344.91f, 15.1353f, 2000); + escort->AddWaypoint(19, -1673.04f, 1344.91f, 15.1353f); + escort->AddWaypoint(20, -1669.32f, 1346.55f, 15.1353f); + escort->AddWaypoint(21, -1666.45f, 1349.89f, 15.1353f); + escort->AddWaypoint(22, -1665.61f, 1353.85f, 15.1353f); + escort->AddWaypoint(23, -1666.04f, 1358.01f, 15.1353f); + escort->AddWaypoint(24, -1669.79f, 1360.71f, 15.1353f); + escort->AddWaypoint(25, -1673.1f, 1362.11f, 15.1353f); + escort->AddWaypoint(26, -1677.12f, 1361.57f, 15.1353f); + escort->AddWaypoint(27, -1679.9f, 1360.1f, 15.1353f); + escort->AddWaypoint(28, -1682.79f, 1357.56f, 15.1353f); + escort->AddWaypoint(29, -1682.79f, 1357.56f, 15.1353f); + escort->AddWaypoint(30, -1689.07f, 1352.39f, 15.1353f); + escort->AddWaypoint(31, -1691.91f, 1351.83f, 15.1353f); + escort->AddWaypoint(32, -1703.81f, 1351.82f, 19.7604f); + escort->AddWaypoint(33, -1707.26f, 1352.38f, 19.7826f); + escort->AddWaypoint(34, -1712.25f, 1353.55f, 19.7826f); + escort->AddWaypoint(35, -1718.2f, 1356.51f, 19.7164f); + escort->AddWaypoint(36, -1741.5f, 1372.04f, 19.9569f); + escort->AddWaypoint(37, -1746.23f, 1375.8f, 19.9817f); + escort->AddWaypoint(38, -1751.06f, 1380.53f, 19.8424f); + escort->AddWaypoint(39, -1754.97f, 1386.34f, 19.8474f); + escort->AddWaypoint(40, -1760.77f, 1394.37f, 19.9282f); + escort->AddWaypoint(41, -1765.11f, 1402.07f, 19.8816f); + escort->AddWaypoint(42, -1768.24f, 1410.2f, 19.7833f); + escort->AddWaypoint(43, -1772.26f, 1420.48f, 19.9029f); + escort->AddWaypoint(44, -1776.98f, 1436.13f, 19.632f); + player->EnterVehicle(horse, 0); + } + } + } return true; } + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_king_genn_greymaneAI(creature); + } + + struct npc_king_genn_greymaneAI : public ScriptedAI + { + npc_king_genn_greymaneAI(Creature* creature) : ScriptedAI(creature), _talkTimer(urand(15000, 35000)) + { + } + + void UpdateAI(uint32 diff) override + { + if (_talkTimer <= diff) + { + Talk(0); + _talkTimer = urand(15000, 35000); + } + else + _talkTimer -= diff; + } + + private: + uint32 _talkTimer; + }; }; -/*###### -## npc_gilnean_mastiff - the player's tracking pet for quest 14204; strips the -## Bloodfang Lurkers' stealth on command so the player can engage them -######*/ - -class npc_gilnean_mastiff : public CreatureScript +class npc_vehicle_genn_horse : public CreatureScript { public: - npc_gilnean_mastiff() : CreatureScript("npc_gilnean_mastiff") { } + npc_vehicle_genn_horse() : CreatureScript("npc_vehicle_genn_horse") { } - struct npc_gilnean_mastiffAI : public ScriptedAI + CreatureAI* GetAI(Creature* creature) const override { - npc_gilnean_mastiffAI(Creature* creature) : ScriptedAI(creature), _followCheckTimer(0) { } + return new npc_vehicle_genn_horseAI(creature); + } - uint32 _followCheckTimer; - - void Reset() OVERRIDE + struct npc_vehicle_genn_horseAI : public npc_escortAI + { + npc_vehicle_genn_horseAI(Creature* creature) : npc_escortAI(creature) { - me->GetCharmInfo()->InitEmptyActionBar(false); - me->GetCharmInfo()->SetActionBar(0, SPELL_MASTIFF_ATTACK_LURKER, ACT_DISABLED); - me->SetReactState(REACT_DEFENSIVE); - me->GetCharmInfo()->SetIsFollowing(true); - _followCheckTimer = 2000; - - // Reset() is also where a stuck-in-evade creature lands every time it - // exits evade mode, and Creature::Update() skips UpdateAI() entirely - // while IsInEvadeMode() is true - so the catch-up teleport has to live - // here too, or a mastiff that keeps evading on a broken path never - // gets a chance to run the check in UpdateAI at all. - if (Unit* owner = me->GetCharmerOrOwner()) - { - if (me->GetDistance(owner) > 15.0f) - me->NearTeleportTo(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); - - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - } + _aranasSaved = false; + _playerSeated = false; } - // Triggered by using the Gilnean Mastiff Collar. Player target selection - // can't pick out a stealthed Lurker at all, so a player-issued attack has - // nothing to act on. The mastiff's own FindNearestCreature is a - // server-side lookup and isn't blocked by client-side stealth, so it - // sniffs one out and reveals it directly on the player's command. - bool RevealNearbyLurker() + bool _playerSeated; + bool _aranasSaved; + + void AttackStart(Unit* /*who*/) override { } + void EnterCombat(Unit* /*who*/) override { } + void EnterEvadeMode() override { } + + void Reset() override { - if (me->IsInCombat()) - return false; - - Creature* lurker = me->FindNearestCreature(NPC_BLOODFANG_LURKER, 15.0f, true); - if (!lurker) - return false; - - lurker->RemoveAura(SPELL_LURKER_SHADOWSTALKER_STEALTH); - lurker->AddThreat(me, 1.0f); - me->AddThreat(lurker, 1.0f); - AttackStart(lurker); - return true; + _playerSeated = false; } - void UpdateAI(uint32 diff) OVERRIDE + void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) { - Unit* owner = me->GetCharmerOrOwner(); - Player* ownerPlayer = owner ? owner->ToPlayer() : NULL; - if (ownerPlayer && ownerPlayer->GetQuestStatus(QUEST_FROM_THE_SHADOWS) == QUEST_STATUS_REWARDED) + if (who->GetTypeId() == TypeID::TYPEID_PLAYER) { - me->DespawnOrUnsummon(1); - return; - } + _playerSeated = true; - // Stairwells/cellar transitions in this zone have gaps in the static - // navmesh, so a normal pathfound follow can get permanently stuck. - // Checked unconditionally (not just while idle) since a broken path - // can also strand it mid-"chase" with a phantom victim. - if (owner) - { - if (_followCheckTimer <= diff) + if (apply) { - if (me->GetDistance(owner) > 15.0f) - { - me->NearTeleportTo(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); - if (!me->IsInCombat()) - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - } - _followCheckTimer = 2000; + Start(false, true, who->GetGUID()); + me->SetSpeed(MOVE_WALK, 1.0f, true); + me->SetSpeed(MOVE_RUN, 1.3f, true); + } + } + else + { + if (apply) + { + SetEscortPaused(false); + _aranasSaved = true; + me->SetSpeed(MOVE_WALK, 1.0f, true); + me->SetSpeed(MOVE_RUN, 1.3f, true); } else - _followCheckTimer -= diff; - } - - if (!UpdateVictim()) - { - me->GetCharmInfo()->SetIsFollowing(true); - me->SetReactState(REACT_DEFENSIVE); - - if (owner && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != FOLLOW_MOTION_TYPE) - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - - return; - } - - DoMeleeAttackIfReady(); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) OVERRIDE - { - if (spell->Id != SPELL_MASTIFF_ATTACK_LURKER) - return; - - target->RemoveAura(SPELL_LURKER_SHADOWSTALKER_STEALTH); - target->AddThreat(me, 1.0f); - me->AddThreat(target, 1.0f); - AttackStart(target); - } - - void JustDied(Unit* /*killer*/) OVERRIDE - { - me->DespawnOrUnsummon(1); - } - - void KilledUnit(Unit* /*victim*/) OVERRIDE - { - Reset(); - } - }; - - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_gilnean_mastiffAI(creature); - } -}; - -/*###### -## item_gilnean_mastiff_collar - commands the player's mastiff to reveal and -## attack the nearest Bloodfang Lurker. Handled entirely in script (returning -## true suppresses the native item-use spell cast) so this doesn't depend on -## any spell effect data at all. -######*/ - -class item_gilnean_mastiff_collar : public ItemScript -{ -public: - item_gilnean_mastiff_collar() : ItemScript("item_gilnean_mastiff_collar") { } - - bool OnUse(Player* player, Item* /*item*/, SpellCastTargets const& /*targets*/) OVERRIDE - { - Guardian* mastiff = player->GetGuardianPet(); - if (!mastiff || mastiff->GetEntry() != NPC_GILNEAN_MASTIFF) - return true; - - CAST_AI(npc_gilnean_mastiff::npc_gilnean_mastiffAI, mastiff->AI())->RevealNearbyLurker(); - return true; - } -}; - -/*###### -## npc_gilnean_mastiff_recall_trigger - invisible catch-all at the top of the -## cellar stairs; players on 14204 whose mastiff isn't nearby get a fresh one -## re-summoned here, working around the stairwell's broken navmesh -######*/ - -class npc_gilnean_mastiff_recall_trigger : public CreatureScript -{ -public: - npc_gilnean_mastiff_recall_trigger() : CreatureScript("npc_gilnean_mastiff_recall_trigger") { } - - struct npc_gilnean_mastiff_recall_triggerAI : public ScriptedAI - { - npc_gilnean_mastiff_recall_triggerAI(Creature* creature) : ScriptedAI(creature), _checkTimer(0) { } - - uint32 _checkTimer; - - void UpdateAI(uint32 diff) OVERRIDE - { - if (_checkTimer > diff) - { - _checkTimer -= diff; - return; - } - _checkTimer = 1000; - - std::list players; - Skyfire::AnyPlayerInObjectRangeCheck checker(me, 8.0f); - Skyfire::PlayerListSearcher searcher(me, players, checker); - me->VisitNearbyWorldObject(8.0f, searcher); - - for (Player* player : players) - { - if (player->GetQuestStatus(QUEST_FROM_THE_SHADOWS) != QUEST_STATUS_INCOMPLETE) - continue; - - Guardian* pet = player->GetGuardianPet(); - if (pet && player->GetDistance(pet) <= 20.0f) - continue; - - if (pet) - pet->DespawnOrUnsummon(1); - - player->CastSpell(player, SPELL_SUMMON_GILNEAN_MASTIFF, true); + me->DespawnOrUnsummon(1); } } - }; - CreatureAI* GetAI(Creature* creature) const OVERRIDE - { - return new npc_gilnean_mastiff_recall_triggerAI(creature); - } -}; - -/*###### -## npc_bloodfang_lurker - stealthed quest kill-target; ambushes a nearby idle -## player once it settles back near its home spot, and can enrage at low health -######*/ - -class npc_bloodfang_lurker : public CreatureScript -{ -public: - npc_bloodfang_lurker() : CreatureScript("npc_bloodfang_lurker") { } - - struct npc_bloodfang_lurkerAI : public ScriptedAI - { - npc_bloodfang_lurkerAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 _enrageTimer; - uint32 _seekTimer; - bool _willEnrage; - - void Reset() OVERRIDE + void WaypointReached(uint32 i) { - _enrageTimer = 0; - _willEnrage = BsohtRand(0, 1) != 0; - _seekTimer = BsohtRand(5000, 10000); - DoCast(me, SPELL_LURKER_SHADOWSTALKER_STEALTH); - } + Player* player = GetPlayerForEscort(); - void UpdateAI(uint32 diff) OVERRIDE - { - if (_seekTimer <= diff) + switch (i) { - if (me->IsAlive() && !me->IsInCombat() && me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) <= 2.0f) + case 1: + { + if (Unit* passenger = me->GetVehicleKit()->GetPassenger(0)) { - if (Player* player = me->SelectNearestPlayer(2.0f)) - { - if (!player->IsInCombat()) + if (Vehicle* vehicle = me->GetVehicleKit()) + if (Unit* passenger = vehicle->GetPassenger(0)) + if (Player* player = passenger->ToPlayer()) + player->SetClientControl(me, 0); + } + break; + } + case 17: + { + if (Unit* passenger = me->GetVehicleKit()->GetPassenger(0)) + { + if (Creature* aranas = passenger->FindNearestCreature(NPC_KRENNAN_ARANAS, 50.0f)) + if (Vehicle* vehicle = me->GetVehicleKit()) + if (Unit* passenger = vehicle->GetPassenger(0)) + if (Player* player = passenger->ToPlayer()) + aranas->AI()->Talk(TEXT_KRENNAN_ARANAS); + + me->GetMotionMaster()->MoveJump(-1673.04f, 1344.91f, 15.1353f, 25.0f, 15.0f); + + AddGilneasDelayedEvent(me, 2000, [this, passenger]() { - AttackStart(player); - _seekTimer = BsohtRand(5000, 10000); + Talk(EMOTE_SAVE_KRENNAN_ARANAS, passenger); + }); + } + break; + } + case 40: + { + if (Vehicle* vehicle = me->GetVehicleKit()) + { + if (Unit* passenger = vehicle->GetPassenger(0)) + { + if (Player* player = passenger->ToPlayer()) + { + std::list guards; + me->GetCreatureListWithEntryInGrid(guards, NPC_GILNEAS_CITY_GUARD, 90.0f); + + if (!guards.empty()) + for (std::list::const_iterator itr = guards.begin(); itr != guards.end(); ++itr) + if ((*itr)->IsAlive()) + if (Creature* worgen = (*itr)->FindNearestCreature(NPC_BLOODFANG_RIPPER, 90.0f)) + (*itr)->CastSpell(worgen, SPELL_GUARD_SHOOT, false); } } } + break; + } + case 41: + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->CombatStop(); + break; + } + case 42: + { + if (Vehicle* vehicle = me->GetVehicleKit()) + if (Unit* passenger = vehicle->GetPassenger(0)) + if (Player* player = passenger->ToPlayer()) + { + player->KilledMonsterCredit(NPC_KRENNAN_ARANAS_KILL_CREDIT, 0); + + if (Unit* passenger_2 = vehicle->GetPassenger(1)) + if (Creature* aranas = passenger_2->ToCreature()) + aranas->AI()->Talk(TEXT_SAVED_KRENNAN_ARANAS); + } + break; + } + case 44: + { + if (Unit* passenger = me->GetVehicleKit()->GetPassenger(0)) + { + if (Vehicle* vehicle = me->GetVehicleKit()) + { + if (Unit* passenger = vehicle->GetPassenger(0)) + if (Player* player = passenger->ToPlayer()) + player->SetClientControl(me, 1); + + if (Unit* passenger = vehicle->GetPassenger(1)) + if (Creature* aranas = passenger->ToCreature()) + aranas->DespawnOrUnsummon(); + + vehicle->RemoveAllPassengers(); + } + } + me->DespawnOrUnsummon(1); + break; + } + } + } + + void OnCharmed(bool /*apply*/) { } + + void UpdateAI(uint32 diff) override + { + npc_escortAI::UpdateAI(diff); + Player* player = GetPlayerForEscort(); + + if (_playerSeated) + { + player->SetClientControl(me, 0); + _playerSeated = false; + } + } + }; +}; + +struct npc_saved_aranas : public ScriptedAI +{ + npc_saved_aranas(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (me->IsSummon()) + { + if (Creature* horse = me->FindNearestCreature(NPC_KING_GREYMANES_HORSE, 20.0f)) + DoCast(horse, 84275, true); + + if (Creature* aranas = me->FindNearestCreature(NPC_KRENNAN_ARANAS, 50.0f)) + aranas->DespawnOrUnsummon(); + } + } +}; + +class npc_gilneas_children : public CreatureScript +{ +public: + npc_gilneas_children(const char* scriptName, uint32 spellId, uint8 playerSayId) : CreatureScript(scriptName), _spellId(spellId), _playerSayId(playerSayId) { } + +private: + uint32 _spellId; + uint8 _playerSayId; + + CreatureAI* GetAI(Creature* creature) const override + { + return new creature_script(creature, _spellId, _playerSayId); + } + + struct creature_script : public ScriptedAI + { + creature_script(Creature* creature, uint32 spellId, uint8 playerSayId) : ScriptedAI(creature), _spellId(spellId), _playerSayId(playerSayId) { } + + EventMap events; + ObjectGuid playerGUID; + uint32 _spellId; + uint8 _playerSayId; + bool activated; + + void Reset() override + { + events.Reset(); + playerGUID = 0; + activated = false; + me->SetFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + + if (me->GetEntry() == NPC_CYNTHIA) + events.ScheduleEvent(EVENT_CRY, 1000); + } + + void SpellHit(Unit* caster, const SpellInfo* spell) + { + if (!activated && spell->Id == _spellId) + { + if (Player* player = caster->ToPlayer()) + { + activated = true; + playerGUID = player->GetGUID(); + player->Say(PlayerText[_playerSayId], Language::LANG_UNIVERSAL); + player->KilledMonsterCredit(me->GetEntry(), 0); + me->RemoveFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + events.ScheduleEvent(EVENT_TALK_TO_PLAYER, 3500); + } + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + if (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TALK_TO_PLAYER: + { + events.CancelEvent(EVENT_CRY); + + if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID)) + Talk(CHILDREN_TEXT_ID, player); + + events.ScheduleEvent(EVENT_START_RUN, 5000); + } + break; + case EVENT_START_RUN: + { + switch (me->GetEntry()) + { + case NPC_JAMES: + MoveGilneasPointPath(me, 0, JamesPath[0], JamesPathLenght); + break; + case NPC_CYNTHIA: + MoveGilneasPointPath(me, 0, CynthiaPath[0], CynthiaPathLenght); + break; + case NPC_ASHLEY: + MoveGilneasPointPath(me, 0, AshleyPath[0], AshleyPathLenght); + break; + default: + return; + } + + events.ScheduleEvent(EVENT_OPEN_DOOR, 5000); + } + break; + case EVENT_OPEN_DOOR: + { + if (GameObject* door = me->FindNearestGameObject(GO_DOOR_TO_THE_BASEMENT, 10.0f)) + { + if (door->GetGoState() == GOState::GO_STATE_READY) + { + door->UseDoorOrButton(); + events.ScheduleEvent(EVENT_RESUME_RUN, 2000); + } + else + events.ScheduleEvent(EVENT_RESUME_RUN, 0); + } + } + break; + case EVENT_RESUME_RUN: + MoveGilneasPointPath(me, 0, childrenBasementPath[0], childrenBasementPathLenght); + me->DespawnOrUnsummon(5000); + break; + case EVENT_CRY: + me->HandleEmoteCommand(EMOTE_ONESHOT_CRY); + events.ScheduleEvent(EVENT_CRY, urand(1000, 1500)); + break; + } + } + } + }; +}; + +class npc_wahl : public CreatureScript +{ +public: + npc_wahl(const char* ScriptName) : CreatureScript(ScriptName) { } + + struct npc_wahlAI : public npc_escortAI + { + npc_wahlAI(Creature* creature) : npc_escortAI(creature) + { + creature->SetReactState(REACT_PASSIVE); + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); + } + + void DoAction(int32 const action) override + { + if (action == ACTION_CONTINUE_SCENE) + { + AddGilneasDelayedEvent(me, 4000, [this]() + { + SetEscortPaused(false); + }); + } + } + + void WaypointReached(uint32 point) + { + if (point == 1) + if (me->IsSummon()) + if (Unit* summoner = me->ToTempSummon()->GetSummoner()) + { + SetEscortPaused(true); + me->SetDisplayId(NPC_WAHL_WORGEN); + Talk(YELL_DONT_MESS); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); + + AddGilneasDelayedEvent(me, 800, [this, summoner]() + { + AttackStart(summoner); + }); + } + } + + void UpdateAI(uint32 diff) override + { + npc_escortAI::UpdateAI(diff); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_wahlAI(creature); + } +}; + +class npc_lucius_the_cruel : public CreatureScript +{ +public: + npc_lucius_the_cruel(const char* ScriptName) : CreatureScript(ScriptName) { } + + struct npc_lucius_the_cruelAI : public ScriptedAI + { + npc_lucius_the_cruelAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + Catch = false; + Summon = false; + uiCatchTimer = 1000; + uiShootTimer = 500; + uiPlayerGUID = 0; + uiSummonTimer = 1500; + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); + } + + ObjectGuid uiPlayerGUID; + uint32 uiCatchTimer; + uint32 uiShootTimer; + uint32 uiSummonTimer; + bool Catch; + bool Summon; + + void EnterEvadeMode() override + { + me->DespawnOrUnsummon(); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* wahl = me->FindNearestCreature(NPC_WAHL, 30.f)) + wahl->AI()->DoAction(ACTION_CONTINUE_SCENE); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (id == POINT_CATCH_CHANCE) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + + if (me->IsSummon()) + if (Unit* summoner = me->ToTempSummon()->GetSummoner()) + if (Creature* chance = summoner->ToCreature()) + { + AddGilneasDelayedEvent(me, 4000, [this, chance]() + { + Catch = true; + Summon = true; + chance->AI()->DoAction(ACTION_CHANCE_DESPAWN); + }); + } + } + } + + void DoAction(int32 const action) override + { + if (action == ACTION_SUMMON_LUCIUS) + { + me->GetMotionMaster()->MovePoint(POINT_CATCH_CHANCE, -2106.372f, 2331.106f, 7.360674f); + + AddGilneasDelayedEvent(me, 1000, [this]() + { + Talk(SAY_THIS_CAT_IS_MINE); + }); + } + } + + void UpdateAI(uint32 diff) override + { + if (Catch) + { + if (uiCatchTimer <= diff) + { + Catch = false; + uiCatchTimer = 1000; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); + me->SetReactState(REACT_AGGRESSIVE); + + if (Player* player = Unit::GetPlayer(*me, uiPlayerGUID)) + AttackStart(player); + } + else + uiCatchTimer -= diff; + } + + if (Summon) + { + if (uiSummonTimer <= diff) + { + Summon = false; + uiSummonTimer = 1500; + + if (Creature* wahl = me->SummonCreature(NPC_WAHL, -2098.366f, 2352.075f, 7.160643f)) + { + if (npc_escortAI* npc_escort = CAST_AI(npc_wahl::npc_wahlAI, wahl->AI())) + { + npc_escort->AddWaypoint(0, -2106.54f, 2342.69f, 6.93668f); + npc_escort->AddWaypoint(1, -2106.12f, 2334.90f, 7.36691f); + npc_escort->AddWaypoint(2, -2117.80f, 2357.15f, 5.88139f); + npc_escort->AddWaypoint(3, -2111.46f, 2366.22f, 7.17151f); + npc_escort->Start(false, true); + } + } + } + else + uiSummonTimer -= diff; } - else - _seekTimer -= diff; if (!UpdateVictim()) return; - if (_enrageTimer <= diff) + if (uiShootTimer <= diff) { - if (_willEnrage && me->GetHealthPct() <= 30.0f) - { - DoCast(me, SPELL_LURKER_ENRAGE); - _enrageTimer = CD_LURKER_ENRAGE; - } + uiShootTimer = 1000; + + if (me->GetDistance(me->GetVictim()) > 2.0f) + DoCastVictim(SPELL_LUCIUS_SHOOT); } else - _enrageTimer -= diff; + uiShootTimer -= diff; DoMeleeAttackIfReady(); } }; - CreatureAI* GetAI(Creature* creature) const OVERRIDE + CreatureAI* GetAI(Creature* creature) const override { - return new npc_bloodfang_lurkerAI(creature); + return new npc_lucius_the_cruelAI(creature); + } +}; + +struct npc_chance_the_cat : public ScriptedAI +{ + npc_chance_the_cat(Creature* creature) : ScriptedAI(creature) + { + Despawn = false; + uiDespawnTimer = 500; + } + + uint32 uiDespawnTimer; + bool Despawn; + + void DoAction(int32 const action) override + { + if (action == ACTION_CHANCE_DESPAWN) + Despawn = true; + } + + void SpellHit(Unit* caster, const SpellInfo* spell) override + { + if (spell->Id == SPELL_CATCH_CAT && caster->GetTypeId() == TypeID::TYPEID_PLAYER) + { + me->RemoveFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + + if (Creature* lucius = me->SummonCreature(NPC_LUCIUS_THE_CRUEL, -2111.533f, 2329.95f, 7.390349f)) + { + lucius->AI()->DoAction(ACTION_SUMMON_LUCIUS); + CAST_AI(npc_lucius_the_cruel::npc_lucius_the_cruelAI, lucius->AI())->uiPlayerGUID = caster->GetGUID(); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (Despawn) + { + if (uiDespawnTimer <= diff) + { + uiDespawnTimer = 500; + Despawn = false; + me->DespawnOrUnsummon(); + } + else + uiDespawnTimer -= diff; + } + } +}; + +class npc_mountain_horse : public CreatureScript +{ +public: + npc_mountain_horse(const char* ScriptName) : CreatureScript(ScriptName) { } + + bool OnGossipHello(Player* player, Creature* creature) + { + if (player->GetQuestStatus(QUEST_THE_HUNGRY_ETTIN) == QUEST_STATUS_INCOMPLETE) + { + player->EnterVehicle(creature, 0); + creature->RemoveFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + creature->GetMotionMaster()->Clear(); + return true; + } + return true; + } + + struct npc_mountain_horseAI : public ScriptedAI + { + npc_mountain_horseAI(Creature* creature) : ScriptedAI(creature) { } + + EventMap events; + + void Reset() override + { + if (!me->GetVehicleKit()->GetPassenger(0)) + me->GetMotionMaster()->MoveRandom(8.0f); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) + { + switch (spell->Id) + { + case SPELL_ROUND_UP_HORSE: + { + if (me->GetVehicleKit()->GetPassenger(0)) + break; + + me->DespawnOrUnsummon(1); + break; + } + default: + break; + } + } + + void PassengerBoarded(Unit* /*passenger*/, int8 /*SeatId*/, bool apply) + { + if (!apply) + { + me->SetFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->SetWalk(true); + me->AI()->EnterEvadeMode(); + } + } + + void OnCharmed(bool apply) { } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_mountain_horseAI(creature); + } +}; + +struct npc_mountain_horse_summoned : public ScriptedAI +{ + npc_mountain_horse_summoned(Creature* creature) : ScriptedAI(creature) { } + + EventMap events; + + void IsSummonedBy(Unit* summoner) override + { + me->GetMotionMaster()->MoveFollow(summoner, 6.0f, 0); + me->CastSpell(summoner, SPELL_ROPE_CHANNEL, true); + me->ClearUnitState(UNIT_STATE_CASTING); + events.ScheduleEvent(EVENT_CHECK_LORNA, 2000); + events.ScheduleEvent(EVENT_CHECK_OWNER, 2000); + me->SetWalk(false); + me->SetSpeed(MOVE_RUN, 2.0f, true); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CHECK_LORNA: + { + if (Creature* lornaCrowley = me->FindNearestCreature(NPC_LORNA_CROWLEY_2, 8.0f, true)) + { + if (Unit* owner = me->GetCharmerOrOwner()) + { + if (owner->GetTypeId() == TypeID::TYPEID_PLAYER) + owner->ToPlayer()->KilledMonsterCredit(QUEST_CREDIT_HORSE); + } + events.CancelEvent(EVENT_CHECK_LORNA); + me->DespawnOrUnsummon(1); + } + else + events.RescheduleEvent(EVENT_CHECK_LORNA, 2000); + break; + } + case EVENT_CHECK_OWNER: + { + if (Unit* owner = me->GetCharmerOrOwner()) + { + if (!owner->IsAlive() || !owner->IsInWorld() || !owner->GetVehicleBase()) + me->DespawnOrUnsummon(1); + + events.CancelEvent(EVENT_CHECK_OWNER); + } + else + events.RescheduleEvent(EVENT_CHECK_OWNER, 2000); + break; + } + default: + break; + } + } + } +}; + +class spell_gilneas_test_telescope : public SpellScript +{ + PrepareSpellScript(spell_gilneas_test_telescope); + + void StartCinematic() + { + if (Unit* caster = GetCaster()) + { + if (caster->GetTypeId() == TypeID::TYPEID_PLAYER) + { + caster->PlayDirectSound(MUSIC_ENTRY_TELESCOPE, caster->ToPlayer()); + caster->ToPlayer()->SendCinematicStart(PLAY_CINEMATIC_TELESCOPE); + } + } + } + + void Register() override + { + AfterHit += SpellHitFn(spell_gilneas_test_telescope::StartCinematic); + } +}; + +class npc_stagecoach_carriage_exodus : public CreatureScript +{ +public: + npc_stagecoach_carriage_exodus(const char* ScriptName) : CreatureScript(ScriptName) { } + + bool OnGossipHello(Player* player, Creature* creature) + { + if (player->GetQuestStatus(QUEST_ENTRY_EXODUS) == QUEST_STATUS_COMPLETE) + { + if (player->GetVehicleBase()) + return true; + + if (Creature* harness = player->FindNearestCreature(NPC_STAGECOACH_HARNESS, 30.0f, true)) + { + Position summonPos(harness->GetPositionX(), harness->GetPositionY(), harness->GetPositionZ(), harness->GetOrientation()); + player->GetMap()->SummonCreature(NPC_HARNESS_SUMMONED, summonPos, sSummonPropertiesStore.LookupEntry(3105), 600000, player); + } + return true; + } + + return true; + } + + struct npc_stagecoach_carriage_exodusAI : public ScriptedAI + { + npc_stagecoach_carriage_exodusAI(Creature* creature) : ScriptedAI(creature) + { + events.ScheduleEvent(EVENT_BOARD_HARNESS_OWNER, 1); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); + } + + EventMap events; + + void UpdateAI(uint32 diff) + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BOARD_HARNESS_OWNER: + { + if (Unit* harness = me->GetVehicleCreatureBase()) + { + if (Unit* harnessOwner = harness->ToTempSummon()->GetSummoner()) + { + if (harnessOwner->IsAlive() && harnessOwner->IsInWorld()) + { + harnessOwner->EnterVehicle(me, 1); + events.CancelEvent(EVENT_BOARD_HARNESS_OWNER); + break; + } + } + } + events.CancelEvent(EVENT_BOARD_HARNESS_OWNER); + break; + } + default: + break; + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_stagecoach_carriage_exodusAI(creature); + } +}; + +class npc_stagecoach_harness : public CreatureScript +{ +public: + npc_stagecoach_harness(const char* ScriptName) : CreatureScript(ScriptName) { } + + struct npc_stagecoach_harnessAI : public npc_escortAI + { + npc_stagecoach_harnessAI(Creature* creature) : npc_escortAI(creature) { } + + void OnCharmed(bool apply) { } + + void IsSummonedBy(Unit* owner) + { + DoAction(ACTION_START_WP); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); + } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_START_WP: + { + Start(false, true, NULL, NULL, false, false, true); + SetDespawnAtEnd(true); + + if (GameObject* gate = me->FindNearestGameObject(GO_FIRST_GATE, 80.0f)) + gate->UseDoorOrButton(0, false, me); + + me->SetWalk(false); + me->SetSpeed(MOVE_RUN, 1.34f, true); + break; + } + default: + break; + } + } + + void WaypointReached(uint32 point) override + { + switch (point) + { + case 16: + { + if (GameObject* gate = me->FindNearestGameObject(GO_KINGS_GATE, 80.0f)) + gate->UseDoorOrButton(0, false, me); + break; + } + case 24: + { + if (Unit* caravan = me->GetVehicleKit()->GetPassenger(2)) + { + if (Unit* lorna = caravan->GetVehicleKit()->GetPassenger(6)) + { + if (lorna->ToCreature()) + lorna->ToCreature()->AI()->Talk(0); + } + } + break; + } + case 30: + { + if (Unit* caravan = me->GetVehicleKit()->GetPassenger(2)) + { + if (Unit* player = caravan->GetVehicleKit()->GetPassenger(1)) + player->ExitVehicle(); + } + break; + } + default: + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_stagecoach_harnessAI(creature); + } +}; + +enum eZoneGilneas +{ + NPC_WORGEN_ALPHA_C2 = 35167, + NPC_WORGEN_ALPHA_C1 = 35170, + NPC_WORGEN_RUNT_C1 = 35188, + NPC_WORGEN_RUNT_C2 = 35456, + + SPELL_BY_THE_SKIN = 66914, + SPELL_ENRAGE_8599 = 8599, + SPELL_GILNEAS_PRISON_PERIODIC_1 = 66894, + SPELL_GILNEAS_PRISON_PERIODIC_2 = 68218, +}; + +/* 35077 - QUEST: 14154 - By The Skin of His Teeth - START */ +class npc_lord_darius_crowley_35077 : public CreatureScript +{ +public: + npc_lord_darius_crowley_35077() : CreatureScript("npc_lord_darius_crowley_35077") { } + + enum eNpc + { + ACTION_START_EVENT = 101, + }; + + bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) override + { + if (quest->GetQuestId() == 14154) + if (CAST_AI(npc_lord_darius_crowley_35077AI, creature->AI())->m_playerGUID == 0) + { + creature->AI()->SetGUID(player->GetGUID()); + creature->AI()->DoAction(ACTION_START_EVENT); + creature->CastSpell(player, SPELL_BY_THE_SKIN, true); + } + return true; + } + + struct npc_lord_darius_crowley_35077AI : public ScriptedAI + { + npc_lord_darius_crowley_35077AI(Creature* creature) : ScriptedAI(creature), m_summons(me) { Init(); } + + enum eQ14154 + { + Event120Secounds = 1, + EventCheckPlayerIsAlive, + EventSummonNextWave, + EventHelpPlayer, + }; + + ObjectGuid m_playerGUID; + EventMap m_events; + SummonList m_summons; + uint32 m_phase; + + void Init() + { + m_events.Reset(); + m_summons.DespawnAll(); + m_playerGUID = 0; + m_phase = 0; + } + + void JustSummoned(Creature* summoned) override + { + m_summons.Summon(summoned); + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + m_summons.Despawn(summon); + } + + void DoAction(int32 /*action*/) override + { + m_phase = 1; + m_events.ScheduleEvent(EventCheckPlayerIsAlive, 1000); + m_events.ScheduleEvent(EventSummonNextWave, 1000); + m_events.ScheduleEvent(Event120Secounds, 120000); + m_events.ScheduleEvent(EventHelpPlayer, 250); + } + + void SetGUID(uint64 guid, int32 /*type = 0*/) override + { + m_playerGUID = guid; + } + + void DamageTaken(Unit* attacker, uint32& /*damage*/) override + { + if (/*Creature* worgen = */attacker->ToCreature()) + if (!me->IsInCombat()) + { + //me->Attack(worgen, true); + } + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + while (uint32 eventId = m_events.ExecuteEvent()) + { + switch (eventId) + { + case Event120Secounds: + Init(); + break; + case EventCheckPlayerIsAlive: // check every sec player is alive + if (!m_playerGUID == 0 && m_phase) + if (Player* player = ObjectAccessor::GetPlayer(*me, m_playerGUID)) + if (!player->IsInWorld() || !player->IsAlive()) + Init(); + + m_events.ScheduleEvent(EventCheckPlayerIsAlive, 1000); + break; + case EventSummonNextWave: + { + for (int i = 0; i < 4; i++) + { + // Entry 35456 is used by the prison periodic wave handler, so keep + // the Darius event on entries that use the Darius wave movement AI. + uint32 w1 = RAND(NPC_WORGEN_RUNT_C1, NPC_WORGEN_ALPHA_C1, NPC_WORGEN_ALPHA_C2); + uint32 w2 = RAND(NPC_WORGEN_RUNT_C1, NPC_WORGEN_ALPHA_C1, NPC_WORGEN_ALPHA_C2); + + if (Creature* creature1 = me->SummonCreature(w1, -1610.39f, 1507.16f, 74.99f, 3.94f, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 120000)) + { + m_summons.Summon(creature1); + creature1->AI()->SetGUID(m_playerGUID); + creature1->AI()->DoAction(1); + } + + if (Creature* creature2 = me->SummonCreature(w2, -1718.01f, 1516.81f, 55.40f, 4.6f, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 120000)) + { + m_summons.Summon(creature2); + creature2->AI()->SetGUID(m_playerGUID); + creature2->AI()->DoAction(2); + } + } + + m_events.ScheduleEvent(EventSummonNextWave, 30000); // every 30 secounds one wave + break; + } + case EventHelpPlayer: + { + if (!me->IsInCombat()) + { + Creature* creature = nullptr; + creature = me->FindNearestCreature(NPC_WORGEN_RUNT_C1, 5.0f); + if (!creature) + creature = me->FindNearestCreature(NPC_WORGEN_RUNT_C2, 5.0f); + if (!creature) + creature = me->FindNearestCreature(NPC_WORGEN_ALPHA_C1, 5.0f); + if (!creature) + creature = me->FindNearestCreature(NPC_WORGEN_ALPHA_C2, 5.0f); + if (creature) + { + me->Attack(creature, true); + // creature->Attack(me, true); + } + } + + m_events.ScheduleEvent(EventHelpPlayer, 250); + break; + } + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_lord_darius_crowley_35077AI(creature); + } +}; + +// 35124 +class npc_tobias_mistmantle_35124 : public CreatureScript +{ +public: + npc_tobias_mistmantle_35124() : CreatureScript("npc_tobias_mistmantle_35124") { } + + struct npc_tobias_mistmantle_35124AI : public ScriptedAI + { + npc_tobias_mistmantle_35124AI(Creature* creature) : ScriptedAI(creature) { } + + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_tobias_mistmantle_35124AI(creature); + } +}; + +// 35188 +class npc_worgen_runt_35188 : public CreatureScript +{ +public: + npc_worgen_runt_35188() : CreatureScript("npc_worgen_runt_35188") {} + + struct npc_worgen_runt_35188AI : public ScriptedAI + { + npc_worgen_runt_35188AI(Creature* creature) : ScriptedAI(creature) { Init(); } + + ObjectGuid m_playerGUID; + EventMap m_events; + uint32 m_phase; + Position jump; + Position JumpW1[3]; + Position LandingW1[3]; + Position LandingW2[4]; + + void Init() + { + m_phase = 0; + JumpW1[0] = Position{ -1643.91f, 1482.96f, 63.22f, 3.95f }; + JumpW1[1] = Position{ -1638.83f, 1478.07f, 65.36f, 3.84f }; + JumpW1[2] = Position{ -1631.49f, 1475.02f, 65.64f, 3.84f }; + + LandingW1[0] = Position{ -1677.39f, 1455.52f, 52.29f, 4.06f }; + LandingW1[1] = Position{ -1671.89f, 1449.27f, 52.29f, 3.84f }; + LandingW1[2] = Position{ -1664.82f, 1443.62f, 52.29f, 3.84f }; + + LandingW2[0] = Position{ -1704.93f, 1469.07f, 52.29f, 5.34f }; + LandingW2[1] = Position{ -1698.90f, 1472.92f, 52.29f, 5.41f }; + LandingW2[2] = Position{ -1703.37f, 1470.66f, 52.29f, 5.49f }; + LandingW2[3] = Position{ -1700.37f, 1473.32f, 52.29f, 5.41f }; + } + + void DoAction(int32 action) override + { + if (!m_playerGUID == 0) + { + m_events.ScheduleEvent(1, 500); + m_phase = action; + me->SetSpeed(MOVE_RUN, frand(1.2f, 1.6f)); + } + } + + void SetGUID(uint64 guid, int32 /*type*/) override + { + m_playerGUID = guid; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE) + m_phase = pointId; + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + uint32 eventId = m_events.ExecuteEvent(); + switch (eventId) + { + case 1: + { + m_events.ScheduleEvent(1, 500); + DoWalk(); + break; + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void DoWalk() + { + switch (m_phase) + { + case 1: + { + m_phase = 3; + uint8 rol = urand(0, 2); + jump = JumpW1[rol]; + me->GetMotionMaster()->MovePoint(11 + rol, jump); + break; + } + case 2: + m_phase = 3; + jump = Position{ -1717.73f, 1486.27f, 57.23f, 5.45f }; + me->GetMotionMaster()->MovePoint(21, jump); + break; + case 11: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[0], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 12: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[1], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 13: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[2], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 21: + { + m_phase = 5; + uint8 rol = urand(0, 3); + jump = LandingW2[rol]; + me->GetMotionMaster()->MoveJump(jump, frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + } + case 25: + m_phase = 6; + if (!m_playerGUID == 0) + if (Player* player = ObjectAccessor::GetPlayer(*me, m_playerGUID)) + if (player->IsInWorld() || player->IsAlive()) + { + Position pos; + player->GetNearPosition(pos, frand(2.0f, 4.0f), frand(3.14f, 6.28f)); + me->GetMotionMaster()->MovePoint(26, pos); + } + break; + case 26: + m_phase = 7; + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_worgen_runt_35188AI(creature); + } +}; + +// 35456 +class npc_worgen_runt_35456 : public CreatureScript +{ +public: + npc_worgen_runt_35456() : CreatureScript("npc_worgen_runt_35456") { } + + struct npc_worgen_runt_35456AI : public ScriptedAI + { + npc_worgen_runt_35456AI(Creature* creature) : ScriptedAI(creature) { Init(); } + + ObjectGuid m_playerGUID; + EventMap m_events; + uint32 m_phase; + Position jump; + Position JumpW1[3]; + Position LandingW1[3]; + Position LandingW2[4]; + + void Init() + { + m_phase = 0; + JumpW1[0] = Position{ -1643.91f, 1482.96f, 63.22f, 3.95f }; + JumpW1[1] = Position{ -1638.83f, 1478.07f, 65.36f, 3.84f }; + JumpW1[2] = Position{ -1631.49f, 1475.02f, 65.64f, 3.84f }; + + LandingW1[0] = Position{ -1677.39f, 1455.52f, 52.29f, 4.06f }; + LandingW1[1] = Position{ -1671.89f, 1449.27f, 52.29f, 3.84f }; + LandingW1[2] = Position{ -1664.82f, 1443.62f, 52.29f, 3.84f }; + + LandingW2[0] = Position{ -1704.93f, 1469.07f, 52.29f, 5.34f }; + LandingW2[1] = Position{ -1698.90f, 1472.92f, 52.29f, 5.41f }; + LandingW2[2] = Position{ -1703.37f, 1470.66f, 52.29f, 5.49f }; + LandingW2[3] = Position{ -1700.37f, 1473.32f, 52.29f, 5.41f }; + } + + void DoAction(int32 action) override + { + if (!m_playerGUID == 0) + { + m_events.ScheduleEvent(1, 500); + m_phase = action; + me->SetSpeed(MOVE_RUN, frand(1.2f, 1.6f)); + } + } + + void SetGUID(uint64 guid, int32 /*type*/) override + { + m_playerGUID = guid; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE) + m_phase = pointId; + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + uint32 eventId = m_events.ExecuteEvent(); + switch (eventId) + { + case 1: + { + m_events.ScheduleEvent(1, 500); + DoWalk(); + break; + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void DoWalk() + { + switch (m_phase) + { + case 1: + { + m_phase = 3; + uint8 rol = urand(0, 2); + jump = JumpW1[rol]; + me->GetMotionMaster()->MovePoint(11 + rol, jump); + break; + } + case 2: + m_phase = 3; + jump = Position{ -1717.73f, 1486.27f, 57.23f, 5.45f }; + me->GetMotionMaster()->MovePoint(21, jump); + break; + case 11: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[0], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 12: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[1], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 13: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[2], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 21: + { + m_phase = 5; + uint8 rol = urand(0, 3); + jump = LandingW2[rol]; + me->GetMotionMaster()->MoveJump(jump, frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + } + case 25: + m_phase = 6; + if (!m_playerGUID == 0) + if (Player* player = ObjectAccessor::GetPlayer(*me, m_playerGUID)) + if (player->IsInWorld() || player->IsAlive()) + { + Position pos; + player->GetNearPosition(pos, frand(2.0f, 4.0f), frand(3.14f, 6.28f)); + me->GetMotionMaster()->MovePoint(26, pos); + } + break; + case 26: + m_phase = 7; + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_worgen_runt_35456AI(creature); + } +}; + +// 35170 +class npc_worgen_alpha_35170 : public CreatureScript +{ +public: + npc_worgen_alpha_35170() : CreatureScript("npc_worgen_alpha_35170") {} + + struct npc_worgen_alpha_35170AI : public ScriptedAI + { + npc_worgen_alpha_35170AI(Creature* creature) : ScriptedAI(creature) { Init(); } + + ObjectGuid m_playerGUID; + EventMap m_events; + uint32 m_phase; + Position jump; + Position JumpW1[3]; + Position LandingW1[3]; + Position LandingW2[4]; + + void Init() + { + m_phase = 0; + JumpW1[0] = Position{ -1643.91f, 1482.96f, 63.22f, 3.95f }; + JumpW1[1] = Position{ -1638.83f, 1478.07f, 65.36f, 3.84f }; + JumpW1[2] = Position{ -1631.49f, 1475.02f, 65.64f, 3.84f }; + + LandingW1[0] = Position{ -1677.39f, 1455.52f, 52.29f, 4.06f }; + LandingW1[1] = Position{ -1671.89f, 1449.27f, 52.29f, 3.84f }; + LandingW1[2] = Position{ -1664.82f, 1443.62f, 52.29f, 3.84f }; + + LandingW2[0] = Position{ -1704.93f, 1469.07f, 52.29f, 5.34f }; + LandingW2[1] = Position{ -1698.90f, 1472.92f, 52.29f, 5.41f }; + LandingW2[2] = Position{ -1703.37f, 1470.66f, 52.29f, 5.49f }; + LandingW2[3] = Position{ -1700.37f, 1473.32f, 52.29f, 5.41f }; + } + + void DoAction(int32 action) override + { + if (!m_playerGUID == 0) + { + m_events.ScheduleEvent(1, 500); + m_phase = action; + me->SetSpeed(MOVE_RUN, frand(1.2f, 1.6f)); + } + } + + void SetGUID(uint64 guid, int32 /*type*/) override + { + m_playerGUID = guid; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE) + m_phase = pointId; + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + uint32 eventId = m_events.ExecuteEvent(); + switch (eventId) + { + case 1: + { + m_events.ScheduleEvent(1, 500); + DoWalk(); + break; + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void DoWalk() + { + switch (m_phase) + { + case 1: + { + m_phase = 3; + uint8 rol = urand(0, 2); + jump = JumpW1[rol]; + me->GetMotionMaster()->MovePoint(11 + rol, jump); + break; + } + case 2: + m_phase = 3; + jump = Position{ -1717.73f, 1486.27f, 57.23f, 5.45f }; + me->GetMotionMaster()->MovePoint(21, jump); + break; + case 11: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[0], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 12: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[1], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 13: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[2], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 21: + { + m_phase = 5; + uint8 rol = urand(0, 3); + jump = LandingW2[rol]; + me->GetMotionMaster()->MoveJump(jump, frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + } + case 25: + m_phase = 6; + if (!m_playerGUID == 0) + if (Player* player = ObjectAccessor::GetPlayer(*me, m_playerGUID)) + if (player->IsInWorld() || player->IsAlive()) + { + Position pos; + player->GetNearPosition(pos, frand(2.0f, 4.0f), frand(3.14f, 6.28f)); + me->GetMotionMaster()->MovePoint(26, pos); + } + break; + case 26: + m_phase = 7; + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_worgen_alpha_35170AI(creature); + } +}; + +// 35167 +class npc_worgen_alpha_35167 : public CreatureScript +{ +public: + npc_worgen_alpha_35167() : CreatureScript("npc_worgen_alpha_35167") {} + + struct npc_worgen_alpha_35167AI : public ScriptedAI + { + npc_worgen_alpha_35167AI(Creature* creature) : ScriptedAI(creature) { Init(); } + + ObjectGuid m_playerGUID; + EventMap m_events; + uint32 m_phase; + Position jump; + Position JumpW1[3]; + Position LandingW1[3]; + Position LandingW2[4]; + + void Init() + { + m_phase = 0; + JumpW1[0] = Position{ -1643.91f, 1482.96f, 63.22f, 3.95f }; + JumpW1[1] = Position{ -1638.83f, 1478.07f, 65.36f, 3.84f }; + JumpW1[2] = Position{ -1631.49f, 1475.02f, 65.64f, 3.84f }; + + LandingW1[0] = Position{ -1677.39f, 1455.52f, 52.29f, 4.06f }; + LandingW1[1] = Position{ -1671.89f, 1449.27f, 52.29f, 3.84f }; + LandingW1[2] = Position{ -1664.82f, 1443.62f, 52.29f, 3.84f }; + + LandingW2[0] = Position{ -1704.93f, 1469.07f, 52.29f, 5.34f }; + LandingW2[1] = Position{ -1698.90f, 1472.92f, 52.29f, 5.41f }; + LandingW2[2] = Position{ -1703.37f, 1470.66f, 52.29f, 5.49f }; + LandingW2[3] = Position{ -1700.37f, 1473.32f, 52.29f, 5.41f }; + } + + void DoAction(int32 action) override + { + if (!m_playerGUID == 0) + { + m_events.ScheduleEvent(1, 500); + m_phase = action; + me->SetSpeed(MOVE_RUN, frand(1.2f, 1.6f)); + } + } + + void SetGUID(uint64 guid, int32 /*type = 0*/) override + { + m_playerGUID = guid; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE) + m_phase = pointId; + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + uint32 eventId = m_events.ExecuteEvent(); + switch (eventId) + { + case 1: + { + m_events.ScheduleEvent(1, 500); + DoWalk(); + break; + } + } + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + void DoWalk() + { + switch (m_phase) + { + case 1: + { + m_phase = 3; + uint8 rol = urand(0, 2); + jump = JumpW1[rol]; + me->GetMotionMaster()->MovePoint(11 + rol, jump); + break; + } + case 2: + m_phase = 3; + jump = Position{ -1717.73f, 1486.27f, 57.23f, 5.45f }; + me->GetMotionMaster()->MovePoint(21, jump); + break; + case 11: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[0], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 12: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[1], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 13: + m_phase = 4; + me->GetMotionMaster()->MoveJump(LandingW1[2], frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + case 21: + { + m_phase = 5; + uint8 rol = urand(0, 3); + jump = LandingW2[rol]; + me->GetMotionMaster()->MoveJump(jump, frand(20.0f, 25.0f), frand(15.0f, 20.0f), 25); + break; + } + case 25: + m_phase = 6; + if (!m_playerGUID == 0) + if (Player* player = ObjectAccessor::GetPlayer(*me, m_playerGUID)) + if (player->IsInWorld() || player->IsAlive()) + { + Position pos; + player->GetNearPosition(pos, frand(2.0f, 4.0f), frand(3.14f, 6.28f)); + me->GetMotionMaster()->MovePoint(26, pos); + } + break; + case 26: + m_phase = 7; + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_worgen_alpha_35167AI(creature); + } +}; + +// 35112 +class npc_king_genn_greymane_35112 : public CreatureScript +{ +public: + npc_king_genn_greymane_35112() : CreatureScript("npc_king_genn_greymane_35112") { } + + struct npc_king_genn_greymane_35112AI : public ScriptedAI + { + npc_king_genn_greymane_35112AI(Creature* creature) : ScriptedAI(creature) {} + + void Reset() override + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_king_genn_greymane_35112AI(creature); + } +}; + +// 35115 +class npc_lord_godfrey_35115 : public CreatureScript +{ +public: + npc_lord_godfrey_35115() : CreatureScript("npc_lord_godfrey_35115") { } + + struct npc_lord_godfrey_35115AI : public ScriptedAI + { + npc_lord_godfrey_35115AI(Creature* creature) : ScriptedAI(creature) {} + + void Reset() override + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_lord_godfrey_35115AI(creature); + } +}; + +// 35118 showfight <> guard 34916 +class npc_bloodfang_worgen_35118 : public CreatureScript +{ +public: + npc_bloodfang_worgen_35118() : CreatureScript("npc_bloodfang_worgen_35118") {} + + enum eNpc + { + EVENT_ENRAGE_COOLDOWN = 101, + }; + + struct npc_bloodfang_worgen_35118AI : public ScriptedAI + { + npc_bloodfang_worgen_35118AI(Creature* creature) : ScriptedAI(creature) {} + + EventMap m_events; + bool m_enrage; + + void Reset() override + { + m_enrage = false; + } + + void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override + { + if (!m_enrage && me->GetHealthPct() < 50.0f) + { + me->CastSpell(me, SPELL_ENRAGE_8599); + m_enrage = true; + m_events.ScheduleEvent(EVENT_ENRAGE_COOLDOWN, 20000); + } + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (Player* player = caster->ToPlayer()) + { + if (player->GetQuestStatus(14276) == QUEST_STATUS_INCOMPLETE) + if (spell->Id == 56641) + player->KilledMonsterCredit(44175); + + if (player->GetQuestStatus(14281) == QUEST_STATUS_INCOMPLETE) + if (spell->Id == 5143) + player->KilledMonsterCredit(44175); + } + } + + void UpdateAI(uint32 diff) override + { + m_events.Update(diff); + + while (uint32 eventId = m_events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ENRAGE_COOLDOWN: + { + m_enrage = false; + break; + } + } + } + + if (!UpdateVictim()) + return; + else + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_bloodfang_worgen_35118AI(creature); + } +}; + +class spell_gilneas_prison_periodic_dummy : public SpellScriptLoader +{ +public: + spell_gilneas_prison_periodic_dummy() : SpellScriptLoader("spell_gilneas_prison_periodic_dummy") { } + +private: + class spell_script_impl : public SpellScript + { + PrepareSpellScript(spell_script_impl) + + void ExtraEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Unit* caster = GetCaster(); + + if (caster) + { + caster->RemoveAura(SPELL_GILNEAS_PRISON_PERIODIC_1); + caster->RemoveAura(SPELL_GILNEAS_PRISON_PERIODIC_2); + + if (Player* player = caster->ToPlayer()) + player->FailQuest(14154); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_script_impl::ExtraEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_script_impl(); + } +}; +/* QUEST - 14154 - By The Skin of His Teeth - END */ + +struct npc_rampaging_worgen : public ScriptedAI +{ + npc_rampaging_worgen(Creature* creature) : ScriptedAI(creature) { } + + void DamageTaken(Unit* attacker, uint32& damage) override + { + if (attacker->GetTypeId() != TypeID::TYPEID_PLAYER && !HealthAbovePct(75)) + damage = 0; + + if (!HealthAbovePct(10) && !me->HasAura(8599)) + { + Talk(0); + DoCast(me, 8599); + } } }; void AddSC_gilneas() { - new go_merchant_square_door(); - new npc_sean_dempsey(); - new npc_lord_darius_crowley_c1(); - new npc_worgen_runt_c1(); - new npc_worgen_runt_c2(); - new npc_worgen_alpha_c1(); - new npc_worgen_alpha_c2(); - new npc_josiah_avery(); - new npc_josiah_avery_trigger(); - new npc_lorna_crowley_p4(); - new npc_gilnean_mastiff(); - new item_gilnean_mastiff_collar(); - new npc_gilnean_mastiff_recall_trigger(); - new npc_bloodfang_lurker(); + new npc_gilnean_crow(); + new gilneas_creature_script("npc_gilneas_city_guard_gate"); + new gilneas_creature_script("npc_prince_liam_greymane"); + new gilneas_creature_script("npc_worgen_runt"); + new gilneas_spell_script("spell_gen_gilneas_prison_periodic_dummy"); + new gilneas_creature_script("npc_josiah_avery"); + new gilneas_creature_script("npc_josiah_avery_worgen_form"); + new gilneas_spell_script("spell_gilneas_pull_to"); + new npc_lorna_crowley_basement("npc_lorna_crowley_basement"); + new gilneas_creature_script("npc_gilnean_mastiff"); + new gilneas_creature_script("npc_bloodfang_lurker"); + new gilneas_spell_script("spell_attack_lurker"); + new npc_king_genn_greymane(); + new npc_vehicle_genn_horse(); + new gilneas_creature_script("npc_saved_aranas"); + new npc_gilneas_children("npc_james", SPELL_SAVE_JAMES, PLAYER_SAY_JAMES); + new npc_gilneas_children("npc_ashley", SPELL_SAVE_ASHLEY, PLAYER_SAY_ASHLEY); + new npc_gilneas_children("npc_cynthia", SPELL_SAVE_CYNTHIA, PLAYER_SAY_CYNTHIA); + new npc_wahl("npc_wahl"); + new npc_lucius_the_cruel("npc_lucius_the_cruel"); + new gilneas_creature_script("npc_chance_the_cat"); + new npc_mountain_horse("npc_mountain_horse"); + new gilneas_creature_script("npc_mountain_horse_summoned"); + new gilneas_spell_script("spell_gilneas_test_telescope"); + new npc_stagecoach_carriage_exodus("npc_stagecoach_carriage_exodus"); + new npc_stagecoach_harness("npc_stagecoach_harness"); + new npc_king_genn_greymane_35112(); + new npc_bloodfang_worgen_35118(); + new npc_tobias_mistmantle_35124(); + new npc_lord_darius_crowley_35077(); + new npc_worgen_runt_35188(); + new npc_worgen_alpha_35170(); + new npc_worgen_runt_35456(); + new npc_worgen_alpha_35167(); + new npc_lord_godfrey_35115(); + new spell_gilneas_prison_periodic_dummy(); + new gilneas_creature_script("npc_rampaging_worgen"); }