diff --git a/data/sql/updates/db_world/2022_07_13_00.sql b/data/sql/updates/db_world/2022_07_13_00.sql new file mode 100644 index 000000000..9b485f276 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_13_00.sql @@ -0,0 +1,8 @@ +-- DB update 2022_07_12_01 -> 2022_07_13_00 +-- + +UPDATE `creature_template` SET `exp`=0, `ManaModifier`=1 WHERE `entry`=11657; +UPDATE `creature_template` SET `unit_flags`=`unit_flags`|512 WHERE `entry`=11677; +UPDATE `creature_template` SET `minlevel`=53, `maxlevel`=54 WHERE `entry`=11600; +UPDATE `creature_template` SET `lootid`=0,`mingold`=0, `maxgold`=0 WHERE `entry` IN (10987,11600,11602,11604,11605,10982,11603); + diff --git a/data/sql/updates/db_world/2022_07_18_00.sql b/data/sql/updates/db_world/2022_07_18_00.sql new file mode 100644 index 000000000..27f250d95 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_18_00.sql @@ -0,0 +1,6 @@ +-- DB update 2022_07_13_00 -> 2022_07_18_00 +-- +DELETE FROM `item_loot_template` WHERE (`Entry` = 9265) AND (`Item` IN (9360, 9361)); +INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(9265, 9360, 0, 92, 0, 1, 1, 1, 1, 'Cuergo\'s Hidden Treasure - Cuergo\'s Gold'), +(9265, 9361, 0, 0, 0, 1, 1, 1, 1, 'Cuergo\'s Hidden Treasure - Cuergo\'s Gold with worm'); diff --git a/data/sql/updates/db_world/2022_07_18_01.sql b/data/sql/updates/db_world/2022_07_18_01.sql new file mode 100644 index 000000000..836f13116 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_18_01.sql @@ -0,0 +1,2 @@ +-- DB update 2022_07_18_00 -> 2022_07_18_01 +UPDATE `creature_template` SET `flags_extra` = `flags_extra` |64 WHERE (`entry` = 10161); diff --git a/data/sql/updates/db_world/2022_07_19_00.sql b/data/sql/updates/db_world/2022_07_19_00.sql new file mode 100644 index 000000000..575bdf287 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_19_00.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_18_01 -> 2022_07_19_00 +-- +UPDATE `spell_dbc` SET `DurationIndex`=21 WHERE `ID`=24235; diff --git a/data/sql/updates/db_world/2022_07_19_01.sql b/data/sql/updates/db_world/2022_07_19_01.sql new file mode 100644 index 000000000..2aa01de06 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_19_01.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_19_00 -> 2022_07_19_01 +-- +UPDATE `creature_template` SET `ScriptName`='npc_brain_wash_totem' WHERE `entry`=15112; diff --git a/data/sql/updates/db_world/2022_07_19_02.sql b/data/sql/updates/db_world/2022_07_19_02.sql new file mode 100644 index 000000000..1a0b09097 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_19_02.sql @@ -0,0 +1,8 @@ +-- DB update 2022_07_19_01 -> 2022_07_19_02 +-- +UPDATE `creature` SET `MovementType` = 1, `wander_distance` = 5 WHERE `guid` IN (51879,51914); +UPDATE `creature` SET `MovementType` = 0 WHERE `guid` = 132313; + +UPDATE `creature_template` SET `AIName` = 'NullCreatureAI' WHERE `AIName` IN ('NullCreatureAi', 'NullAI'); +UPDATE `creature_template` SET `AIName` = 'AggressorAI' WHERE `AIName` = 'AgressorAI'; +UPDATE `creature_template` SET `AIName` = '' WHERE `AIName` = 'OutdoorPvPObjectiveAI'; diff --git a/data/sql/updates/db_world/2022_07_19_03.sql b/data/sql/updates/db_world/2022_07_19_03.sql new file mode 100644 index 000000000..d95649125 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_19_03.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_19_02 -> 2022_07_19_03 +-- +UPDATE `spell_proc_event` SET `procPhase`=1 WHERE `entry`=24658; diff --git a/data/sql/updates/db_world/2022_07_19_04.sql b/data/sql/updates/db_world/2022_07_19_04.sql new file mode 100644 index 000000000..89f553a4f --- /dev/null +++ b/data/sql/updates/db_world/2022_07_19_04.sql @@ -0,0 +1,284 @@ +-- DB update 2022_07_19_03 -> 2022_07_19_04 +-- +/* Maintenance on ZG Entranceway mobs part 2 Pooling */ +DELETE FROM `creature` WHERE `guid` IN (49116, 49117, 49118, 49119); +DELETE FROM `creature_addon` WHERE `guid` IN (49116, 49117, 49118, 49119); +DELETE FROM `waypoint_data` WHERE `id` IN (49116, 49117, 49118, 49119); + +/* 20 Pools of V( (Themselves Pooled) to represent every possibility; this is the only way I know how to represent every possibility I am open to other suggestions; 72 snakes + +INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES +(@GUID+, 0, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- Empty Occasionally 1 slot, front facing exit +(@GUID+, 0, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- Empty Occasionally 2 slot left facing exit +(@GUID+, 0, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 slot center slot +(@GUID+, 0, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0); -- 4 slot right slot + +@POOL+0 Master Pool of all of the following Pools + +8 Pools are 6.25% to create a 50% chance of 3 mobs spawning, let E1 and E2 represent empty xyz slots that have been witnessed empty + +@POOL+1 E1 A@GUID+0 S@GUID+1 X@GUID+2 +@POOL+2 E1 A@GUID+3 X@GUID+4 S@GUID+5 +@POOL+3 E1 S@GUID+6 A@GUID+7 X@GUID+8 +@POOL+4 E1 S@GUID+9 X@GUID+10 A@GUID+11 +@POOL+5 A@GUID+12 E2 S@GUID+13 X@GUID+14 +@POOL+6 A@GUID+15 E2 X@GUID+16 S@GUID+17 +@POOL+7 S@GUID+18 E2 A@GUID+19 X@GUID+20 +@POOL+8 S@GUID+21 E2 X@GUID+22 A@GUID+23 + +11 Pools of 4.16% and 1 of 4.24% to create a 50% chance of 4 mobs spawning 1-3 of each type +@POOL+9 A@GUID+24 S@GUID+25 X@GUID+26 X@GUID+27 +@POOL+10 A@GUID+28 X@GUID+29 S@GUID+30 X@GUID+31 +@POOL+11 A@GUID+32 X@GUID+33 X@GUID+34 S@GUID+35 +@POOL+12 S@GUID+36 A@GUID+37 X@GUID+38 X@GUID+39 +@POOL+13 S@GUID+40 X@GUID+41 A@GUID+42 X@GUID+43 +@POOL+14 S@GUID+44 X@GUID+45 X@GUID+46 A@GUID+47 +@POOL+15 X@GUID+48 A@GUID+49 S@GUID+50 X@GUID+51 +@POOL+16 X@GUID+52 A@GUID+53 X@GUID+54 S@GUID+55 +@POOL+17 X@GUID+56 S@GUID+57 A@GUID+58 X@GUID+59 +@POOL+18 X@GUID+60 S@GUID+61 X@GUID+62 A@GUID+63 +@POOL+19 X@GUID+64 X@GUID+65 A@GUID+66 S@GUID+67 +@POOL+20 X@GUID+68 X@GUID+69 S@GUID+70 A@GUID+71 */ + +SET @GUID :=86939; +DELETE FROM `creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+71; +INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES +-- 3 Packs +-- @POOL+1 E1 11372, 0, 0,@GUID+0 11371, 0, 0,@GUID+1 11371, 11372, 0,@GUID+2 +(@GUID+0, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+1, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+2, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+2 E1 11372, 0, 0,@GUID+3 11371, 11372, 0,@GUID+4 11371, 0, 0,@GUID+5 +(@GUID+3, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+4, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+5, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+3 E1 11371, 0, 0,@GUID+6 11372, 0, 0,@GUID+7 11371, 11372, 0,@GUID+8 +(@GUID+6, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+7, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+8, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+4 E1 11371, 0, 0,@GUID+9 11371, 11372, 0,@GUID+10 11372, 0, 0,@GUID+11 +(@GUID+9, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+10, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+11, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+5 11372, 0, 0,@GUID+12 E2 11371, 0, 0,@GUID+13 11371, 11372, 0,@GUID+14 +(@GUID+12, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+13, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+14, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+6 11372, 0, 0,@GUID+15 E2 11371, 11372, 0,@GUID+16 11371, 0, 0,@GUID+17 +(@GUID+15, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+16, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+17, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+7 11371, 0, 0,@GUID+18 E2 11372, 0, 0,@GUID+19 11371, 11372, 0,@GUID+20 +(@GUID+18, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+19, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+20, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+8 11371, 0, 0,@GUID+21 E2 11371, 11372, 0,@GUID+22 11372, 0, 0,@GUID+23 +(@GUID+21, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+22, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+23, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- 4 Packs +-- @POOL+9 11372, 0, 0,@GUID+24 11371, 0, 0,@GUID+25 11371, 11372, 0,@GUID+26 11371, 11372, 0,@GUID+27 +(@GUID+24, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+25, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+26, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+27, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+10 11372, 0, 0,@GUID+28 11371, 11372, 0,@GUID+29 11371, 0, 0,@GUID+30 11371, 11372, 0,@GUID+31 +(@GUID+28, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+29, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+30, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+31, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+11 11372, 0, 0,@GUID+32 11371, 11372, 0,@GUID+33 11371, 11372, 0,@GUID+34 11371, 0, 0,@GUID+35 +(@GUID+32, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+33, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+34, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+35, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+12 11371, 0, 0,@GUID+36 11372, 0, 0,@GUID+37 11371, 11372, 0,@GUID+38 11371, 11372, 0,@GUID+39 +(@GUID+36, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+37, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+38, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+39, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+13 11371, 0, 0,@GUID+40 11371, 11372, 0,@GUID+41 11372, 0, 0,@GUID+42 11371, 11372, 0,@GUID+43 +(@GUID+40, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+41, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+42, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+43, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+14 11371, 0, 0,@GUID+44 11371, 11372, 0,@GUID+45 11371, 11372, 0,@GUID+46 11372, 0, 0,@GUID+47 +(@GUID+44, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+45, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+46, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+47, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+15 11371, 11372, 0,@GUID+48 11372, 0, 0,@GUID+49 11371, 0, 0,@GUID+50 11371, 11372, 0,@GUID+51 +(@GUID+48, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+49, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+50, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+51, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+16 11371, 11372, 0,@GUID+52 11372, 0, 0,@GUID+53 11371, 11372, 0,@GUID+54 11371, 0, 0,@GUID+55 +(@GUID+52, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+53, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+54, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+55, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+17 11371, 11372, 0,@GUID+56 11371, 0, 0,@GUID+57 11372, 0, 0,@GUID+58 11371, 11372, 0,@GUID+59 +(@GUID+56, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+57, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+58, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+59, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+18 11371, 11372, 0,@GUID+60 11371, 0, 0,@GUID+61 11371, 11372, 0,@GUID+62 11372, 0, 0,@GUID+63 +(@GUID+60, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+61, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+62, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+63, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+19 11371, 11372, 0,@GUID+64 11371, 11372, 0,@GUID+65 11372, 0, 0,@GUID+66 11371, 0, 0,@GUID+67 +(@GUID+64, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+65, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+66, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+67, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 4 +-- @POOL+20 11371, 11372, 0,@GUID+68 11371, 11372, 0,@GUID+69 11371, 0, 0,@GUID+70 11372, 0, 0,@GUID+71 +(@GUID+68, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11884.3, -1379.01, 66.4316, 3.36848, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 1 +(@GUID+69, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11896.4, -1365.13, 69.8727, 2.42601, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 2 +(@GUID+70, 11371, 0, 0, 309, 0, 0, 1, 1, 0, -11885, -1368.42, 68.8007, 5.53269, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0), -- 3 +(@GUID+71, 11372, 0, 0, 309, 0, 0, 1, 1, 0, -11878.2, -1368.68, 69.7661, 3.90954, 7200, 3, 0, 15260, 0, 1, 0, 0, 0, '', 0); -- 4 + +SET @POOL :=448; +DELETE FROM `pool_template` WHERE `entry` BETWEEN @POOL+0 AND @POOL+20; +DELETE FROM `pool_creature` WHERE `guid` BETWEEN @GUID+0 AND @GUID+71; + +INSERT INTO `pool_template` (`entry`, `max_limit`, `description`) VALUES +(@POOL+0, 1, 'ZG Entrance Snake 3-4 Pack Pool of Pools'), +(@POOL+1, 3, 'ZG Entrance Snake as 3 Pack 1/8'), +(@POOL+2, 3, 'ZG Entrance Snake as 3 Pack 2/8'), +(@POOL+3, 3, 'ZG Entrance Snake as 3 Pack 3/8'), +(@POOL+4, 3, 'ZG Entrance Snake as 3 Pack 4/8'), +(@POOL+5, 3, 'ZG Entrance Snake as 3 Pack 5/8'), +(@POOL+6, 3, 'ZG Entrance Snake as 3 Pack 6/8'), +(@POOL+7, 3, 'ZG Entrance Snake as 3 Pack 7/8'), +(@POOL+8, 3, 'ZG Entrance Snake as 3 Pack 8/8'), +(@POOL+9, 4, 'ZG Entrance Snake as 4 Pack 1/12'), +(@POOL+10, 4, 'ZG Entrance Snake as 4 Pack 2/12'), +(@POOL+11, 4, 'ZG Entrance Snake as 4 Pack 3/12'), +(@POOL+12, 4, 'ZG Entrance Snake as 4 Pack 4/12'), +(@POOL+13, 4, 'ZG Entrance Snake as 4 Pack 5/12'), +(@POOL+14, 4, 'ZG Entrance Snake as 4 Pack 6/12'), +(@POOL+15, 4, 'ZG Entrance Snake as 4 Pack 7/12'), +(@POOL+16, 4, 'ZG Entrance Snake as 4 Pack 8/12'), +(@POOL+17, 4, 'ZG Entrance Snake as 4 Pack 9/12'), +(@POOL+18, 4, 'ZG Entrance Snake as 4 Pack 10/12'), +(@POOL+19, 4, 'ZG Entrance Snake as 4 Pack 11/12'), +(@POOL+20, 4, 'ZG Entrance Snake as 4 Pack 12/12'); + +DELETE FROM `pool_pool` WHERE `pool_id` BETWEEN @POOL+0 AND @POOL+20; +DELETE FROM `pool_pool` WHERE `mother_pool` BETWEEN @POOL+0 AND @POOL+20; +INSERT INTO `pool_pool` (`pool_id`, `mother_pool`, `chance`, `description`) VALUES +(@POOL+1, @POOL+0, 6, 'ZG Entrance Snake as 3 Pack 1/8'), +(@POOL+2, @POOL+0, 6, 'ZG Entrance Snake as 3 Pack 2/8'), +(@POOL+3, @POOL+0, 6, 'ZG Entrance Snake as 3 Pack 3/8'), +(@POOL+4, @POOL+0, 7, 'ZG Entrance Snake as 3 Pack 4/8'), +(@POOL+5, @POOL+0, 6, 'ZG Entrance Snake as 3 Pack 5/8'), +(@POOL+6, @POOL+0, 6, 'ZG Entrance Snake as 3 Pack 6/8'), +(@POOL+7, @POOL+0, 6, 'ZG Entrance Snake as 3 Pack 7/8'), +(@POOL+8, @POOL+0, 7, 'ZG Entrance Snake as 3 Pack 8/8'), +(@POOL+9, @POOL+0, 5, 'ZG Entrance Snake as 4 Pack 1/12'), +(@POOL+10, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 2/12'), +(@POOL+11, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 3/12'), +(@POOL+12, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 4/12'), +(@POOL+13, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 5/12'), +(@POOL+14, @POOL+0, 5, 'ZG Entrance Snake as 4 Pack 6/12'), +(@POOL+15, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 7/12'), +(@POOL+16, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 8/12'), +(@POOL+17, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 9/12'), +(@POOL+18, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 10/12'), +(@POOL+19, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 11/12'), +(@POOL+20, @POOL+0, 4, 'ZG Entrance Snake as 4 Pack 12/12'); + +INSERT INTO `pool_creature` (`guid`, `pool_entry`, `description`) VALUES +-- @POOL+1 E1 A@GUID+0 S@GUID+1 X@GUID+2 +(@GUID+0, @POOL+1, 'ZG Entrance Snake as 3 Pack 1/8 Adder'), +(@GUID+1, @POOL+1, 'ZG Entrance Snake as 3 Pack 1/8 Serpent'), +(@GUID+2, @POOL+1, 'ZG Entrance Snake as 3 Pack 1/8 Xsnake'), +-- @POOL+2 E1 A@GUID+3 X@GUID+4 S@GUID+5 +(@GUID+3, @POOL+2, 'ZG Entrance Snake as 3 Pack 2/8 Adder'), +(@GUID+4, @POOL+2, 'ZG Entrance Snake as 3 Pack 2/8 Xsnake'), +(@GUID+5, @POOL+2, 'ZG Entrance Snake as 3 Pack 2/8 Serpent'), +-- @POOL+3 E1 S@GUID+6 A@GUID+7 X@GUID+8 +(@GUID+6, @POOL+3, 'ZG Entrance Snake as 3 Pack 3/8 Serpent'), +(@GUID+7, @POOL+3, 'ZG Entrance Snake as 3 Pack 3/8 Adder'), +(@GUID+8, @POOL+3, 'ZG Entrance Snake as 3 Pack 3/8 Xsnake'), +-- @POOL+4 E1 S@GUID+9 X@GUID+10 A@GUID+11 +(@GUID+9, @POOL+4, 'ZG Entrance Snake as 3 Pack 4/8 Serpent'), +(@GUID+10, @POOL+4, 'ZG Entrance Snake as 3 Pack 4/8 Xsnake'), +(@GUID+11, @POOL+4, 'ZG Entrance Snake as 3 Pack 4/8 Adder'), +-- @POOL+5 A@GUID+12 E2 S@GUID+13 X@GUID+14 +(@GUID+12, @POOL+5, 'ZG Entrance Snake as 3 Pack 5/8 Adder'), +(@GUID+13, @POOL+5, 'ZG Entrance Snake as 3 Pack 5/8 Serpent'), +(@GUID+14, @POOL+5, 'ZG Entrance Snake as 3 Pack 5/8 Xsnake'), +-- @POOL+6 A@GUID+15 E2 X@GUID+16 S@GUID+17 +(@GUID+15, @POOL+6, 'ZG Entrance Snake as 3 Pack 6/8 Adder'), +(@GUID+16, @POOL+6, 'ZG Entrance Snake as 3 Pack 6/8 Xsnake'), +(@GUID+17, @POOL+6, 'ZG Entrance Snake as 3 Pack 6/8 Serpent'), +-- @POOL+7 S@GUID+18 E2 A@GUID+19 X@GUID+20 +(@GUID+18, @POOL+7, 'ZG Entrance Snake as 3 Pack 7/8 Serpent'), +(@GUID+19, @POOL+7, 'ZG Entrance Snake as 3 Pack 7/8 Adder'), +(@GUID+20, @POOL+7, 'ZG Entrance Snake as 3 Pack 7/8 Xsnake'), +-- @POOL+8 S@GUID+21 E2 X@GUID+22 A@GUID+23 +(@GUID+21, @POOL+8, 'ZG Entrance Snake as 3 Pack 8/8 Serpent'), +(@GUID+22, @POOL+8, 'ZG Entrance Snake as 3 Pack 8/8 Xsnake'), +(@GUID+23, @POOL+8, 'ZG Entrance Snake as 3 Pack 8/8 Adder'), +-- @POOL+9 A@GUID+24 S@GUID+25 X@GUID+26 X@GUID+27 +(@GUID+24, @POOL+9, 'ZG Entrance Snake as 4 Pack 1/12 Adder'), +(@GUID+25, @POOL+9, 'ZG Entrance Snake as 4 Pack 1/12 Serpent'), +(@GUID+26, @POOL+9, 'ZG Entrance Snake as 4 Pack 1/12 Xsnake'), +(@GUID+27, @POOL+9, 'ZG Entrance Snake as 4 Pack 1/12 Xsnake'), +-- @POOL+10 A@GUID+28 X@GUID+29 S@GUID+30 X@GUID+31 +(@GUID+28, @POOL+10, 'ZG Entrance Snake as 4 Pack 2/12 Adder'), +(@GUID+29, @POOL+10, 'ZG Entrance Snake as 4 Pack 2/12 Xsnake'), +(@GUID+30, @POOL+10, 'ZG Entrance Snake as 4 Pack 2/12 Serpent'), +(@GUID+31, @POOL+10, 'ZG Entrance Snake as 4 Pack 2/12 Xsnake'), +-- @POOL+11 A@GUID+32 X@GUID+33 X@GUID+34 S@GUID+35 +(@GUID+32, @POOL+11, 'ZG Entrance Snake as 4 Pack 3/12 Adder'), +(@GUID+33, @POOL+11, 'ZG Entrance Snake as 4 Pack 3/12 Xsnake'), +(@GUID+34, @POOL+11, 'ZG Entrance Snake as 4 Pack 3/12 Xsnake'), +(@GUID+35, @POOL+11, 'ZG Entrance Snake as 4 Pack 3/12 Serpent'), +-- @POOL+12 S@GUID+36 A@GUID+37 X@GUID+38 X@GUID+39 +(@GUID+36, @POOL+12, 'ZG Entrance Snake as 4 Pack 4/12 Serpent'), +(@GUID+37, @POOL+12, 'ZG Entrance Snake as 4 Pack 4/12 Adder'), +(@GUID+38, @POOL+12, 'ZG Entrance Snake as 4 Pack 4/12 Xsnake'), +(@GUID+39, @POOL+12, 'ZG Entrance Snake as 4 Pack 4/12 Xsnake'), +-- @POOL+13 S@GUID+40 X@GUID+41 A@GUID+42 X@GUID+43 +(@GUID+40, @POOL+13, 'ZG Entrance Snake as 4 Pack 5/12 Serpent'), +(@GUID+41, @POOL+13, 'ZG Entrance Snake as 4 Pack 5/12 Xsnake'), +(@GUID+42, @POOL+13, 'ZG Entrance Snake as 4 Pack 5/12 Adder'), +(@GUID+43, @POOL+13, 'ZG Entrance Snake as 4 Pack 5/12 Xsnake'), +-- @POOL+14 S@GUID+44 X@GUID+45 X@GUID+46 A@GUID+47 +(@GUID+44, @POOL+14, 'ZG Entrance Snake as 4 Pack 6/12 Serpent'), +(@GUID+45, @POOL+14, 'ZG Entrance Snake as 4 Pack 6/12 Xsnake'), +(@GUID+46, @POOL+14, 'ZG Entrance Snake as 4 Pack 6/12 Xsnake'), +(@GUID+47, @POOL+14, 'ZG Entrance Snake as 4 Pack 6/12 Adder'), +-- @POOL+15 X@GUID+48 A@GUID+49 S@GUID+50 X@GUID+51 +(@GUID+48, @POOL+15, 'ZG Entrance Snake as 4 Pack 7/12 Xsnake'), +(@GUID+49, @POOL+15, 'ZG Entrance Snake as 4 Pack 7/12 Adder'), +(@GUID+50, @POOL+15, 'ZG Entrance Snake as 4 Pack 7/12 Serpent'), +(@GUID+51, @POOL+15, 'ZG Entrance Snake as 4 Pack 7/12 Xsnake'), +-- @POOL+16 X@GUID+52 A@GUID+53 X@GUID+54 S@GUID+55 +(@GUID+52, @POOL+16, 'ZG Entrance Snake as 4 Pack 8/12 Xsnake'), +(@GUID+53, @POOL+16, 'ZG Entrance Snake as 4 Pack 8/12 Adder'), +(@GUID+54, @POOL+16, 'ZG Entrance Snake as 4 Pack 8/12 Xsnake'), +(@GUID+55, @POOL+16, 'ZG Entrance Snake as 4 Pack 8/12 Serpent'), +-- @POOL+17 X@GUID+56 S@GUID+57 A@GUID+58 X@GUID+59 +(@GUID+56, @POOL+17, 'ZG Entrance Snake as 4 Pack 9/12 Xsnake'), +(@GUID+57, @POOL+17, 'ZG Entrance Snake as 4 Pack 9/12 Serpent'), +(@GUID+58, @POOL+17, 'ZG Entrance Snake as 4 Pack 9/12 Adder'), +(@GUID+59, @POOL+17, 'ZG Entrance Snake as 4 Pack 9/12 Xsnake'), +-- @POOL+18 X@GUID+60 S@GUID+61 X@GUID+62 A@GUID+63 +(@GUID+60, @POOL+18, 'ZG Entrance Snake as 4 Pack 10/12 Xsnake'), +(@GUID+61, @POOL+18, 'ZG Entrance Snake as 4 Pack 10/12 Serpent'), +(@GUID+62, @POOL+18, 'ZG Entrance Snake as 4 Pack 10/12 Xsnake'), +(@GUID+63, @POOL+18, 'ZG Entrance Snake as 4 Pack 10/12 Adder'), +-- @POOL+19 X@GUID+64 X@GUID+65 A@GUID+66 S@GUID+67 +(@GUID+64, @POOL+19, 'ZG Entrance Snake as 4 Pack 11/12 Xsnake'), +(@GUID+65, @POOL+19, 'ZG Entrance Snake as 4 Pack 11/12 Xsnake'), +(@GUID+66, @POOL+19, 'ZG Entrance Snake as 4 Pack 11/12 Adder'), +(@GUID+67, @POOL+19, 'ZG Entrance Snake as 4 Pack 11/12 Serpent'), +-- @POOL+20 X@GUID+68 X@GUID+69 S@GUID+70 A@GUID+71 +(@GUID+68, @POOL+20, 'ZG Entrance Snake as 4 Pack 12/12 Xsnake'), +(@GUID+69, @POOL+20, 'ZG Entrance Snake as 4 Pack 12/12 Xsnake'), +(@GUID+70, @POOL+20, 'ZG Entrance Snake as 4 Pack 12/12 Serpent'), +(@GUID+71, @POOL+20, 'ZG Entrance Snake as 4 Pack 12/12 Adder'); diff --git a/data/sql/updates/db_world/2022_07_20_00.sql b/data/sql/updates/db_world/2022_07_20_00.sql new file mode 100644 index 000000000..d7d767069 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_00.sql @@ -0,0 +1,54 @@ +-- DB update 2022_07_19_04 -> 2022_07_20_00 +-- +SET @NPC := 42880; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x`=-10661, `position_y`=-3924.57, `position_z`=18.8015, `orientation`=5.83672, `MovementType`='2' WHERE `guid`=@NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); + +DELETE FROM `waypoint_data` WHERE `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`) VALUES +(@PATH, 1, -10641.5, -3982.49, 19.943), +(@PATH, 2, -10591, -3982.21, 21.4646), +(@PATH, 3, -10574.5, -3995.66, 18.5265), +(@PATH, 4, -10556.4, -4008.31, 19.5063), +(@PATH, 5, -10541.2, -4012.2, 22.3642), +(@PATH, 6, -10510.2, -4016.9, 18.3724), +(@PATH, 7, -10482.4, -4010.78, 18.9192), +(@PATH, 8, -10475.6, -4003.55, 19.5199), +(@PATH, 9, -10460.1, -3998.53, 18.5604), +(@PATH, 10, -10434, -4005, 18.5093), +(@PATH, 11, -10408.6, -4010.32, 18.2372), +(@PATH, 12, -10387.1, -3999.93, 19.7943), +(@PATH, 13, -10363.4, -3997.07, 19.3136), +(@PATH, 14, -10343.3, -4003.71, 20.5207), +(@PATH, 15, -10328.6, -4013.14, 18.4205), +(@PATH, 16, -10335.8, -4029.01, 19.4894), +(@PATH, 17, -10325.5, -4054.12, 19.7849), +(@PATH, 18, -10315.2, -4078.22, 22.4922), +(@PATH, 19, -10296, -4123.39, 23.2141), +(@PATH, 20, -10301, -4143.57, 19.8863), +(@PATH, 21, -10322.1, -4159.15, 18.3385), +(@PATH, 22, -10357.8, -4178.26, 20.1807), +(@PATH, 23, -10379.9, -4192.31, 22.7909), +(@PATH, 24, -10419, -4192.8, 19.1422), +(@PATH, 25, -10441.2, -4184.96, 18.6967), +(@PATH, 26, -10480, -4193.1, 18.9901), +(@PATH, 27, -10495, -4205.67, 19.6285), +(@PATH, 28, -10511.9, -4209.93, 19.0212), +(@PATH, 29, -10547.4, -4199.08, 18.7961), +(@PATH, 30, -10564.6, -4187.57, 19.3169), +(@PATH, 31, -10581, -4203.9, 20.3609), +(@PATH, 32, -10594, -4205.64, 21.6639), +(@PATH, 33, -10620.6, -4211.36, 23.3686), +(@PATH, 34, -10673.5, -4191.09, 22.867), +(@PATH, 35, -10710.4, -4172.44, 21.8668), +(@PATH, 36, -10723.1, -4139.99, 18.6405), +(@PATH, 37, -10745.3, -4114.88, 19.7025), +(@PATH, 38, -10749.3, -4070.5, 20.6484), +(@PATH, 39, -10756.1, -4048.57, 22.868), +(@PATH, 40, -10742.5, -4002.81, 20.3069), +(@PATH, 41, -10701.2, -3956.85, 23.3119), +(@PATH, 42, -10662.1, -3926.38, 19.4344); diff --git a/data/sql/updates/db_world/2022_07_20_01.sql b/data/sql/updates/db_world/2022_07_20_01.sql new file mode 100644 index 000000000..03e742122 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_01.sql @@ -0,0 +1,227 @@ +-- DB update 2022_07_20_00 -> 2022_07_20_01 +-- +SET @EVENT := 8; + +DELETE FROM `game_event_creature` WHERE `eventEntry` = @EVENT AND `guid` IN +(146602, + 146609, + 146618, + 146619, + 146621); + +INSERT INTO `game_event_creature` (`eventEntry`, `guid`) VALUES +(@EVENT, 146602), +(@EVENT, 146609), +(@EVENT, 146618), +(@EVENT, 146619), +(@EVENT, 146621); + +DELETE FROM `game_event_gameobject` WHERE `eventEntry` = @EVENT AND `guid` IN +(9780, + 9754, + 9782, + 9751, + 9766, + 9756, + 9747, + 9749, + 9809, + 9774, + 9746, + 9748, + 9802, + 9808, + 9752, + 9760, + 9792, + 9762, + 9778, + 9757, + 9770, + 9793, + 9758, + 9769, + 9830, + 9828, + 9761, + 9779, + 9791, + 9773, + 9768, + 9833, + 9759, + 9800, + 9804, + 9801, + 9787, + 9783, + 9798, + 9772, + 9794, + 9781, + 9790, + 9795, + 9813, + 9753, + 9811, + 9805, + 9785, + 9807, + 9797, + 9799, + 9810, + 9784, + 9771, + 9796, + 9743, + 9803, + 9786, + 9777, + 9767, + 9765, + 9789, + 9763, + 242252, + 242257, + 242259, + 242267, + 242253, + 242254, + 242275, + 242274, + 242273, + 242271, + 242263, + 242272, + 242276, + 242270, + 242265, + 242255, + 242306, + 242307, + 242302, + 242301, + 242304, + 242303, + 242300, + 242299, + 242305, + 242266, + 242264, + 242282, + 242258, + 242261, + 242284, + 242283, + 242256, + 242260, + 242278, + 242277, + 242279, + 242280, + 242281); + +INSERT INTO `game_event_gameobject` (`eventEntry`, `guid`) VALUES +(@EVENT, 9780), +(@EVENT, 9754), +(@EVENT, 9782), +(@EVENT, 9751), +(@EVENT, 9766), +(@EVENT, 9756), +(@EVENT, 9747), +(@EVENT, 9749), +(@EVENT, 9809), +(@EVENT, 9774), +(@EVENT, 9746), +(@EVENT, 9748), +(@EVENT, 9802), +(@EVENT, 9808), +(@EVENT, 9752), +(@EVENT, 9760), +(@EVENT, 9792), +(@EVENT, 9762), +(@EVENT, 9778), +(@EVENT, 9757), +(@EVENT, 9770), +(@EVENT, 9793), +(@EVENT, 9758), +(@EVENT, 9769), +(@EVENT, 9830), +(@EVENT, 9828), +(@EVENT, 9761), +(@EVENT, 9779), +(@EVENT, 9791), +(@EVENT, 9773), +(@EVENT, 9768), +(@EVENT, 9833), +(@EVENT, 9759), +(@EVENT, 9800), +(@EVENT, 9804), +(@EVENT, 9801), +(@EVENT, 9787), +(@EVENT, 9783), +(@EVENT, 9798), +(@EVENT, 9772), +(@EVENT, 9794), +(@EVENT, 9781), +(@EVENT, 9790), +(@EVENT, 9795), +(@EVENT, 9813), +(@EVENT, 9753), +(@EVENT, 9811), +(@EVENT, 9805), +(@EVENT, 9785), +(@EVENT, 9807), +(@EVENT, 9797), +(@EVENT, 9799), +(@EVENT, 9810), +(@EVENT, 9784), +(@EVENT, 9771), +(@EVENT, 9796), +(@EVENT, 9743), +(@EVENT, 9803), +(@EVENT, 9786), +(@EVENT, 9777), +(@EVENT, 9767), +(@EVENT, 9765), +(@EVENT, 9789), +(@EVENT, 9763), +(@EVENT, 242252), +(@EVENT, 242257), +(@EVENT, 242259), +(@EVENT, 242267), +(@EVENT, 242253), +(@EVENT, 242254), +(@EVENT, 242275), +(@EVENT, 242274), +(@EVENT, 242273), +(@EVENT, 242271), +(@EVENT, 242263), +(@EVENT, 242272), +(@EVENT, 242276), +(@EVENT, 242270), +(@EVENT, 242265), +(@EVENT, 242255), +(@EVENT, 242306), +(@EVENT, 242307), +(@EVENT, 242302), +(@EVENT, 242301), +(@EVENT, 242304), +(@EVENT, 242303), +(@EVENT, 242300), +(@EVENT, 242299), +(@EVENT, 242305), +(@EVENT, 242266), +(@EVENT, 242264), +(@EVENT, 242282), +(@EVENT, 242258), +(@EVENT, 242261), +(@EVENT, 242284), +(@EVENT, 242283), +(@EVENT, 242256), +(@EVENT, 242260), +(@EVENT, 242278), +(@EVENT, 242277), +(@EVENT, 242279), +(@EVENT, 242280), +(@EVENT, 242281); diff --git a/data/sql/updates/db_world/2022_07_20_02.sql b/data/sql/updates/db_world/2022_07_20_02.sql new file mode 100644 index 000000000..e21a1e744 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_02.sql @@ -0,0 +1,57 @@ +-- DB update 2022_07_20_01 -> 2022_07_20_02 +-- Rocklance +SET @NPC := 20720; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x`=-1199.35, `position_y`=-3100.46, `position_z`=94.7484, `orientation`=2.7918, `MovementType`='2' WHERE `guid`=@NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); + +DELETE FROM `waypoint_data` WHERE `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`) VALUES +(@PATH, 1, -1201.63, -3099.24, 94.8781), +(@PATH, 2, -1219.21, -3099.76, 95.241), +(@PATH, 3, -1272.76, -3089.53, 93.8928), +(@PATH, 4, -1315.08, -3106.5, 91.7995), +(@PATH, 5, -1330.48, -3095.55, 92.4438), +(@PATH, 6, -1341.49, -3060.61, 92.6899), +(@PATH, 7, -1354.4, -3030.3, 93.3309), +(@PATH, 8, -1386.31, -3005.86, 93.1475), +(@PATH, 9, -1430.19, -2974.08, 93.1218), +(@PATH, 10, -1436.49, -2943.46, 91.668), +(@PATH, 11, -1436.75, -2920.35, 92.5429), +(@PATH, 12, -1410.03, -2893.52, 93.1282), +(@PATH, 13, -1388.5, -2866.72, 94.5754), +(@PATH, 14, -1360.27, -2850.79, 94.705), +(@PATH, 15, -1332.8, -2857.77, 93.5965), +(@PATH, 16, -1288.33, -2870.37, 93.0108), +(@PATH, 17, -1265.32, -2850.79, 94.069), +(@PATH, 18, -1239.87, -2834.24, 94.41), +(@PATH, 19, -1219.09, -2834.03, 93.9937), +(@PATH, 20, -1194.71, -2865.09, 93.5771), +(@PATH, 21, -1170.2, -2886.21, 94.3522), +(@PATH, 22, -1146.43, -2925.68, 93.1956), +(@PATH, 23, -1123.57, -2957.35, 92.8819), +(@PATH, 24, -1114.24, -2966.51, 92.4826), +(@PATH, 25, -1111.46, -3018.12, 94.8292), +(@PATH, 26, -1101.72, -3047.27, 93.4784), +(@PATH, 27, -1123.65, -3070.33, 91.8408), +(@PATH, 28, -1147.38, -3076.85, 92.3126), +(@PATH, 29, -1177.95, -3082.89, 92.8266); + +DELETE FROM `creature_formations` WHERE `leaderGUID` = @NPC; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES (@NPC, @NPC, 0, 0, 512); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES (@NPC, 20588, 3, 215, 512); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES (@NPC, 14007, 3, 135, 512); + +UPDATE `creature` SET `spawntimesecs`=25000 WHERE `guid`=14007; +UPDATE `creature` SET `spawntimesecs`=25000 WHERE `guid`=20588; +UPDATE `creature` SET `spawntimesecs`=19800 WHERE `guid`=@NPC; + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 5841; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 5841) AND (`source_type` = 0) AND (`id` IN (3, 4)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(5841, 0, 3, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 70, 500, 0, 0, 0, 0, 0, 10, 14007, 0, 0, 0, 0, 0, 0, 0, 'Rocklance - On Respawn - Respawn Formation Member 14007'), +(5841, 0, 4, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 70, 500, 0, 0, 0, 0, 0, 10, 20588, 0, 0, 0, 0, 0, 0, 0, 'Rocklance - On Respawn - Respawn Formation Member 20588'); diff --git a/data/sql/updates/db_world/2022_07_20_03.sql b/data/sql/updates/db_world/2022_07_20_03.sql new file mode 100644 index 000000000..9f7d1d737 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_03.sql @@ -0,0 +1,4 @@ +-- DB update 2022_07_20_02 -> 2022_07_20_03 +-- +DELETE FROM `command` WHERE `name` = 'npc guid'; +INSERT INTO `command` (`name`, `security`, `help`) VALUES ('npc guid', 1, 'Syntax: .npc guid\r\n\r\nDisplays GUID, faction, NPC flags, Entry ID, Model ID for selected creature.'); diff --git a/data/sql/updates/db_world/2022_07_20_04.sql b/data/sql/updates/db_world/2022_07_20_04.sql new file mode 100644 index 000000000..06edb512f --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_04.sql @@ -0,0 +1,9 @@ +-- DB update 2022_07_20_03 -> 2022_07_20_04 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 11076; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 11076); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(11076, 0, 0, 0, 0, 0, 100, 0, 0, 0, 3400, 4800, 0, 11, 12471, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Cauldron Lord Razarch - In Combat - Cast \'Shadow Bolt\''), +(11076, 0, 1, 0, 0, 0, 100, 0, 11000, 15000, 20000, 25000, 0, 11, 17204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cauldron Lord Razarch - In Combat - Cast \'Summon Skeleton\''), +(11076, 0, 2, 0, 2, 0, 100, 0, 0, 50, 14000, 18000, 0, 11, 17173, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Cauldron Lord Razarch - Between 0-50% Health - Cast \'Drain Life\''), +(11076, 0, 3, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Cauldron Lord Razarch - On Aggro - Say Line 0'); diff --git a/data/sql/updates/db_world/2022_07_20_05.sql b/data/sql/updates/db_world/2022_07_20_05.sql new file mode 100644 index 000000000..fa2a74941 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_05.sql @@ -0,0 +1,6 @@ +-- DB update 2022_07_20_04 -> 2022_07_20_05 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 1785; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1785) AND (`source_type` = 0) AND (`id` IN (0, 1)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(1785, 0, 0, 0, 2, 0, 100, 1, 5, 30, 0, 0, 0, 11, 12542, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeletal Terror - Between 5-30% Health - Cast \'Fear\' (No Repeat)'); diff --git a/data/sql/updates/db_world/2022_07_20_06.sql b/data/sql/updates/db_world/2022_07_20_06.sql new file mode 100644 index 000000000..06fe8042c --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_06.sql @@ -0,0 +1,28 @@ +-- DB update 2022_07_20_05 -> 2022_07_20_06 +-- Remorseful Highborne --> Add gossip texts (Credit: https://github.com/Haeniken/FairyCore/commit/25260b92a6c5163643248deeae7247a3bac6cbb7) +UPDATE `creature_template` SET `gossip_menu_id`=3803, `npcflag` = `npcflag` | 1 WHERE `entry`=10684; + +DELETE FROM `gossip_menu` WHERE `MenuID`=3803; +INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES +(3803,4635), +(3803,4636); + +DELETE FROM `npc_text` WHERE `ID`=4636; +INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`) VALUES +(4636,'',"I will not forrrget what you have done...$B$BPleassse, leave meee...",7309,0,1); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=3803; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(14,3803,4636,0,0,8,0,5248,0,0,0,0,0,'',"Remorseful Highborne - Show Gossip Menu Text 4636 if Quest 5248 is rewarded"); + +-- Remorseful Highborne --> Add texts on quest finished +DELETE FROM `creature_text` WHERE `CreatureID`=10684; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(10684,0,0,"Highborne spirits! Be at peace! The Crystal of Zin-Malor is whole once again!",14,0,100,0,0,0,6505,0,"Remorseful Highborne"), +(10684,0,1,"Cursed spirits! Let go of the past! The Crystal of Zin-Malor no longer binds you!",14,0,100,0,0,0,6506,0,"Remorseful Highborne"), +(10684,0,2,"Spirits of the Highborne! You may now rest! The curse of the crystal releases you!",14,0,100,0,0,0,6507,0,"Remorseful Highborne"); + +UPDATE `creature_template` SET `AIName`="SmartAI" WHERE `entry`=10684; +DELETE FROM `smart_scripts` WHERE `entryorguid`=10684 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(10684,0,0,0,20,0,100,0,5248,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Remorseful Highborne - On Quest \'Tormented by the Past\' Finished - Say Line 0"); diff --git a/data/sql/updates/db_world/2022_07_20_07.sql b/data/sql/updates/db_world/2022_07_20_07.sql new file mode 100644 index 000000000..d3a039af4 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_07.sql @@ -0,0 +1,4 @@ +-- DB update 2022_07_20_06 -> 2022_07_20_07 +-- +UPDATE `smart_scripts` SET `target_type`=24 WHERE `entryorguid`=25416 AND `source_type`=0 AND `id`=4; +UPDATE `smart_scripts` SET `target_type`=24 WHERE `entryorguid`=25418 AND `source_type`=0 AND `id`=4; diff --git a/data/sql/updates/db_world/2022_07_20_08.sql b/data/sql/updates/db_world/2022_07_20_08.sql new file mode 100644 index 000000000..68e6beea2 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_08.sql @@ -0,0 +1,6 @@ +-- DB update 2022_07_20_07 -> 2022_07_20_08 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 202; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 202) AND (`source_type` = 0) AND (`id` IN (0)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(202, 0, 0, 0, 0, 0, 100, 0, 5000, 8000, 9000, 13000, 0, 11, 7399, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeletal Horror - In Combat - Cast \'Terrify\' (No Repeat)'); diff --git a/data/sql/updates/db_world/2022_07_20_09.sql b/data/sql/updates/db_world/2022_07_20_09.sql new file mode 100644 index 000000000..2685bc2f1 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_09.sql @@ -0,0 +1,7 @@ +-- DB update 2022_07_20_08 -> 2022_07_20_09 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 12119; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 12119) AND (`source_type` = 0) AND (`id` IN (0, 1)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(12119, 0, 0, 0, 0, 0, 100, 0, 5000, 5000, 6500, 6500, 0, 11, 20604, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 'Flamewaker Protector - In Combat - Cast \'Dominate Mind\''), +(12119, 0, 1, 0, 0, 0, 100, 0, 5000, 10000, 7000, 7000, 0, 11, 20605, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Flamewaker Protector - In Combat - Cast \'Cleave\''); diff --git a/data/sql/updates/db_world/2022_07_20_10.sql b/data/sql/updates/db_world/2022_07_20_10.sql new file mode 100644 index 000000000..8fe12a4d2 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_10.sql @@ -0,0 +1,22 @@ +-- DB update 2022_07_20_09 -> 2022_07_20_10 +-- +/* Snakes */ +UPDATE `creature` SET `id1`=11371 WHERE `guid` IN (49096, 49097); +UPDATE `creature` SET `id2`=11372 WHERE `guid` IN (49096, 49097); + +/* Priest can be Axe thrower */ +UPDATE `creature` SET `id2`=11350 WHERE `guid`=49754; + +/* Crocs movement is a scripted action that occurs about every 30 seconds, and all crocs do it--not normal random movement */ +UPDATE `creature` SET `wander_distance`=0, `MovementType`=0 WHERE `id1`=15043; + +/* Reposition a Snake */ +/* Reposition two Trolls */ +DELETE FROM `creature` WHERE `guid` IN (49121, 49122, 49097); +INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES +(49097, 11371, 11372, 0, 309, 0, 0, 1, 1, 0, -11959.5, -1547.96, 40.6727, 3.1776, 7200, 0, 0, 15260, 0, 0, 0, 0, 0, '', 0), +(49121, 11351, 0, 0, 309, 0, 0, 1, 1, 1, -12008.5, -1484.79, 79.1498, 4.87654, 7200, 0, 0, 21364, 0, 0, 0, 0, 0, '', 0), +(49122, 11831, 0, 0, 309, 0, 0, 1, 1, 1, -12004.5, -1483.46, 79.5746, 4.71553, 7200, 0, 0, 24420, 12170, 0, 0, 0, 0, '', 0); + +/* Movetype and wander distance corrections for Snakes and Bats/Bat Riders */ +UPDATE `creature` SET `wander_distance`=2, `MovementType`=1 WHERE `guid` IN (49096, 49097, 49190, 49191, 49192, 49193); diff --git a/data/sql/updates/db_world/2022_07_20_11.sql b/data/sql/updates/db_world/2022_07_20_11.sql new file mode 100644 index 000000000..bd38538ac --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_11.sql @@ -0,0 +1,6 @@ +-- DB update 2022_07_20_10 -> 2022_07_20_11 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 25371 AND `ScriptName` = 'spell_consume_aq20'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (25371, 'spell_consume_aq20'); +DELETE FROM `spell_script_names` WHERE `spell_id` = 25373 AND `ScriptName` = 'spell_gen_10pct_count_pct_from_max_hp'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (25373, 'spell_gen_10pct_count_pct_from_max_hp'); diff --git a/data/sql/updates/db_world/2022_07_20_12.sql b/data/sql/updates/db_world/2022_07_20_12.sql new file mode 100644 index 000000000..04a2d8320 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_12.sql @@ -0,0 +1,4 @@ +-- DB update 2022_07_20_11 -> 2022_07_20_12 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 26180 AND `ScriptName` = 'spell_huhuran_wyvern_sting'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (26180, 'spell_huhuran_wyvern_sting'); diff --git a/data/sql/updates/db_world/2022_07_20_13.sql b/data/sql/updates/db_world/2022_07_20_13.sql new file mode 100644 index 000000000..bc91b0b86 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_13.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_20_12 -> 2022_07_20_13 +-- fix Slim Pickings quest +UPDATE `creature_template` SET `npcflag`=`npcflag`|1 WHERE `entry` = 26809; diff --git a/data/sql/updates/db_world/2022_07_20_14.sql b/data/sql/updates/db_world/2022_07_20_14.sql new file mode 100644 index 000000000..d7262e839 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_14.sql @@ -0,0 +1,6 @@ +-- DB update 2022_07_20_13 -> 2022_07_20_14 +-- +DELETE FROM `creature_addon` WHERE `guid`=144632; +INSERT INTO `creature_addon` (`guid`, `auras`) VALUES +(144632, '8876'); -- Triggers SPELL_THRASH = 3391 + diff --git a/data/sql/updates/db_world/2022_07_20_15.sql b/data/sql/updates/db_world/2022_07_20_15.sql new file mode 100644 index 000000000..3cdcf09bd --- /dev/null +++ b/data/sql/updates/db_world/2022_07_20_15.sql @@ -0,0 +1,47 @@ +-- DB update 2022_07_20_14 -> 2022_07_20_15 +-- +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (15325, 15343, 15320, 15335, 15336, 15319, 15461, 15462, 15505); + +DELETE FROM `smart_scripts` WHERE `entryorguid`IN (15325, 15343, 15320, 15335, 15336, 15319, 15461, 15462, 15505); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +-- swarmguard +(15343, 0, 0, 0, 9, 0, 100, 0, 0, 5, 8000, 12000, 0, 11, 25174, 3, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Qiraji Swarmguard - Within 0-5 Range - Cast \'Sundering Cleave\''), + +-- hive wasp +(15325, 0, 0, 0, 9, 0, 100, 0, 0, 40, 5000, 7000, 0, 11, 25185, 4, 32, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Wasp - Within 0-40 Range - Cast \'Itch\''), + +-- hive soldier +(15320, 0, 0, 0, 0, 0, 100, 0, 1000, 3000, 19000, 23000, 0, 11, 22857, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Soldier - In Combat - Cast \'Retaliation\''), +(15320, 0, 1, 0, 9, 0, 100, 0, 0, 30, 5000, 7000, 0, 11, 25497, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Soldier - Within 0-30 Range - Cast \'Venom Spit\''), + +-- flesh hunter +(15335, 0, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 11, 8876, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - On Respawn - Cast \'Thrash\''), +(15335, 0, 1, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - On Aggro - Set Event Phase 1'), +(15335, 0, 2, 0, 9, 0, 100, 0, 0, 45, 5000, 7000, 0, 11, 25424, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - Within 0-45 Range - Cast \'Poison Bolt\''), +(15335, 0, 3, 0, 24, 2, 100, 0, 25371, 1, 5000, 5000, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - On Target Buffed With \'Consume\' - Set Event Phase 2 (Phase 2)'), +(15335, 0, 4, 0, 28, 0, 100, 0, 5000, 5000, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - On Passenger Removed - Set Event Phase 1'), +(15335, 0, 5, 0, 9, 1, 100, 0, 0, 10, 21000, 24000, 0, 11, 25371, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - Within 0-10 Range - Cast \'Consume\' (Phase 1)'), +(15335, 0, 6, 0, 7, 0, 100, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Flesh Hunter - On Evade - Set Event Phase 1'), + +-- tail lasher +(15336, 0, 0, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Tail Lasher - On Aggro - Set Event Phase 1'), +(15336, 0, 1, 0, 9, 1, 100, 0, 0, 5, 6000, 9000, 0, 11, 25645, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Tail Lasher - Within 0-5 Range - Cast \'Poison\' (Phase 1)'), +(15336, 0, 2, 0, 24, 1, 100, 0, 25645, 5, 5000, 5000, 0, 22, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Tail Lasher - On Target Buffed With \'Poison\' - Set Event Phase 2 (Phase 1)'), +(15336, 0, 3, 0, 24, 2, 100, 0, 25645, 1, 5000, 5000, 0, 22, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Tail Lasher - On Target Buffed With \'Poison\' - Set Event Phase 1 (Phase 2)'), +(15336, 0, 4, 0, 9, 0, 100, 0, 0, 30, 7000, 10000, 0, 11, 25654, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Tail Lasher - Within 0-30 Range - Cast \'Tail Lash\''), +(15336, 0, 5, 0, 7, 0, 100, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Tail Lasher - On Evade - Set Event Phase 0'), + +-- hive collector +(15319, 0, 0, 0, 9, 0, 100, 0, 0, 30, 10000, 16000, 0, 11, 12252, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Collector - Within 0-30 Range - Cast \'Web Spray\''), +(15319, 0, 1, 0, 0, 0, 100, 0, 7000, 11000, 12000, 15000, 0, 11, 3589, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Collector - In Combat - Cast \'Deafening Screech\''), + +-- shrieker scarab +(15461, 0, 0, 0, 9, 0, 100, 0, 0, 40, 14000, 18000, 0, 11, 22886, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Shrieker Scarab - Within 0-40 Range - Cast \'Berserker Charge\''), +(15461, 0, 1, 0, 0, 0, 100, 0, 5000, 9000, 10000, 15000, 0, 11, 26379, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Shrieker Scarab - In Combat - Cast \'Piercing Shriek\''), + +-- spitting scarab +(15462, 0, 0, 0, 9, 0, 100, 0, 0, 40, 14000, 18000, 0, 11, 22886, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Spitting Scarab - Within 0-40 Range - Cast \'Berserker Charge\''), +(15462, 0, 1, 0, 0, 0, 100, 0, 5000, 9000, 4000, 6000, 0, 11, 24334, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Spitting Scarab - In Combat - Cast \'Acid Spit\''), + +-- canal frenzy +(15505, 0, 0, 0, 9, 0, 100, 0, 0, 5, 5000, 8000, 0, 11, 12097, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Canal Frenzy - Within 0-5 Range - Cast \'Pierce Armor\''); diff --git a/data/sql/updates/db_world/2022_07_22_00.sql b/data/sql/updates/db_world/2022_07_22_00.sql new file mode 100644 index 000000000..d59b77543 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_22_00.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_20_15 -> 2022_07_22_00 +-- +UPDATE `creature_loot_template` SET `Chance`='100' WHERE `Item`=20513 AND `Reference`=0 AND `GroupId`=0; diff --git a/data/sql/updates/db_world/2022_07_23_00.sql b/data/sql/updates/db_world/2022_07_23_00.sql new file mode 100644 index 000000000..04e8a96a2 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_23_00.sql @@ -0,0 +1,6 @@ +-- DB update 2022_07_22_00 -> 2022_07_23_00 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 17606; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 17606) AND (`source_type` = 0) AND (`id` IN (1, 2)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(17606, 0, 1, 0, 0, 0, 100, 0, 0, 3000, 4500, 5000, 0, 11, 19816, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Sunhawk Reclaimer - IC - Cast Fireball'); diff --git a/data/sql/updates/db_world/2022_07_23_01.sql b/data/sql/updates/db_world/2022_07_23_01.sql new file mode 100644 index 000000000..5997b7e87 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_23_01.sql @@ -0,0 +1,46 @@ +-- DB update 2022_07_23_00 -> 2022_07_23_01 +-- +ALTER TABLE `pet_levelstats` CHANGE `hp` `hp` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `mana` `mana` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `str` `str` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `agi` `agi` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `sta` `sta` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `inte` `inte` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `spi` `spi` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `min_dmg` `min_dmg` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `max_dmg` `max_dmg` INT UNSIGNED DEFAULT 0 NOT NULL; + +ALTER TABLE `player_classlevelstats` CHANGE `basehp` `basehp` INT UNSIGNED DEFAULT 1 NOT NULL, +CHANGE `basemana` `basemana` INT UNSIGNED DEFAULT 1 NOT NULL; + +ALTER TABLE `player_levelstats` CHANGE `str` `str` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `agi` `agi` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `sta` `sta` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `inte` `inte` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `spi` `spi` INT UNSIGNED DEFAULT 0 NOT NULL; + +ALTER TABLE `creature_classlevelstats` CHANGE `basehp0` `basehp0` INT UNSIGNED DEFAULT 1 NOT NULL, +CHANGE `basehp1` `basehp1` INT UNSIGNED DEFAULT 1 NOT NULL, +CHANGE `basehp2` `basehp2` INT UNSIGNED DEFAULT 1 NOT NULL, +CHANGE `basemana` `basemana` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `basearmor` `basearmor` INT UNSIGNED DEFAULT 1 NOT NULL, +CHANGE `attackpower` `attackpower` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `rangedattackpower` `rangedattackpower` INT UNSIGNED DEFAULT 0 NOT NULL; + +ALTER TABLE `item_template` CHANGE `stat_value1` `stat_value1` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value2` `stat_value2` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value3` `stat_value3` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value4` `stat_value4` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value5` `stat_value5` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value6` `stat_value6` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value7` `stat_value7` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value8` `stat_value8` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value9` `stat_value9` INT DEFAULT 0 NOT NULL, +CHANGE `stat_value10` `stat_value10` INT DEFAULT 0 NOT NULL, +CHANGE `armor` `armor` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `holy_res` `holy_res` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `fire_res` `fire_res` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `nature_res` `nature_res` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `frost_res` `frost_res` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `shadow_res` `shadow_res` INT UNSIGNED DEFAULT 0 NOT NULL, +CHANGE `arcane_res` `arcane_res` INT UNSIGNED DEFAULT 0 NOT NULL; diff --git a/data/sql/updates/db_world/2022_07_24_00.sql b/data/sql/updates/db_world/2022_07_24_00.sql new file mode 100644 index 000000000..d4530dbdf --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_00.sql @@ -0,0 +1,12 @@ +-- DB update 2022_07_23_01 -> 2022_07_24_00 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 7453; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 7453) AND (`source_type` = 0) AND (`id` IN (0, 1)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(7453, 0, 0, 0, 0, 0, 100, 0, 7000, 11000, 15000, 18000, 0, 11, 15798, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Moontouched Owlbeast - In Combat - Cast \'Moonfire\''), +(7453, 0, 1, 0, 0, 0, 100, 0, 0, 0, 18000, 21000, 0, 11, 12160, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Moontouched Owlbeast - In Combat - Cast \'Rejuvenation\''); + +DELETE FROM `creature_template_spell` WHERE (`CreatureID` = 7453) AND (`Index` IN (0, 1)); +INSERT INTO `creature_template_spell` (`CreatureID`, `Index`, `Spell`, `VerifiedBuild`) VALUES +(7453, 0, 15798, 12340), +(7453, 1, 12160, 12340); diff --git a/data/sql/updates/db_world/2022_07_24_01.sql b/data/sql/updates/db_world/2022_07_24_01.sql new file mode 100644 index 000000000..e43d979c3 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_01.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_24_00 -> 2022_07_24_01 +-- +UPDATE `reference_loot_template` SET `Chance`=0 WHERE `Entry`=35026 AND `Item` IN (22407, 22406, 22405, 22404, 22403); diff --git a/data/sql/updates/db_world/2022_07_24_02.sql b/data/sql/updates/db_world/2022_07_24_02.sql new file mode 100644 index 000000000..4d3fe7bc7 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_02.sql @@ -0,0 +1,39 @@ +-- DB update 2022_07_24_01 -> 2022_07_24_02 +-- Warmaul Chef Bufferlo +UPDATE `creature_template` SET `AIName`="SmartAI", `speed_walk`=1 WHERE `entry`=18440; +DELETE FROM `smart_scripts` WHERE `entryorguid`=18440 AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (1844000,1844001,1844002) AND `source_type`=9; +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 +(18440,0,0,0,4,0,100,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Aggro - Say Line 0"), +(18440,0,1,0,1,0,100,0,10000,30000,80000,100000,0,87,1844000,1844001,1844002,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - Out of Combat - Run Random Script"), +(18440,0,2,0,0,0,100,0,7000,12000,7000,12000,0,11,32376,0,0,0,0,0,2,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - In Combat - Cast 'Tenderize'"), +(18440,0,3,0,0,0,100,0,4000,6000,14000,18000,0,11,32378,0,0,0,0,0,2,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - In Combat - Cast 'Filet'"), +(18440,0,4,0,4,0,100,0,0,0,0,0,0,11,31994,0,0,0,0,0,2,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Aggro - Cast 'Shoulder Charge'"), +(1844000,9,0,0,0,0,100,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 1"), +(1844000,9,1,0,0,0,100,0,6000,6000,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 2"), +(1844001,9,0,0,0,0,100,0,0,0,0,0,0,5,36,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Play Emote 36"), +(1844001,9,1,0,0,0,100,0,2000,2000,0,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 3"), +(1844002,9,0,0,0,0,100,0,0,0,0,0,0,5,35,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Play Emote 35"), +(1844002,9,1,0,0,0,100,0,2000,2000,0,0,0,1,4,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 4"), +(1844002,9,2,0,0,0,100,0,5000,5000,0,0,0,1,5,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 5"), +(1844002,9,3,0,0,0,100,0,4000,4000,0,0,0,1,6,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 6"), +(1844002,9,4,0,0,0,100,0,4000,4000,0,0,0,1,7,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 7"), +(1844002,9,5,0,0,0,100,0,2000,2000,0,0,0,5,35,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Play Emote 35"), +(1844002,9,6,0,0,0,100,0,2000,2000,0,0,0,1,8,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 8"), +(1844002,9,7,0,0,0,100,0,8000,8000,0,0,0,1,9,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Say Line 9"), +(1844002,9,8,0,0,0,100,0,3000,3000,0,0,0,5,153,0,0,0,0,0,1,0,0,0,0,0,0,0,"Warmaul Chef Bufferlo - On Script - Play Emote 153"); + +DELETE FROM `creature_text` WHERE `CreatureID`=18440; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(18440,0,0,"IT DUZ WUT IT'S TOLD!",12,0,100,0,0,0,15419,0,"Warmaul Chef Bufferlo"), +(18440,0,1,"GET IN DA STEW!",12,0,100,0,0,0,15420,0,"Warmaul Chef Bufferlo"), +(18440,0,2,"YOU GUD IN DA BELLY!",12,0,100,0,0,0,15421,0,"Warmaul Chef Bufferlo"), +(18440,1,0,"Your daddy pay Warmaul and maybe we no eat you.",12,0,100,1,0,0,15426,0,"Warmaul Chef Bufferlo"), +(18440,2,0,"Ha-ha! Just kidding. We eat you for shure anyway!",12,0,100,11,0,0,15427,0,"Warmaul Chef Bufferlo"), +(18440,3,0,"BAM! Look at dat gristle sizzle!",12,0,100,1,0,0,15430,0,"Warmaul Chef Bufferlo"), +(18440,4,0,"And dis is da recipe for da bestest Broken chowder!",12,0,100,1,0,0,15431,0,"Warmaul Chef Bufferlo"), +(18440,5,0,"First you need da spices.",12,0,100,1,0,0,15432,0,"Warmaul Chef Bufferlo"), +(18440,6,0,"Da salt goes into da pot...",12,0,100,35,0,0,15433,0,"Warmaul Chef Bufferlo"), +(18440,7,0,"Den you put da pepper in da pot...",12,0,100,0,0,0,15434,0,"Warmaul Chef Bufferlo"), +(18440,8,0,"Now we gonna kick it up a notch wit da secret ingra... ingor... inrag... da secret sauce!",12,0,100,43,0,0,15435,0,"Warmaul Chef Bufferlo"), +(18440,9,0,"And last, we put in da Corki!",12,0,100,1,0,0,15436,0,"Warmaul Chef Bufferlo"); diff --git a/data/sql/updates/db_world/2022_07_24_03.sql b/data/sql/updates/db_world/2022_07_24_03.sql new file mode 100644 index 000000000..cb7e1ed95 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_03.sql @@ -0,0 +1,5 @@ +-- DB update 2022_07_24_02 -> 2022_07_24_03 +-- +DELETE FROM `spell_script_names` WHERE `spell_id`=56246; +INSERT INTO `spell_script_names` VALUES +(56246,'spell_warl_glyph_of_felguard'); diff --git a/data/sql/updates/db_world/2022_07_24_04.sql b/data/sql/updates/db_world/2022_07_24_04.sql new file mode 100644 index 000000000..00eb2fee6 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_04.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_24_03 -> 2022_07_24_04 +-- +UPDATE `spell_proc_event` SET `SpellFamilyName`=11, `SpellFamilyMask0`=0x00000003, `SpellFamilyMask1`=0x00001000 WHERE `entry`=16166; diff --git a/data/sql/updates/db_world/2022_07_24_05.sql b/data/sql/updates/db_world/2022_07_24_05.sql new file mode 100644 index 000000000..f81a7fe4c --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_05.sql @@ -0,0 +1,13 @@ +-- DB update 2022_07_24_04 -> 2022_07_24_05 +-- +-- Crocs movement is a scripted action that occurs about every 30 seconds, not normal random movement +UPDATE `creature` SET `wander_distance`=0, `MovementType`=0 WHERE `id1`=15043; + +DELETE FROM `smart_scripts` WHERE `entryorguid`=15043 AND `source_type`=0; +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(15043, 0, 0, 0, 0, 0, 100, 0, 8000, 9000, 11000, 12000, 0, 11, 3604, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Zulian Crocolisk - In Combat - Cast \'Tendon Rip\''), +(15043, 0, 1, 0, 0, 0, 100, 0, 17000, 19000, 22000, 24000, 0, 11, 13445, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Zulian Crocolisk - In Combat - Cast \'Rend\''), +(15043, 0, 2, 0, 1, 0, 100, 0, 30000, 30000, 40000, 40000, 0, 89, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'ZG Crocolisks will wander a small amount for about 10 seconds out of every 40 (wander on-2)'), +(15043, 0, 3, 0, 1, 0, 100, 0, 39500, 39500, 40000, 40000, 0, 89, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'ZG Crocolisks will wander a small amount for about 10 seconds out of every 40 (wander on-0)'), +(15043, 0, 4, 0, 1, 0, 100, 0, 39999, 39999, 40000, 40000, 0, 101, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Send ZG Croclisks toward home position to control wandering range (set home POS)'), +(15043, 0, 5, 0, 1, 0, 100, 0, 40000, 40000, 40000, 40000, 0, 24, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Send ZG Croclisks toward home position to control wandering range (reset to home POS)'); diff --git a/data/sql/updates/db_world/2022_07_24_06.sql b/data/sql/updates/db_world/2022_07_24_06.sql new file mode 100644 index 000000000..d8b0e6153 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_06.sql @@ -0,0 +1,19 @@ +-- DB update 2022_07_24_05 -> 2022_07_24_06 + +-- Immune to Taunt +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|256 WHERE `entry`=15370; + +-- Disable exp on Buru egg / Hive'zara hatchling +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|64 WHERE `entry` IN (15514,15521); + +-- New smartAI - despawn +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=15521; +DELETE FROM `smart_scripts` WHERE `entryorguid`= 15521 AND `source_type`= 0 AND `id`= 0; +INSERT INTO `smart_scripts` (`entryorguid`, `event_type`, `event_flags`, `event_param1`, `event_param2`, `action_type`, `action_param1`, `target_type`, `comment`) VALUES +(15521, 1, 1, 10000, 10000, 41, 500, 1, 'Hive\'Zara Hatchling - Out of Combat - Despawn (No Repeat)'); + +-- Root egg properly - avoid reset +DELETE FROM `creature_template_movement` WHERE `CreatureId`=15514; +INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`) VALUES +(15514, 1, 1, 0, 1, 0, 0); + diff --git a/data/sql/updates/db_world/2022_07_24_07.sql b/data/sql/updates/db_world/2022_07_24_07.sql new file mode 100644 index 000000000..e05b9a2fa --- /dev/null +++ b/data/sql/updates/db_world/2022_07_24_07.sql @@ -0,0 +1,5 @@ +-- DB update 2022_07_24_06 -> 2022_07_24_07 +-- +UPDATE `gameobject_template` SET `ScriptName` = 'go_sand_trap' WHERE `entry` = 180647; + +UPDATE `creature_text` SET `TextRange` = 3 WHERE `CreatureID` = 15339 AND `GroupID` = 5; diff --git a/data/sql/updates/db_world/2022_07_25_00.sql b/data/sql/updates/db_world/2022_07_25_00.sql new file mode 100644 index 000000000..805766367 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_00.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_24_07 -> 2022_07_25_00 +-- +UPDATE `smart_scripts` SET `action_param1`=500 WHERE `entryorguid`=28788 AND `source_type`=0 AND `id`=5; diff --git a/data/sql/updates/db_world/2022_07_25_01.sql b/data/sql/updates/db_world/2022_07_25_01.sql new file mode 100644 index 000000000..09f4321f4 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_01.sql @@ -0,0 +1,11 @@ +-- DB update 2022_07_25_00 -> 2022_07_25_01 +DELETE FROM `creature_formations` WHERE `leaderguid` IN (144488, 144486, 144484, 144483); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144488, 144488, 0, 0, 3, 0, 0), +(144488, 144489, 0, 0, 3, 0, 0), +(144486, 144486, 0, 0, 3, 0, 0), +(144486, 144487, 0, 0, 3, 0, 0), +(144484, 144484, 0, 0, 3, 0, 0), +(144484, 144485, 0, 0, 3, 0, 0), +(144483, 144483, 0, 0, 3, 0, 0), +(144483, 144482, 0, 0, 3, 0, 0); diff --git a/data/sql/updates/db_world/2022_07_25_02.sql b/data/sql/updates/db_world/2022_07_25_02.sql new file mode 100644 index 000000000..5fc890f96 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_02.sql @@ -0,0 +1,53 @@ +-- DB update 2022_07_25_01 -> 2022_07_25_02 +DELETE FROM `creature_formations` WHERE `leaderguid` IN (144698, 144695, 144715, 144684, 144726); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144698, 144698, 0, 0, 3, 0, 0), +(144698, 144723, 0, 0, 3, 0, 0), +(144698, 144699, 0, 0, 3, 0, 0), +(144698, 144725, 0, 0, 3, 0, 0), +(144698, 144700, 0, 0, 3, 0, 0), +(144698, 144721, 0, 0, 3, 0, 0), +(144698, 144722, 0, 0, 3, 0, 0), +(144698, 144724, 0, 0, 3, 0, 0), +(144698, 144697, 0, 0, 3, 0, 0), +(144698, 144696, 0, 0, 3, 0, 0), +(144695, 144695, 0, 0, 3, 0, 0), +(144695, 144720, 0, 0, 3, 0, 0), +(144695, 144718, 0, 0, 3, 0, 0), +(144695, 144694, 0, 0, 3, 0, 0), +(144695, 144717, 0, 0, 3, 0, 0), +(144695, 144692, 0, 0, 3, 0, 0), +(144695, 144716, 0, 0, 3, 0, 0), +(144695, 144690, 0, 0, 3, 0, 0), +(144695, 144693, 0, 0, 3, 0, 0), +(144695, 144719, 0, 0, 3, 0, 0), +(144715, 144715, 0, 0, 3, 0, 0), +(144715, 144688, 0, 0, 3, 0, 0), +(144715, 144691, 0, 0, 3, 0, 0), +(144715, 144714, 0, 0, 3, 0, 0), +(144715, 144689, 0, 0, 3, 0, 0), +(144715, 144713, 0, 0, 3, 0, 0), +(144715, 144712, 0, 0, 3, 0, 0), +(144715, 144686, 0, 0, 3, 0, 0), +(144715, 144687, 0, 0, 3, 0, 0), +(144715, 144711, 0, 0, 3, 0, 0), +(144684, 144684, 0, 0, 3, 0, 0), +(144684, 144710, 0, 0, 3, 0, 0), +(144684, 144708, 0, 0, 3, 0, 0), +(144684, 144709, 0, 0, 3, 0, 0), +(144684, 144683, 0, 0, 3, 0, 0), +(144684, 144682, 0, 0, 3, 0, 0), +(144684, 144681, 0, 0, 3, 0, 0), +(144684, 144706, 0, 0, 3, 0, 0), +(144684, 144707, 0, 0, 3, 0, 0), +(144684, 144685, 0, 0, 3, 0, 0), +(144726, 144726, 0, 0, 3, 0, 0), +(144726, 144727, 0, 0, 3, 0, 0), +(144726, 144703, 0, 0, 3, 0, 0), +(144726, 144729, 0, 0, 3, 0, 0), +(144726, 144704, 0, 0, 3, 0, 0), +(144726, 144702, 0, 0, 3, 0, 0), +(144726, 144701, 0, 0, 3, 0, 0), +(144726, 144728, 0, 0, 3, 0, 0), +(144726, 144730, 0, 0, 3, 0, 0), +(144726, 144705, 0, 0, 3, 0, 0); diff --git a/data/sql/updates/db_world/2022_07_25_03.sql b/data/sql/updates/db_world/2022_07_25_03.sql new file mode 100644 index 000000000..bff1790eb --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_03.sql @@ -0,0 +1,4 @@ +-- DB update 2022_07_25_02 -> 2022_07_25_03 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 25185 AND `ScriptName` = 'spell_itch_aq20'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (25185, 'spell_itch_aq20'); diff --git a/data/sql/updates/db_world/2022_07_25_04.sql b/data/sql/updates/db_world/2022_07_25_04.sql new file mode 100644 index 000000000..28073f0bd --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_04.sql @@ -0,0 +1,77 @@ +-- DB update 2022_07_25_03 -> 2022_07_25_04 +-- Captain Qeez +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144676; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144676, 144676, 0, 0, 11, 0, 0), +(144676, 144611, 0, 0, 11, 0, 0), +(144676, 144656, 0, 0, 11, 0, 0), +(144676, 144653, 0, 0, 11, 0, 0), +(144676, 144655, 0, 0, 11, 0, 0), +(144676, 144610, 0, 0, 11, 0, 0), +(144676, 144654, 0, 0, 11, 0, 0); + +-- Tubid +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144677; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144677, 144677, 0, 0, 11, 0, 0), +(144677, 144658, 0, 0, 11, 0, 0), +(144677, 144616, 0, 0, 11, 0, 0), +(144677, 144617, 0, 0, 11, 0, 0), +(144677, 144619, 0, 0, 11, 0, 0), +(144677, 144660, 0, 0, 11, 0, 0), +(144677, 144659, 0, 0, 11, 0, 0); + +-- Drenn +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144674; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144674, 144674, 0, 0, 11, 0, 0), +(144674, 144618, 0, 0, 11, 0, 0), +(144674, 144657, 0, 0, 11, 0, 0), +(144674, 144614, 0, 0, 11, 0, 0), +(144674, 144613, 0, 0, 11, 0, 0), +(144674, 144612, 0, 0, 11, 0, 0), +(144674, 144615, 0, 0, 11, 0, 0); + +-- Yeggeth +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144652; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144652, 144652, 0, 0, 11, 0, 0), +(144652, 144664, 0, 0, 11, 0, 0), +(144652, 144622, 0, 0, 11, 0, 0), +(144652, 144624, 0, 0, 11, 0, 0), +(144652, 144663, 0, 0, 11, 0, 0), +(144652, 144621, 0, 0, 11, 0, 0), +(144652, 144620, 0, 0, 11, 0, 0); + +-- Xurrem +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144675; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144675, 144675, 0, 0, 11, 0, 0), +(144675, 144625, 0, 0, 11, 0, 0), +(144675, 144623, 0, 0, 11, 0, 0), +(144675, 144665, 0, 0, 11, 0, 0), +(144675, 144626, 0, 0, 11, 0, 0), +(144675, 144662, 0, 0, 11, 0, 0), +(144675, 144661, 0, 0, 11, 0, 0); + +-- Pakkon +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144673; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144673, 144673, 0, 0, 11, 0, 0), +(144673, 144669, 0, 0, 11, 0, 0), +(144673, 144630, 0, 0, 11, 0, 0), +(144673, 144670, 0, 0, 11, 0, 0), +(144673, 144631, 0, 0, 11, 0, 0), +(144673, 144672, 0, 0, 11, 0, 0), +(144673, 144671, 0, 0, 11, 0, 0); + +-- Zerram +DELETE FROM `creature_formations` WHERE `leaderGUID` = 144651; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(144651, 144651, 0, 0, 11, 0, 0), +(144651, 144668, 0, 0, 11, 0, 0), +(144651, 144629, 0, 0, 11, 0, 0), +(144651, 144667, 0, 0, 11, 0, 0), +(144651, 144628, 0, 0, 11, 0, 0), +(144651, 144666, 0, 0, 11, 0, 0), +(144651, 144627, 0, 0, 11, 0, 0); diff --git a/data/sql/updates/db_world/2022_07_25_05.sql b/data/sql/updates/db_world/2022_07_25_05.sql new file mode 100644 index 000000000..feb66b714 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_05.sql @@ -0,0 +1,7 @@ +-- DB update 2022_07_25_04 -> 2022_07_25_05 +-- +DELETE FROM `creature_template_movement` WHERE `creatureId` = 15802; +INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES +(15802, 1, 0, 0, 1, 0, 0, 0); + +UPDATE `creature_template` SET `ScriptName` = '' WHERE `entry` = 15802; diff --git a/data/sql/updates/db_world/2022_07_25_06.sql b/data/sql/updates/db_world/2022_07_25_06.sql new file mode 100644 index 000000000..a11a226dd --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_06.sql @@ -0,0 +1,19 @@ +-- DB update 2022_07_25_05 -> 2022_07_25_06 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15343; +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15343) AND (`source_type` = 0) AND (`id` IN (0)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(15343, 0, 0, 0, 9, 0, 100, 0, 0, 5, 5000, 7000, 0, 11, 25174, 3, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Qiraji Swarmguard - Within 0-5 Range - Cast \'Sundering Cleave\''); + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15325; +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15325) AND (`source_type` = 0) AND (`id` IN (0)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(15325, 0, 0, 0, 9, 0, 100, 0, 0, 40, 11000, 16000, 0, 11, 25185, 4, 3, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Wasp - Within 0-40 Range - Cast \'Itch\''); + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15338; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 15338); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(15338, 0, 0, 0, 0, 0, 100, 0, 5000, 9000, 8000, 11000, 0, 11, 25756, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - In Combat - Cast \'Purge\''), +(15338, 0, 1, 0, 0, 0, 100, 0, 2000, 4000, 6000, 6000, 0, 11, 25755, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - In Combat - Cast \'Drain Mana\''), +(15338, 0, 2, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 27627, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - On Just Died - Cast \'Serverside - Drop Obsidian\''), +(15338, 0, 3, 0, 7, 0, 100, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - On Respawn - Set Mana To 0'); +UPDATE `creature_template` SET `unit_flags2` = 0 WHERE (`entry` = 15338); diff --git a/data/sql/updates/db_world/2022_07_25_07.sql b/data/sql/updates/db_world/2022_07_25_07.sql new file mode 100644 index 000000000..91426fa0d --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_07.sql @@ -0,0 +1,7 @@ +-- DB update 2022_07_25_06 -> 2022_07_25_07 + +-- Ossirian immune to Taunt +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|256 WHERE `entry`=15339; + +-- Sand Vortex UNIT_FLAG_NOT_SELECTABLE +UPDATE `creature_template` SET `unit_flags`=`unit_flags`|33554432 WHERE `entry`=15428; diff --git a/data/sql/updates/db_world/2022_07_25_08.sql b/data/sql/updates/db_world/2022_07_25_08.sql new file mode 100644 index 000000000..0e6d9ddf2 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_25_08.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_25_07 -> 2022_07_25_08 +-- +UPDATE `creature_template` SET `ScriptName` = 'npc_anubisath_guardian' WHERE `entry` = 15355; diff --git a/data/sql/updates/db_world/2022_07_26_00.sql b/data/sql/updates/db_world/2022_07_26_00.sql new file mode 100644 index 000000000..e88653012 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_00.sql @@ -0,0 +1,9 @@ +-- DB update 2022_07_25_08 -> 2022_07_26_00 +-- + +UPDATE `creature_template` SET `mingold`=0, `maxgold`=0, `AIName`='SmartAI' WHERE `entry`=15527; +DELETE FROM `smart_scripts` WHERE `entryorguid`=15527 AND `source_type`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `target_type`, `comment`) VALUES +(15527, 0, 0, 0, 0, 0, 100, 0, 6000, 6000, 6000, 6000, 11, 25679, 2, 2, 'Mana Fiend - In Combat - Cast Arcane Explosion'), +(15527, 0, 1, 0, 13, 0, 100, 0, 10000, 20000, 0, 0, 11, 15122, 0, 2, 'Mana Fiend - In Combat - Cast Counterspell'); + diff --git a/data/sql/updates/db_world/2022_07_26_01.sql b/data/sql/updates/db_world/2022_07_26_01.sql new file mode 100644 index 000000000..49814d44c --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_01.sql @@ -0,0 +1,2 @@ +-- DB update 2022_07_26_00 -> 2022_07_26_01 +UPDATE `creature_onkill_reputation` SET `MaxStanding1` = 5 WHERE (`creature_id` IN (7157, 7156, 7158)); diff --git a/data/sql/updates/db_world/2022_07_26_02.sql b/data/sql/updates/db_world/2022_07_26_02.sql new file mode 100644 index 000000000..d69db58fc --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_02.sql @@ -0,0 +1,13 @@ +-- DB update 2022_07_26_01 -> 2022_07_26_02 +-- +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_moam_mana_drain_filter'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(25676, 'spell_moam_mana_drain_filter'); + +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_moam_summon_mana_fiends'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(25684, 'spell_moam_summon_mana_fiends'); + +DELETE FROM `creature_text` WHERE `CreatureID` = 15340 AND `GroupID` = 2; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(15340, 2, 0, '%s drains your mana and turns to stone.', 16, 0, 100, 0, 0, 0, 11474, 0, 'moam EMOTE_STONE_PHASE'); diff --git a/data/sql/updates/db_world/2022_07_26_03.sql b/data/sql/updates/db_world/2022_07_26_03.sql new file mode 100644 index 000000000..eae6e9558 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_03.sql @@ -0,0 +1,5 @@ +-- DB update 2022_07_26_02 -> 2022_07_26_03 +-- +DELETE FROM `spell_custom_attr` WHERE `spell_id` = 5255; +INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES +(5255, 0x00008000); diff --git a/data/sql/updates/db_world/2022_07_26_04.sql b/data/sql/updates/db_world/2022_07_26_04.sql new file mode 100644 index 000000000..0e601cfc5 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_04.sql @@ -0,0 +1,9 @@ +-- DB update 2022_07_26_03 -> 2022_07_26_04 +-- + +UPDATE `creature_template` SET `mingold`=0, `maxgold`=0 WHERE `entry`=15546; +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|256 WHERE `entry`=15369; +DELETE FROM `creature_addon` WHERE `guid`=144641; +INSERT INTO `creature_addon` (`guid`, `auras`) VALUES +(144641, '8876'); -- Triggers SPELL_THRASH = 3391 + diff --git a/data/sql/updates/db_world/2022_07_26_05.sql b/data/sql/updates/db_world/2022_07_26_05.sql new file mode 100644 index 000000000..efb011b83 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_05.sql @@ -0,0 +1,760 @@ +-- DB update 2022_07_26_04 -> 2022_07_26_05 +-- +/* Vile Familiar - GUID 4701 */ + + +SET @NPC := 4701; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -35.7399, `position_y` = -4228.09, `position_z` = 65.2618, `orientation` = 3.89663 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -35.7399, -4228.09, 65.2618, 100.0, 0), +(@PATH, 2, -25.1474, -4238.52, 68.0743, 100.0, 0), +(@PATH, 3, -28.5747, -4245.48, 68.4759, 100.0, 0), +(@PATH, 4, -23.6166, -4258.85, 66.6592, 100.0, 0), +(@PATH, 5, -35.6993, -4270.22, 66.894, 100.0, 0), +(@PATH, 6, -56.3938, -4280.35, 70.0308, 100.0, 0), +(@PATH, 7, -53.3781, -4302.13, 69.8885, 100.0, 0), +(@PATH, 8, -39.7387, -4310.99, 70.2738, 100.0, 0), +(@PATH, 9, -53.3781, -4302.13, 69.8885, 100.0, 0), +(@PATH, 10, -56.3938, -4280.35, 70.0308, 100.0, 0), +(@PATH, 11, -35.6993, -4270.22, 66.894, 100.0, 0), +(@PATH, 12, -23.6166, -4258.85, 66.6592, 100.0, 0), +(@PATH, 13, -28.5747, -4245.48, 68.4759, 100.0, 0), +(@PATH, 14, -25.1474, -4238.52, 68.0743, 100.0, 0), +(@PATH, 15, -35.7399, -4228.09, 65.2619, 100.0, 0), +(@PATH, 16, -49.5318, -4222.88, 62.2678, 100.0, 0); + + +/* Vile Familiar - GUID 4705 */ + + +SET @NPC := 4705; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -152.718, `position_y` = -4264.43, `position_z` = 61.5234, `orientation` = 1.04177 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -152.718, -4264.43, 61.5234, 100.0, 0), +(@PATH, 2, -150.795, -4251.99, 59.8122, 100.0, 0), +(@PATH, 3, -140.417, -4234.24, 58.089, 100.0, 0), +(@PATH, 4, -127.943, -4230.0, 57.2045, 100.0, 0), +(@PATH, 5, -110.444, -4210.7, 54.7955, 100.0, 0), +(@PATH, 6, -96.4095, -4201.51, 51.431, 100.0, 0), +(@PATH, 7, -80.8383, -4204.42, 49.8348, 100.0, 0), +(@PATH, 8, -79.6806, -4223.97, 53.0284, 100.0, 0), +(@PATH, 9, -83.5118, -4242.02, 52.784, 100.0, 0), +(@PATH, 10, -96.4792, -4250.83, 51.9981, 100.0, 0), +(@PATH, 11, -83.5118, -4242.02, 52.784, 100.0, 0), +(@PATH, 12, -79.6806, -4223.97, 53.0284, 100.0, 0), +(@PATH, 13, -80.8383, -4204.42, 49.8348, 100.0, 0), +(@PATH, 14, -96.4095, -4201.51, 51.431, 100.0, 0), +(@PATH, 15, -110.265, -4210.5, 54.7808, 100.0, 0), +(@PATH, 16, -127.943, -4230.0, 57.2045, 100.0, 0), +(@PATH, 17, -140.286, -4234.02, 58.09, 100.0, 0), +(@PATH, 18, -150.776, -4251.96, 59.792, 100.0, 0), +(@PATH, 19, -152.797, -4264.3, 61.4815, 100.0, 0), +(@PATH, 20, -145.721, -4275.72, 63.287, 100.0, 0); + +/* Sen'jin Watcher - GUID 6401 */ + + +SET @NPC := 6401; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -820.061, `position_y` = -4892.82, `position_z` = 19.3183, `orientation` = 3.33843 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -820.061, -4892.82, 19.3183, 100.0, 0), +(@PATH, 2, -814.445, -4894.38, 19.1953, 100.0, 0), +(@PATH, 3, -810.197, -4898.55, 19.2201, 100.0, 0), +(@PATH, 4, -805.71, -4902.39, 19.3582, 100.0, 0), +(@PATH, 5, -800.273, -4902.95, 19.4798, 100.0, 0), +(@PATH, 6, -794.502, -4901.52, 19.5224, 100.0, 0), +(@PATH, 7, -791.733, -4902.05, 19.5467, 100.0, 0), +(@PATH, 8, -789.871, -4904.44, 19.5926, 100.0, 0), +(@PATH, 9, -790.881, -4909.7, 19.5959, 100.0, 0), +(@PATH, 10, -793.125, -4911.08, 19.5652, 100.0, 0), +(@PATH, 11, -798.939, -4909.47, 19.4492, 100.0, 0), +(@PATH, 12, -801.808, -4908.93, 19.3913, 100.0, 0), +(@PATH, 13, -804.86, -4909.7, 19.3525, 100.0, 0), +(@PATH, 14, -808.699, -4913.92, 19.2707, 100.0, 0), +(@PATH, 15, -811.502, -4919.28, 19.3742, 100.0, 0), +(@PATH, 16, -815.664, -4923.35, 19.5169, 100.0, 0), +(@PATH, 17, -821.037, -4926.27, 19.7472, 100.0, 0), +(@PATH, 18, -824.913, -4930.46, 20.2496, 100.0, 0), +(@PATH, 19, -825.216, -4933.02, 20.4924, 100.0, 0), +(@PATH, 20, -822.131, -4938.15, 20.9481, 100.0, 0), +(@PATH, 21, -822.812, -4941.48, 21.2641, 100.0, 0), +(@PATH, 22, -828.34, -4939.55, 21.1166, 100.0, 0), +(@PATH, 23, -831.006, -4931.77, 20.6677, 100.0, 0), +(@PATH, 24, -833.433, -4930.48, 20.7289, 100.0, 0), +(@PATH, 25, -835.654, -4928.46, 20.7985, 100.0, 0), +(@PATH, 26, -839.542, -4923.88, 20.6797, 100.0, 0), +(@PATH, 27, -840.869, -4921.56, 20.6249, 100.0, 0), +(@PATH, 28, -842.204, -4918.86, 20.5327, 100.0, 0), +(@PATH, 29, -842.497, -4916.01, 20.4017, 100.0, 0), +(@PATH, 30, -840.453, -4910.24, 20.1169, 100.0, 0), +(@PATH, 31, -838.588, -4907.94, 19.9559, 100.0, 0), +(@PATH, 32, -833.656, -4904.45, 19.8107, 100.0, 0), +(@PATH, 33, -831.472, -4902.45, 19.8099, 100.0, 0), +(@PATH, 34, -829.256, -4897.08, 19.89, 100.0, 0), +(@PATH, 35, -828.472, -4894.54, 19.858, 100.0, 0); + + +/* Sen'jin Watcher - GUID 7318 */ + + +SET @NPC := 7318; +SET @PATH := @NPC * 10; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -751.532, -4937.42, 22.0626, 1.39087, 0), +(@PATH, 2, -749.446, -4925.95, 21.7179, 1.40658, 0), +(@PATH, 3, -748.146, -4909.12, 21.6451, 1.53224, 0), +(@PATH, 4, -749.044, -4894.65, 21.3131, 1.80792, 0), +(@PATH, 5, -758.065, -4886.38, 20.7674, 2.42367, 0), +(@PATH, 6, -769.284, -4881.33, 20.2048, 2.81558, 0), +(@PATH, 7, -786.327, -4873.79, 19.3151, 2.69777, 0), +(@PATH, 8, -800.025, -4868.83, 19.0121, 2.81558, 0), +(@PATH, 9, -814.01, -4868.4, 19.1711, 3.05199, 0), +(@PATH, 10, -830.176, -4867.12, 20.0416, 3.19336, 0), +(@PATH, 11, -840.925, -4866.71, 20.9414, 3.11796, 0), +(@PATH, 12, -852.233, -4866.44, 20.6684, 3.11796, 0), +(@PATH, 13, -862.73, -4866.2, 19.5395, 3.11796, 0), +(@PATH, 14, -877.267, -4867.57, 15.675, 3.35358, 0), +(@PATH, 15, -889.625, -4876.12, 11.69, 4.09814, 0), +(@PATH, 16, -892.882, -4882.87, 10.4069, 4.41387, 0), +(@PATH, 17, -894.161, -4891.19, 9.9882, 4.72724, 0), +(@PATH, 18, -891.952, -4904.18, 11.096, 5.00292, 0), +(@PATH, 19, -887.942, -4917.59, 13.5855, 5.00292, 0), +(@PATH, 20, -885.714, -4929.01, 15.4245, 4.84505, 0), +(@PATH, 21, -884.325, -4939.42, 16.5051, 4.84505, 0), +(@PATH, 22, -882.937, -4949.83, 17.3169, 4.84505, 0), +(@PATH, 23, -881.758, -4958.38, 17.6026, 5.00292, 0), +(@PATH, 24, -877.399, -4967.48, 17.6634, 5.3964, 0), +(@PATH, 25, -869.496, -4975.38, 16.6692, 5.55427, 0), +(@PATH, 26, -860.011, -4982.71, 14.9847, 5.67208, 0), +(@PATH, 27, -852.52, -4987.43, 14.0936, 5.78989, 0), +(@PATH, 28, -840.341, -4990.7, 14.844, 6.18102, 0), +(@PATH, 29, -830.497, -4989.98, 15.4556, 0.13345, 0), +(@PATH, 30, -819.594, -4986.79, 16.2936, 0.369069, 0), +(@PATH, 31, -809.257, -4982.2, 17.4642, 0.446824, 0), +(@PATH, 32, -793.258, -4973.57, 18.1898, 0.486879, 0), +(@PATH, 33, -775.559, -4963.22, 20.2241, 0.564633, 0), +(@PATH, 34, -763.732, -4955.73, 21.347, 0.564633, 0), +(@PATH, 35, -757.087, -4948.8, 21.8513, 0.878007, 0), +(@PATH, 36, -750.98, -4940.85, 22.1672, 0.995817, 0); + + +/* Sen'jin Watcher - GUID 7324 */ + + +SET @NPC := 7324; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -772.175, `position_y` = -4941.56, `position_z` = 36.863, `orientation` = 2.03416 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -772.175, -4941.56, 36.863, 100.0, 0), +(@PATH, 2, -774.724, -4940.84, 38.2501, 100.0, 0), +(@PATH, 3, -777.686, -4940.8, 38.2811, 100.0, 0), +(@PATH, 4, -779.612, -4942.97, 38.2811, 100.0, 0), +(@PATH, 5, -781.083, -4945.55, 38.2811, 100.0, 0), +(@PATH, 6, -786.085, -4947.83, 38.2811, 100.0, 0), +(@PATH, 7, -788.325, -4946.54, 38.2811, 100.0, 0), +(@PATH, 8, -789.578, -4943.82, 38.2811, 100.0, 0), +(@PATH, 9, -789.76, -4940.87, 38.2811, 100.0, 0), +(@PATH, 10, -784.81, -4937.9, 38.2811, 100.0, 0), +(@PATH, 11, -779.324, -4939.52, 38.2811, 100.0, 0), +(@PATH, 12, -776.578, -4940.72, 38.2811, 100.0, 0), +(@PATH, 13, -768.679, -4942.92, 34.9, 100.0, 0), +(@PATH, 14, -766.035, -4944.11, 33.9918, 100.0, 0), +(@PATH, 15, -763.665, -4945.41, 32.7905, 100.0, 0), +(@PATH, 16, -762.145, -4947.73, 31.7292, 100.0, 0), +(@PATH, 17, -762.604, -4953.17, 29.8729, 100.0, 0), +(@PATH, 18, -764.436, -4955.34, 29.2952, 100.0, 0), +(@PATH, 19, -767.039, -4956.27, 28.2648, 100.0, 0), +(@PATH, 20, -772.457, -4955.5, 26.0306, 100.0, 0), +(@PATH, 21, -779.579, -4952.01, 22.2463, 100.0, 0), +(@PATH, 22, -782.32, -4950.71, 22.2463, 100.0, 0), +(@PATH, 23, -786.267, -4947.33, 22.2463, 100.0, 0), +(@PATH, 24, -786.019, -4944.63, 22.2463, 100.0, 0), +(@PATH, 25, -781.034, -4943.89, 22.2463, 100.0, 0), +(@PATH, 26, -778.747, -4948.8, 22.2463, 100.0, 0), +(@PATH, 27, -777.972, -4951.7, 22.2463, 100.0, 0), +(@PATH, 28, -771.84, -4955.62, 26.2679, 100.0, 0), +(@PATH, 29, -769.283, -4956.47, 27.5535, 100.0, 0), +(@PATH, 30, -766.381, -4956.36, 28.4894, 100.0, 0), +(@PATH, 31, -763.87, -4955.03, 29.4397, 100.0, 0), +(@PATH, 32, -762.094, -4952.75, 30.1289, 100.0, 0), +(@PATH, 33, -761.814, -4947.37, 31.8481, 100.0, 0), +(@PATH, 34, -763.198, -4945.0, 32.8622, 100.0, 0), +(@PATH, 35, -768.301, -4942.61, 34.8163, 100.0, 0); + +/* Den Grunt - GUID 7656 */ + + +SET @NPC := 7656; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -600.043, `position_y` = -4342.45, `position_z` = 37.8159, `orientation` = 1.11138 WHERE `guid` = @NPC; + +UPDATE `creature_addon` set `path_id` = @PATH WHERE `guid` = @NPC; +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -600.043, -4342.45, 37.8159, 100.0, 0), +(@PATH, 2, -599.399, -4324.38, 37.5988, 100.0, 0), +(@PATH, 3, -599.657, -4312.29, 37.5986, 100.0, 0), +(@PATH, 4, -599.869, -4298.37, 37.811, 100.0, 0), +(@PATH, 5, -599.768, -4307.47, 37.5992, 100.0, 0), +(@PATH, 6, -599.445, -4319.6, 37.5986, 100.0, 0), +(@PATH, 7, -599.705, -4334.79, 37.5988, 100.0, 0), +(@PATH, 8, -600.446, -4349.94, 38.131, 100.0, 0), +(@PATH, 9, -600.588, -4362.75, 38.8676, 100.0, 0), +(@PATH, 10, -601.845, -4378.2, 39.9664, 100.0, 0), +(@PATH, 11, -601.612, -4395.27, 42.6652, 100.0, 0), +(@PATH, 12, -600.024, -4410.47, 43.5231, 100.0, 0), +(@PATH, 13, -594.057, -4427.35, 42.4307, 100.0, 0), +(@PATH, 14, -579.457, -4457.44, 41.9763, 100.0, 0), +(@PATH, 15, -573.993, -4468.27, 42.2239, 100.0, 0), +(@PATH, 16, -570.217, -4476.48, 42.5183, 100.0, 0), +(@PATH, 17, -569.013, -4485.33, 42.566, 100.0, 0), +(@PATH, 18, -570.17, -4497.38, 42.5664, 100.0, 0), +(@PATH, 19, -578.906, -4511.47, 42.5098, 100.0, 0), +(@PATH, 20, -581.195, -4514.85, 42.4688, 100.0, 0), +(@PATH, 21, -572.172, -4501.6, 42.5659, 100.0, 0), +(@PATH, 22, -569.257, -4490.21, 42.5659, 100.0, 0), +(@PATH, 23, -569.142, -4481.09, 42.566, 100.0, 0), +(@PATH, 24, -571.964, -4472.59, 42.4032, 100.0, 0), +(@PATH, 25, -578.171, -4460.08, 41.9867, 100.0, 0), +(@PATH, 26, -583.786, -4448.55, 41.618, 100.0, 0), +(@PATH, 27, -589.919, -4434.83, 42.0238, 100.0, 0), +(@PATH, 28, -597.115, -4418.48, 43.1092, 100.0, 0), +(@PATH, 29, -600.253, -4403.03, 43.6641, 100.0, 0), +(@PATH, 30, -601.071, -4387.19, 41.4481, 100.0, 0), +(@PATH, 31, -600.667, -4370.0, 39.3044, 100.0, 0), +(@PATH, 32, -600.132, -4356.39, 38.4777, 100.0, 0); + +/* Clattering Scorpid - GUID 7953 */ + + +SET @NPC := 7953; +SET @PATH := @NPC * 10; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -103.086, -4657.6, 33.6479, 100.0, 0), +(@PATH, 2, -85.3881, -4677.97, 32.5394, 100.0, 0), +(@PATH, 3, -81.7362, -4701.13, 30.2284, 100.0, 0), +(@PATH, 4, -70.1425, -4695.94, 30.9405, 100.0, 0), +(@PATH, 5, -59.5394, -4681.0, 33.771, 100.0, 0), +(@PATH, 6, -54.5816, -4677.98, 35.3588, 100.0, 0), +(@PATH, 7, -49.7002, -4676.23, 38.9528, 100.0, 0), +(@PATH, 8, -46.3046, -4673.13, 41.046, 100.0, 0), +(@PATH, 9, -44.1007, -4670.26, 41.0807, 100.0, 0), +(@PATH, 10, -44.0761, -4665.47, 38.7072, 100.0, 0), +(@PATH, 11, -44.3984, -4659.13, 35.8799, 100.0, 0), +(@PATH, 12, -40.1175, -4644.03, 36.3342, 100.0, 0), +(@PATH, 13, -34.7326, -4631.52, 40.2554, 100.0, 0), +(@PATH, 14, -33.4486, -4622.9, 43.117, 100.0, 0), +(@PATH, 15, -45.7339, -4611.2, 44.6652, 100.0, 0), +(@PATH, 16, -59.8055, -4613.19, 43.9173, 100.0, 0), +(@PATH, 17, -72.1956, -4616.84, 41.993, 100.0, 0), +(@PATH, 18, -82.2069, -4628.65, 38.7271, 100.0, 0), +(@PATH, 19, -89.89, -4632.09, 38.1229, 100.0, 0), +(@PATH, 20, -103.297, -4625.97, 39.8145, 100.0, 0), +(@PATH, 21, -112.51, -4623.24, 41.5492, 100.0, 0), +(@PATH, 22, -116.701, -4640.65, 36.011, 100.0, 0), +(@PATH, 23, -116.177, -4648.41, 34.4998, 100.0, 0); + +/* Dire Mottled Boar - GUID 8539 */ + + +SET @NPC := 8539; +SET @PATH := @NPC * 10; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -214.372, -4845.64, 29.1291, 100.0, 0), +(@PATH, 2, -225.02, -4850.37, 30.6568, 100.0, 0), +(@PATH, 3, -235.224, -4854.72, 31.7916, 100.0, 0), +(@PATH, 4, -247.126, -4856.09, 31.6676, 100.0, 0), +(@PATH, 5, -256.584, -4848.05, 31.4637, 100.0, 0), +(@PATH, 6, -269.014, -4841.03, 32.0333, 100.0, 0), +(@PATH, 7, -289.34, -4837.1, 34.9092, 100.0, 0), +(@PATH, 8, -310.287, -4836.23, 39.2223, 100.0, 0), +(@PATH, 9, -320.813, -4838.24, 39.9581, 100.0, 0), +(@PATH, 10, -330.673, -4844.51, 40.5147, 100.0, 0), +(@PATH, 11, -333.401, -4850.53, 40.7722, 100.0, 0), +(@PATH, 12, -328.735, -4858.96, 40.7124, 100.0, 0), +(@PATH, 13, -321.563, -4868.14, 40.2101, 100.0, 0), +(@PATH, 14, -317.509, -4873.85, 39.4117, 100.0, 0), +(@PATH, 15, -306.572, -4879.36, 36.7733, 100.0, 0), +(@PATH, 16, -292.646, -4884.23, 33.3096, 100.0, 0), +(@PATH, 17, -280.699, -4884.3, 31.3057, 100.0, 0), +(@PATH, 18, -270.147, -4887.51, 29.426, 100.0, 0), +(@PATH, 19, -265.117, -4889.67, 28.3422, 100.0, 0), +(@PATH, 20, -252.422, -4898.02, 27.9178, 100.0, 0), +(@PATH, 21, -246.598, -4899.89, 27.4249, 100.0, 0), +(@PATH, 22, -239.562, -4898.45, 29.0681, 100.0, 0), +(@PATH, 23, -234.568, -4895.74, 29.3167, 100.0, 0), +(@PATH, 24, -226.236, -4890.71, 29.3149, 100.0, 0), +(@PATH, 25, -217.424, -4884.85, 29.7653, 100.0, 0), +(@PATH, 26, -211.227, -4871.29, 29.6777, 100.0, 0), +(@PATH, 27, -210.178, -4858.07, 29.221, 100.0, 0); + +/* Clattering Scorpid - GUID 10474 */ + + +SET @NPC := 10474; +SET @PATH := @NPC * 10; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -406.087, -4716.63, 44.8804, 100.0, 0), +(@PATH, 2, -408.276, -4708.65, 45.1308, 100.0, 0), +(@PATH, 3, -409.576, -4703.31, 40.2804, 100.0, 0), +(@PATH, 4, -412.923, -4691.66, 39.5794, 100.0, 0), +(@PATH, 5, -419.728, -4679.76, 38.7276, 100.0, 0), +(@PATH, 6, -428.741, -4672.17, 37.967, 100.0, 0), +(@PATH, 7, -439.755, -4664.31, 40.0006, 100.0, 0), +(@PATH, 8, -456.36, -4658.33, 40.9741, 100.0, 0), +(@PATH, 9, -460.767, -4666.47, 39.0189, 100.0, 0), +(@PATH, 10, -467.21, -4674.15, 36.7182, 100.0, 0), +(@PATH, 11, -478.211, -4682.6, 38.8073, 100.0, 0), +(@PATH, 12, -489.172, -4689.26, 36.6404, 100.0, 0), +(@PATH, 13, -494.44, -4693.17, 36.7468, 100.0, 0), +(@PATH, 14, -482.252, -4697.46, 36.8586, 100.0, 0), +(@PATH, 15, -470.356, -4697.13, 38.0726, 100.0, 0), +(@PATH, 16, -455.515, -4698.51, 38.4622, 100.0, 0), +(@PATH, 17, -444.913, -4710.9, 37.4488, 100.0, 0), +(@PATH, 18, -433.46, -4722.15, 38.8961, 100.0, 0), +(@PATH, 19, -424.593, -4731.05, 40.0664, 100.0, 0), +(@PATH, 20, -415.99, -4737.86, 40.2052, 100.0, 0), +(@PATH, 21, -409.609, -4729.68, 41.9805, 100.0, 0), +(@PATH, 22, -406.009, -4721.75, 41.9123, 100.0, 0); + + +/* Vile Familiar - GUID 12169 */ + + +SET @NPC := 12169; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -107.068, `position_y` = -4306.76, `position_z` = 62.6159, `orientation` = 6.04921 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -107.068, -4306.76, 62.6159, 100.0, 0), +(@PATH, 2, -124.8, -4318.37, 66.0147, 100.0, 0), +(@PATH, 3, -139.239, -4303.63, 66.1942, 100.0, 0), +(@PATH, 4, -143.22, -4283.83, 64.4553, 100.0, 0), +(@PATH, 5, -129.423, -4280.46, 64.745, 100.0, 0), +(@PATH, 6, -109.47, -4285.22, 63.7303, 100.0, 0), +(@PATH, 7, -94.2235, -4292.27, 60.9362, 100.0, 0); + +/* Clattering Scorpid - GUID 12264 */ + + +SET @NPC := 12264; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -121.162, `position_y` = -4709.15, `position_z` = 27.93, `orientation` = 0.263307 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -121.162, -4709.15, 27.93, 100.0, 0), +(@PATH, 2, -103.324, -4704.22, 28.4752, 100.0, 0), +(@PATH, 3, -91.8912, -4693.48, 30.4882, 100.0, 0), +(@PATH, 4, -98.0826, -4668.58, 32.5437, 100.0, 0), +(@PATH, 5, -108.558, -4659.12, 33.0813, 100.0, 0), +(@PATH, 6, -123.121, -4652.93, 33.8118, 100.0, 0), +(@PATH, 7, -137.574, -4653.24, 35.3335, 100.0, 0), +(@PATH, 8, -152.153, -4651.58, 37.4562, 100.0, 0), +(@PATH, 9, -167.803, -4649.81, 37.7494, 100.0, 0), +(@PATH, 10, -186.079, -4647.93, 38.5911, 100.0, 0), +(@PATH, 11, -188.795, -4657.63, 36.2397, 100.0, 0), +(@PATH, 12, -189.618, -4669.97, 33.4692, 100.0, 0), +(@PATH, 13, -198.707, -4679.42, 33.1351, 100.0, 0), +(@PATH, 14, -209.977, -4691.24, 32.6171, 100.0, 0), +(@PATH, 15, -217.987, -4698.61, 31.033, 100.0, 0), +(@PATH, 16, -221.252, -4706.95, 29.1452, 100.0, 0), +(@PATH, 17, -226.853, -4716.18, 29.2998, 100.0, 0), +(@PATH, 18, -228.244, -4721.6, 29.3076, 100.0, 0), +(@PATH, 19, -222.968, -4725.64, 29.6394, 100.0, 0), +(@PATH, 20, -217.048, -4728.59, 31.5374, 100.0, 0), +(@PATH, 21, -209.686, -4728.02, 32.0704, 100.0, 0), +(@PATH, 22, -196.465, -4727.24, 32.0757, 100.0, 0), +(@PATH, 23, -178.542, -4717.88, 31.7107, 100.0, 0), +(@PATH, 24, -175.455, -4698.0, 32.316, 100.0, 0), +(@PATH, 25, -153.919, -4700.8, 30.4153, 100.0, 0), +(@PATH, 26, -141.606, -4706.08, 28.791, 100.0, 0), +(@PATH, 27, -132.901, -4712.47, 27.927, 100.0, 0); + +/* Razormane Scout - GUID 12307 */ + + +SET @NPC := 12307; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = 69.2959, `position_y` = -4609.61, `position_z` = 48.2853, `orientation` = 0.64357 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, 69.2959, -4609.61, 48.2853, 100.0, 10000), +(@PATH, 2, 72.8356, -4591.06, 55.2529, 100.0, 0), +(@PATH, 3, 76.6362, -4578.17, 56.5297, 100.0, 0), +(@PATH, 4, 84.8748, -4572.65, 56.1986, 100.0, 0), +(@PATH, 5, 93.5395, -4567.38, 55.1739, 100.0, 0), +(@PATH, 6, 95.7022, -4560.2, 54.7452, 100.0, 0), +(@PATH, 7, 90.0297, -4556.16, 54.7916, 100.0, 0), +(@PATH, 8, 84.1164, -4557.37, 54.8289, 100.0, 0), +(@PATH, 9, 79.8056, -4559.84, 54.9896, 100.0, 0), +(@PATH, 10, 74.5471, -4569.52, 55.9016, 100.0, 0), +(@PATH, 11, 75.6316, -4575.49, 56.3877, 100.0, 0), +(@PATH, 12, 81.4626, -4576.27, 56.6136, 100.0, 0), +(@PATH, 13, 84.9299, -4571.12, 55.8428, 100.0, 0), +(@PATH, 14, 84.1083, -4562.97, 54.7466, 100.0, 0), +(@PATH, 15, 82.6289, -4555.58, 55.1128, 100.0, 0), +(@PATH, 16, 83.1458, -4551.12, 55.8152, 100.0, 0), +(@PATH, 17, 88.5177, -4548.67, 56.596, 100.0, 20000), +(@PATH, 18, 85.0209, -4556.79, 54.8304, 100.0, 0), +(@PATH, 19, 81.9841, -4566.79, 55.1042, 100.0, 0), +(@PATH, 20, 78.8213, -4577.88, 56.6008, 100.0, 0), +(@PATH, 21, 75.8794, -4588.68, 56.083, 100.0, 0), +(@PATH, 22, 72.7215, -4599.41, 52.3967, 100.0, 0); + +/* Dire Mottled Boar - GUID 12312 */ + + +SET @NPC := 12312; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -61.8657, `position_y` = -4828.86, `position_z` = 22.6982, `orientation` = 1.96017 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -61.8657, -4828.86, 22.6982, 100.0, 0), +(@PATH, 2, -74.1842, -4823.68, 23.4622, 100.0, 0), +(@PATH, 3, -83.4586, -4827.15, 23.5508, 100.0, 0), +(@PATH, 4, -91.9781, -4833.29, 23.7535, 100.0, 0), +(@PATH, 5, -103.712, -4841.91, 22.8193, 100.0, 0), +(@PATH, 6, -114.994, -4850.2, 21.4633, 100.0, 0), +(@PATH, 7, -126.212, -4858.57, 20.7062, 100.0, 0), +(@PATH, 8, -130.104, -4870.51, 20.677, 100.0, 0), +(@PATH, 9, -127.47, -4878.73, 21.0682, 100.0, 0), +(@PATH, 10, -118.877, -4883.74, 21.1563, 100.0, 0), +(@PATH, 11, -107.751, -4884.02, 20.3514, 100.0, 0), +(@PATH, 12, -99.2225, -4885.73, 18.9527, 100.0, 0), +(@PATH, 13, -83.4712, -4889.91, 17.615, 100.0, 0), +(@PATH, 14, -76.0254, -4891.22, 17.5674, 100.0, 0), +(@PATH, 15, -68.0709, -4887.69, 17.682, 100.0, 0), +(@PATH, 16, -60.9011, -4879.28, 18.6881, 100.0, 0), +(@PATH, 17, -58.3497, -4872.06, 20.4372, 100.0, 0), +(@PATH, 18, -55.5972, -4863.78, 20.8662, 100.0, 0), +(@PATH, 19, -54.8455, -4852.25, 21.3061, 100.0, 0), +(@PATH, 20, -56.5215, -4843.12, 22.1018, 100.0, 0); + + +/* Razormane Scout - GUID 12316 */ + + +SET @NPC := 12316; +SET @PATH := @NPC * 10; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, 124.53, -4582.72, 63.7189, 100.0, 0), +(@PATH, 2, 133.618, -4582.61, 63.8564, 100.0, 0), +(@PATH, 3, 138.082, -4583.02, 62.9627, 100.0, 0), +(@PATH, 4, 141.923, -4585.0, 65.7188, 100.0, 0), +(@PATH, 5, 145.08, -4587.58, 64.9695, 100.0, 20000), +(@PATH, 6, 141.282, -4584.24, 65.4642, 100.0, 0), +(@PATH, 7, 137.239, -4583.36, 62.5436, 100.0, 0), +(@PATH, 8, 134.007, -4582.37, 63.8799, 100.0, 0), +(@PATH, 9, 123.97, -4582.68, 63.7515, 100.0, 0), +(@PATH, 10, 117.123, -4580.07, 62.112, 100.0, 0), +(@PATH, 11, 110.209, -4572.99, 57.9044, 100.0, 0), +(@PATH, 12, 102.608, -4566.32, 55.3204, 100.0, 20000), +(@PATH, 13, 110.348, -4573.89, 58.1059, 100.0, 0), +(@PATH, 14, 116.007, -4578.7, 61.2531, 100.0, 0), +(@PATH, 15, 121.21, -4582.27, 63.9267, 100.0, 0); + +/* Dire Mottled Boar - GUID 12943 */ + + +SET @NPC := 12943; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -200.386, `position_y` = -4883.89, `position_z` = 27.1407, `orientation` = 3.59203 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -200.386, -4883.89, 27.1407, 100.0, 0), +(@PATH, 2, -193.105, -4896.78, 25.5057, 100.0, 0), +(@PATH, 3, -187.962, -4899.92, 23.7865, 100.0, 0), +(@PATH, 4, -182.618, -4903.26, 19.2486, 100.0, 0), +(@PATH, 5, -170.129, -4906.9, 19.2486, 100.0, 0), +(@PATH, 6, -156.713, -4894.43, 19.5028, 100.0, 0), +(@PATH, 7, -146.434, -4884.93, 20.0447, 100.0, 0), +(@PATH, 8, -126.3, -4870.36, 21.0744, 100.0, 0), +(@PATH, 9, -129.568, -4853.1, 20.1477, 100.0, 0), +(@PATH, 10, -117.071, -4842.32, 21.1624, 100.0, 0), +(@PATH, 11, -103.254, -4835.31, 23.3766, 100.0, 0), +(@PATH, 12, -100.011, -4829.95, 23.8422, 100.0, 0), +(@PATH, 13, -105.703, -4815.96, 24.8568, 100.0, 0), +(@PATH, 14, -111.89, -4808.07, 25.1118, 100.0, 0), +(@PATH, 15, -123.375, -4813.62, 24.5666, 100.0, 0), +(@PATH, 16, -146.001, -4825.22, 23.1651, 100.0, 0), +(@PATH, 17, -153.565, -4838.05, 21.2692, 100.0, 0), +(@PATH, 18, -168.864, -4845.25, 20.7892, 100.0, 0), +(@PATH, 19, -182.876, -4852.28, 22.8461, 100.0, 0), +(@PATH, 20, -192.274, -4840.5, 25.7954, 100.0, 0), +(@PATH, 21, -196.924, -4835.91, 26.8833, 100.0, 0), +(@PATH, 22, -201.854, -4832.7, 24.8223, 100.0, 0), +(@PATH, 23, -209.203, -4836.12, 24.9899, 100.0, 0), +(@PATH, 24, -214.462, -4839.38, 27.5361, 100.0, 0), +(@PATH, 25, -223.442, -4846.79, 29.9977, 100.0, 0), +(@PATH, 26, -226.932, -4855.15, 31.4781, 100.0, 0), +(@PATH, 27, -218.524, -4863.81, 30.614, 100.0, 0), +(@PATH, 28, -206.247, -4873.63, 28.7488, 100.0, 0); + +/* Kul Tiras Marine - GUID 12998 */ + + +SET @NPC := 12998; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -230.719, `position_y` = -5125.15, `position_z` = 42.4774, `orientation` = 4.53786 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -230.719, -5125.15, 42.4774, 100.0, 0), +(@PATH, 2, -230.686, -5131.19, 45.7119, 100.0, 0), +(@PATH, 3, -229.064, -5132.69, 45.8029, 100.0, 0), +(@PATH, 4, -222.909, -5132.9, 49.2699, 100.0, 0), +(@PATH, 5, -221.358, -5132.17, 49.2699, 100.0, 0), +(@PATH, 6, -221.043, -5127.19, 49.2699, 100.0, 0), +(@PATH, 7, -224.449, -5124.92, 49.2699, 100.0, 0), +(@PATH, 8, -225.147, -5115.53, 49.3237, 100.0, 0), +(@PATH, 9, -224.832, -5124.48, 49.2703, 100.0, 0), +(@PATH, 10, -220.976, -5127.14, 49.2703, 100.0, 0), +(@PATH, 11, -221.009, -5131.62, 49.2703, 100.0, 0), +(@PATH, 12, -223.324, -5132.8, 49.2703, 100.0, 0), +(@PATH, 13, -229.317, -5132.73, 45.712, 100.0, 0), +(@PATH, 14, -230.802, -5130.94, 45.712, 100.0, 0), +(@PATH, 15, -230.745, -5125.24, 42.477, 100.0, 0), +(@PATH, 16, -229.071, -5123.85, 42.477, 100.0, 0), +(@PATH, 17, -221.9, -5124.38, 38.2719, 100.0, 0), +(@PATH, 18, -220.41, -5126.12, 38.2719, 100.0, 0), +(@PATH, 19, -220.741, -5128.71, 38.2719, 100.0, 0), +(@PATH, 20, -224.215, -5129.94, 38.2719, 100.0, 0), +(@PATH, 21, -231.927, -5129.92, 34.0668, 100.0, 0), +(@PATH, 22, -233.333, -5128.56, 34.0668, 100.0, 0), +(@PATH, 23, -232.741, -5126.2, 34.0668, 100.0, 0), +(@PATH, 24, -229.79, -5125.62, 34.0668, 100.0, 0), +(@PATH, 25, -228.711, -5122.72, 34.0653, 100.0, 0), +(@PATH, 26, -228.582, -5108.82, 34.0653, 100.0, 0), +(@PATH, 27, -228.8, -5098.57, 41.3473, 100.0, 0), +(@PATH, 28, -231.072, -5095.27, 41.3473, 100.0, 0), +(@PATH, 29, -235.625, -5093.99, 41.3473, 100.0, 0), +(@PATH, 30, -252.0, -5094.0, 41.3473, 100.0, 0), +(@PATH, 31, -232.244, -5094.07, 41.3473, 100.0, 0), +(@PATH, 32, -228.875, -5098.53, 41.3473, 100.0, 0), +(@PATH, 33, -228.729, -5108.67, 34.0658, 100.0, 0), +(@PATH, 34, -229.067, -5111.95, 34.0658, 100.0, 0), +(@PATH, 35, -234.399, -5112.87, 34.0658, 100.0, 0), +(@PATH, 36, -252.847, -5113.07, 34.0658, 100.0, 0), +(@PATH, 37, -231.446, -5112.98, 34.0658, 100.0, 0), +(@PATH, 38, -228.84, -5117.89, 34.0658, 100.0, 0), +(@PATH, 39, -228.85, -5124.55, 34.0658, 100.0, 0), +(@PATH, 40, -231.059, -5125.75, 34.0658, 100.0, 0), +(@PATH, 41, -233.287, -5126.61, 34.0658, 100.0, 0), +(@PATH, 42, -233.166, -5129.52, 34.0658, 100.0, 0), +(@PATH, 43, -231.672, -5129.95, 34.0669, 100.0, 0), +(@PATH, 44, -224.454, -5129.98, 38.2726, 100.0, 0), +(@PATH, 45, -221.865, -5129.24, 38.2726, 100.0, 0), +(@PATH, 46, -220.17, -5126.07, 38.2726, 100.0, 0), +(@PATH, 47, -221.888, -5124.38, 38.2719, 100.0, 0), +(@PATH, 48, -229.382, -5123.85, 42.4772, 100.0, 0); + +/* Clattering Scorpid - GUID 13002 */ + + +SET @NPC := 13002; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -327.766, `position_y` = -4760.08, `position_z` = 36.6491, `orientation` = 6.08023 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -327.766, -4760.08, 36.6491, 100.0, 0), +(@PATH, 2, -307.026, -4757.96, 36.3603, 100.0, 0), +(@PATH, 3, -286.811, -4756.11, 34.1922, 100.0, 0), +(@PATH, 4, -272.284, -4754.77, 34.1844, 100.0, 0), +(@PATH, 5, -265.5, -4753.05, 33.6913, 100.0, 0), +(@PATH, 6, -256.536, -4741.59, 32.2737, 100.0, 0), +(@PATH, 7, -256.426, -4725.89, 33.2756, 100.0, 0), +(@PATH, 8, -257.675, -4709.1, 34.2231, 100.0, 0), +(@PATH, 9, -260.288, -4699.09, 37.0144, 100.0, 0), +(@PATH, 10, -264.176, -4694.38, 38.3938, 100.0, 0), +(@PATH, 11, -269.589, -4690.96, 38.8834, 100.0, 0), +(@PATH, 12, -280.665, -4690.68, 39.2254, 100.0, 0), +(@PATH, 13, -291.292, -4693.17, 39.4739, 100.0, 0), +(@PATH, 14, -303.736, -4689.96, 41.9234, 100.0, 0), +(@PATH, 15, -311.884, -4690.42, 41.0454, 100.0, 0), +(@PATH, 16, -321.512, -4692.89, 40.3765, 100.0, 0), +(@PATH, 17, -337.345, -4696.95, 38.814, 100.0, 0), +(@PATH, 18, -347.369, -4707.03, 38.2411, 100.0, 0), +(@PATH, 19, -357.466, -4726.06, 38.4795, 100.0, 0), +(@PATH, 20, -361.583, -4734.52, 39.4971, 100.0, 0), +(@PATH, 21, -366.072, -4742.29, 38.7492, 100.0, 0), +(@PATH, 22, -369.61, -4747.54, 40.3396, 100.0, 0), +(@PATH, 23, -361.003, -4753.41, 37.5095, 100.0, 0), +(@PATH, 24, -345.576, -4759.72, 36.8648, 100.0, 0); + + + +/* Hexed Troll - GUID 13026 */ + + +SET @NPC := 13026; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -1138.31, `position_y` = -5597.88, `position_z` = 7.61002, `orientation` = 3.24477 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -1138.31, -5597.88, 7.61002, 100.0, 0), +(@PATH, 2, -1148.76, -5592.07, 8.36803, 100.0, 0), +(@PATH, 3, -1153.21, -5584.65, 8.89221, 100.0, 0), +(@PATH, 4, -1161.68, -5573.5, 8.47221, 100.0, 0), +(@PATH, 5, -1164.14, -5566.63, 8.27151, 100.0, 0), +(@PATH, 6, -1157.9, -5555.72, 7.68995, 100.0, 0), +(@PATH, 7, -1153.67, -5550.14, 7.69433, 100.0, 0), +(@PATH, 8, -1147.32, -5541.78, 7.18916, 100.0, 0), +(@PATH, 9, -1144.69, -5538.37, 7.33432, 100.0, 0), +(@PATH, 10, -1137.1, -5531.1, 6.45399, 100.0, 0), +(@PATH, 11, -1130.09, -5526.81, 7.79135, 100.0, 0), +(@PATH, 12, -1124.47, -5527.46, 8.42845, 100.0, 0), +(@PATH, 13, -1115.83, -5535.14, 8.6434, 100.0, 0), +(@PATH, 14, -1106.94, -5544.4, 7.6163, 100.0, 0), +(@PATH, 15, -1098.62, -5551.2, 9.11498, 100.0, 0), +(@PATH, 16, -1098.47, -5559.96, 8.45261, 100.0, 0), +(@PATH, 17, -1103.26, -5568.14, 7.54396, 100.0, 0), +(@PATH, 18, -1109.9, -5578.23, 7.82146, 100.0, 0), +(@PATH, 19, -1117.06, -5586.63, 8.32589, 100.0, 0), +(@PATH, 20, -1127.57, -5595.51, 7.71829, 100.0, 0); + + +/* Vile Familiar - GUID 13062 */ + + +SET @NPC := 13062; +SET @PATH := @NPC * 10; + +UPDATE `creature` SET `position_x` = -154.199, `position_y` = -4357.06, `position_z` = 66.8175, `orientation` = 3.49807 WHERE `guid` = @NPC; + +DELETE FROM `creature_addon` WHERE `guid` = @NPC; +INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES (@NPC, @PATH); +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` = @NPC; + +DELETE FROM `waypoint_data` where `id` = @PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`) VALUES +(@PATH, 1, -154.199, -4357.06, 66.8175, 100.0, 0), +(@PATH, 2, -139.779, -4370.04, 66.2358, 100.0, 0), +(@PATH, 3, -132.177, -4361.44, 67.0957, 100.0, 0), +(@PATH, 4, -129.829, -4346.96, 66.2549, 100.0, 0), +(@PATH, 5, -127.669, -4337.69, 64.1934, 100.0, 0), +(@PATH, 6, -113.978, -4332.43, 65.8378, 100.0, 0), +(@PATH, 7, -95.8724, -4329.41, 64.5048, 100.0, 0), +(@PATH, 8, -78.0683, -4330.18, 66.9585, 100.0, 0), +(@PATH, 9, -69.2985, -4337.84, 67.894, 100.0, 0), +(@PATH, 10, -53.1216, -4331.94, 68.3126, 100.0, 0), +(@PATH, 11, -69.2985, -4337.84, 67.894, 100.0, 0), +(@PATH, 12, -78.0683, -4330.18, 66.9585, 100.0, 0), +(@PATH, 13, -95.8724, -4329.41, 64.5048, 100.0, 0), +(@PATH, 14, -113.978, -4332.43, 65.8378, 100.0, 0), +(@PATH, 15, -127.627, -4337.51, 64.1911, 100.0, 0), +(@PATH, 16, -129.829, -4346.96, 66.2549, 100.0, 0), +(@PATH, 17, -132.177, -4361.44, 67.0957, 100.0, 0), +(@PATH, 18, -139.779, -4370.04, 66.2358, 100.0, 0), +(@PATH, 19, -154.199, -4357.06, 66.8175, 100.0, 0), +(@PATH, 20, -162.918, -4360.37, 67.2569, 100.0, 0); diff --git a/data/sql/updates/db_world/2022_07_26_06.sql b/data/sql/updates/db_world/2022_07_26_06.sql new file mode 100644 index 000000000..7462b205f --- /dev/null +++ b/data/sql/updates/db_world/2022_07_26_06.sql @@ -0,0 +1,23 @@ +-- DB update 2022_07_26_05 -> 2022_07_26_06 +-- +UPDATE `creature_text` SET `BroadcastTextId` = 1456 WHERE `CreatureID` = 10000 AND `GroupID` = 0; +UPDATE `creature_text` SET `BroadcastTextId` = 5680 WHERE `CreatureID` = 10000 AND `GroupID` = 1; +UPDATE `creature_text` SET `BroadcastTextId` = 5681 WHERE `CreatureID` = 10000 AND `GroupID` = 2; +UPDATE `creature_text` SET `BroadcastTextId` = 5682 WHERE `CreatureID` = 10000 AND `GroupID` = 3; + +-- SFK: Arugal intro script +DELETE FROM `smart_scripts` WHERE `entryorguid` = 10000 AND `source_type`= 0; +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(10000,0,0,0,60,0,100,1,0,0,0,0,0,47,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Set Invisible'), +(10000,0,1,0,60,0,100,1,5000,5000,0,0,0,47,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Set Visible'), +(10000,0,2,0,60,0,100,1,5000,5000,0,0,0,11,7741,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Cast spell teleport'), +(10000,0,3,0,60,0,100,1,7000,7000,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Say text 0'), +(10000,0,4,0,60,0,100,1,7000,7000,0,0,0,5,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Emote talk'), +(10000,0,5,0,60,0,100,1,10000,10000,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Say text 1'), +(10000,0,6,0,60,0,100,1,10000,10000,0,0,0,5,25,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Emote point'), +(10000,0,7,0,60,0,100,1,14000,14000,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Say text 2'), +(10000,0,8,0,60,0,100,1,14000,14000,0,0,0,5,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Emote talk'), +(10000,0,9,0,60,0,100,1,16000,16000,0,0,0,5,11,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Emote laught'), +(10000,0,10,0,60,0,100,1,19000,19000,0,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Say text 3'), +(10000,0,11,0,60,0,100,1,21000,21000,0,0,0,11,7741,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Cast spell teleport'), +(10000,0,12,0,60,0,100,1,0,0,0,0,0,41,22000,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Arugal - Despawn'); diff --git a/data/sql/updates/db_world/2022_07_27_00.sql b/data/sql/updates/db_world/2022_07_27_00.sql new file mode 100644 index 000000000..dac106a95 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_27_00.sql @@ -0,0 +1,3 @@ +-- DB update 2022_07_26_06 -> 2022_07_27_00 +-- +UPDATE `creature_template` SET `flags_extra` = `flags_extra`|0x80000000 WHERE `entry` = 15339; diff --git a/data/sql/updates/db_world/2022_07_27_01.sql b/data/sql/updates/db_world/2022_07_27_01.sql new file mode 100644 index 000000000..ff9db182a --- /dev/null +++ b/data/sql/updates/db_world/2022_07_27_01.sql @@ -0,0 +1,8 @@ +-- DB update 2022_07_27_00 -> 2022_07_27_01 +-- +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15325; +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15325) AND (`source_type` = 0) AND (`id` IN (0, 1, 2)); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(15325, 0, 0, 1, 9, 0, 100, 0, 0, 40, 11000, 16000, 0, 11, 25185, 4, 3, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Wasp - Within 0-40 Range - Cast \'Itch\''), +(15325, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 11, 25185, 4, 3, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Wasp - Within 0-40 Range - Cast \'Itch\''), +(15325, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 11, 25185, 4, 3, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hive\'Zara Wasp - Within 0-40 Range - Cast \'Itch\''); diff --git a/data/sql/updates/db_world/2022_07_27_02.sql b/data/sql/updates/db_world/2022_07_27_02.sql new file mode 100644 index 000000000..72ebdab17 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_27_02.sql @@ -0,0 +1,9 @@ +-- DB update 2022_07_27_01 -> 2022_07_27_02 +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15338; +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 15338); +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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(15338, 0, 0, 0, 0, 0, 100, 0, 5000, 9000, 8000, 11000, 0, 11, 25756, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - In Combat - Cast \'Purge\''), +(15338, 0, 1, 0, 0, 0, 100, 0, 2000, 4000, 6000, 6000, 0, 11, 25755, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - In Combat - Cast \'Drain Mana\''), +(15338, 0, 2, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 27627, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - On Just Died - Cast \'Serverside - Drop Obsidian\''), +(15338, 0, 3, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - On Respawn - Set Mana To 0'), +(15338, 0, 4, 0, 7, 0, 100, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Obsidian Destroyer - On Evade - Set Mana To 0'); diff --git a/data/sql/updates/db_world/2022_07_27_03.sql b/data/sql/updates/db_world/2022_07_27_03.sql new file mode 100644 index 000000000..c0f3e3ae3 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_27_03.sql @@ -0,0 +1,5 @@ +-- DB update 2022_07_27_02 -> 2022_07_27_03 +-- +DELETE FROM `spell_bonus_data` WHERE `entry`=22009; +INSERT INTO `spell_bonus_data` VALUES +(22009,0,0.2,0,0,'Priest - Greater Heal - 8P T2'); diff --git a/data/sql/updates/db_world/2022_07_27_04.sql b/data/sql/updates/db_world/2022_07_27_04.sql new file mode 100644 index 000000000..9a6a16b56 --- /dev/null +++ b/data/sql/updates/db_world/2022_07_27_04.sql @@ -0,0 +1,78 @@ +-- DB update 2022_07_27_03 -> 2022_07_27_04 +DELETE FROM `creature_formations` WHERE `leaderguid` IN (49609, 49059, 51584, 49309, 51350, 51974, 51570, 49793, 49274, 51979, 49290); +DELETE FROM `creature_formations` WHERE `leaderguid` = 49065 AND `memberGUID` = 49051; +DELETE FROM `creature_formations` WHERE `leaderguid` = 49062 AND `memberGUID` = 49052; +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(51584, 51584, 0, 0, 3, 0, 0), +(51584, 49801, 0, 0, 3, 0, 0), +(51584, 49802, 0, 0, 3, 0, 0), +(51584, 49803, 0, 0, 3, 0, 0), +(51584, 49804, 0, 0, 3, 0, 0), +(51584, 51583, 0, 0, 3, 0, 0), +(51584, 49805, 0, 0, 3, 0, 0), +(51584, 51582, 0, 0, 3, 0, 0), +(49309, 49309, 0, 0, 3, 0, 0), +(49309, 49296, 0, 0, 3, 0, 0), +(49309, 49297, 0, 0, 3, 0, 0), +(49309, 49308, 0, 0, 3, 0, 0), +(49309, 49300, 0, 0, 3, 0, 0), +(49309, 49307, 0, 0, 3, 0, 0), +(49309, 49299, 0, 0, 3, 0, 0), +(49309, 49298, 0, 0, 3, 0, 0), +(51350, 51350, 0, 0, 3, 0, 0), +(51350, 51351, 0, 0, 3, 0, 0), +(51350, 49813, 0, 0, 3, 0, 0), +(51350, 51352, 0, 0, 3, 0, 0), +(51350, 49812, 0, 0, 3, 0, 0), +(51350, 49811, 0, 0, 3, 0, 0), +(51350, 51349, 0, 0, 3, 0, 0), +(51974, 51974, 0, 0, 3, 0, 0), +(51974, 51460, 0, 0, 3, 0, 0), +(51974, 51983, 0, 0, 3, 0, 0), +(51974, 51461, 0, 0, 3, 0, 0), +(51570, 51570, 0, 0, 3, 0, 0), +(51570, 51967, 0, 0, 3, 0, 0), +(51570, 51571, 0, 0, 3, 0, 0), +(51570, 51572, 0, 0, 3, 0, 0), +(51570, 51968, 0, 0, 3, 0, 0), +(51570, 51969, 0, 0, 3, 0, 0), +(49793, 49793, 0, 0, 3, 0, 0), +(49793, 49796, 0, 0, 3, 0, 0), +(49793, 49795, 0, 0, 3, 0, 0), +(49793, 49794, 0, 0, 3, 0, 0), +(49274, 49274, 0, 0, 3, 0, 0), +(49274, 49276, 0, 0, 3, 0, 0), +(49274, 51565, 0, 0, 3, 0, 0), +(49274, 51564, 0, 0, 3, 0, 0), +(49274, 49275, 0, 0, 3, 0, 0), +(49274, 51462, 0, 0, 3, 0, 0), +(51979, 51979, 0, 0, 3, 0, 0), +(51979, 51455, 0, 0, 3, 0, 0), +(51979, 51453, 0, 0, 3, 0, 0), +(51979, 51454, 0, 0, 3, 0, 0), +(51979, 51980, 0, 0, 3, 0, 0), +(51979, 51978, 0, 0, 3, 0, 0), +(49290, 49290, 0, 0, 3, 0, 0), +(49290, 51580, 0, 0, 3, 0, 0), +(49290, 49304, 0, 0, 3, 0, 0), +(49290, 51581, 0, 0, 3, 0, 0), +(49290, 49810, 0, 0, 3, 0, 0), +(49290, 49800, 0, 0, 3, 0, 0), +(49290, 49291, 0, 0, 3, 0, 0), +(49290, 49306, 0, 0, 3, 0, 0), +(49290, 49289, 0, 0, 3, 0, 0), +(49059, 49059, 0, 0, 3, 0, 0), +(49059, 49060, 0, 0, 3, 0, 0), +(49059, 49061, 0, 0, 3, 0, 0), +(49065, 49051, 0, 0, 3, 0, 0), +(49062, 49052, 0, 0, 3, 0, 0), +(49609, 49609, 0, 0, 3, 0, 0), +(49609, 49574, 0, 0, 3, 0, 0), +(49609, 49421, 0, 0, 3, 0, 0), +(49609, 49576, 0, 0, 3, 0, 0), +(49609, 49402, 0, 0, 3, 0, 0), +(49609, 49650, 0, 0, 3, 0, 0), +(49609, 49575, 0, 0, 3, 0, 0), +(49609, 49573, 0, 0, 3, 0, 0), +(49609, 49403, 0, 0, 3, 0, 0), +(49609, 49577, 0, 0, 3, 0, 0); diff --git a/src/common/Dynamic/FactoryHolder.h b/src/common/Dynamic/FactoryHolder.h index c1f1055b0..093f6e4f3 100644 --- a/src/common/Dynamic/FactoryHolder.h +++ b/src/common/Dynamic/FactoryHolder.h @@ -19,33 +19,29 @@ #define ACORE_FACTORY_HOLDER #include "Define.h" -#include "Dynamic/TypeList.h" #include "ObjectRegistry.h" +#include "TypeList.h" -/* - * FactoryHolder holds a factory object of a specific type +/** FactoryHolder holds a factory object of a specific type */ -template +template class FactoryHolder { public: - typedef ObjectRegistry, Key > FactoryHolderRegistry; + typedef ObjectRegistry, Key> FactoryHolderRegistry; - FactoryHolder(Key k) : i_key(k) { } + explicit FactoryHolder(Key const& k) : _key(k) { } virtual ~FactoryHolder() { } - inline Key key() const { return i_key; } - void RegisterSelf(void) { FactoryHolderRegistry::instance()->InsertItem(this, i_key); } - void DeregisterSelf(void) { FactoryHolderRegistry::instance()->RemoveItem(this, false); } + void RegisterSelf() { FactoryHolderRegistry::instance()->InsertItem(this, _key); } /// Abstract Factory create method - virtual T* Create(void* data = nullptr) const = 0; + virtual T* Create(O* object = nullptr) const = 0; private: - Key i_key; + Key const _key; }; -/* - * Permissible is a classic way of letting the object decide +/** Permissible is a classic way of letting the object decide * whether how good they handle things. This is not retricted * to factory selectors. */ @@ -54,7 +50,6 @@ class Permissible { public: virtual ~Permissible() { } - virtual int Permit(const T*) const = 0; + virtual int32 Permit(T const*) const = 0; }; - #endif diff --git a/src/common/Dynamic/ObjectRegistry.h b/src/common/Dynamic/ObjectRegistry.h index 7cc2c9abc..ba9bccd39 100644 --- a/src/common/Dynamic/ObjectRegistry.h +++ b/src/common/Dynamic/ObjectRegistry.h @@ -23,20 +23,23 @@ #include #include #include +#include /** ObjectRegistry holds all registry item of the same type */ template -class ObjectRegistry +class ObjectRegistry final { public: - typedef std::map RegistryMapType; + typedef std::map> RegistryMapType; /// Returns a registry item - const T* GetRegistryItem(Key key) const + T const* GetRegistryItem(Key const& key) const { - typename RegistryMapType::const_iterator iter = i_registeredObjects.find(key); - return ( iter == i_registeredObjects.end() ? nullptr : iter->second ); + auto itr = _registeredObjects.find(key); + if (itr == _registeredObjects.end()) + return nullptr; + return itr->second.get(); } static ObjectRegistry* instance() @@ -46,72 +49,40 @@ public: } /// Inserts a registry item - bool InsertItem(T* obj, Key key, bool override = false) + bool InsertItem(T* obj, Key const& key, bool force = false) { - typename RegistryMapType::iterator iter = i_registeredObjects.find(key); - if ( iter != i_registeredObjects.end() ) + auto itr = _registeredObjects.find(key); + if (itr != _registeredObjects.end()) { - if ( !override ) + if (!force) { return false; } - delete iter->second; - i_registeredObjects.erase(iter); + _registeredObjects.erase(itr); } - i_registeredObjects[key] = obj; + _registeredObjects.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(obj)); return true; } - /// Removes a registry item - void RemoveItem(Key key, bool delete_object = true) - { - typename RegistryMapType::iterator iter = i_registeredObjects.find(key); - if ( iter != i_registeredObjects.end() ) - { - if ( delete_object ) - { - delete iter->second; - } - i_registeredObjects.erase(iter); - } - } - /// Returns true if registry contains an item - bool HasItem(Key key) const + bool HasItem(Key const& key) const { - return (i_registeredObjects.find(key) != i_registeredObjects.end()); - } - - /// Inefficiently return a vector of registered items - unsigned int GetRegisteredItems(std::vector& l) const - { - unsigned int sz = l.size(); - l.resize(sz + i_registeredObjects.size()); - for (typename RegistryMapType::const_iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter) - { - l[sz++] = iter->first; - } - return i_registeredObjects.size(); + return (_registeredObjects.count(key) > 0); } /// Return the map of registered items RegistryMapType const& GetRegisteredItems() const { - return i_registeredObjects; + return _registeredObjects; } - ObjectRegistry() { } - ~ObjectRegistry() - { - for (typename RegistryMapType::iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter) - { - delete iter->second; - } - i_registeredObjects.clear(); - } private: - RegistryMapType i_registeredObjects; + RegistryMapType _registeredObjects; + + // non instanceable, only static + ObjectRegistry() { } + ~ObjectRegistry() { } }; #endif diff --git a/src/common/Utilities/Timer.h b/src/common/Utilities/Timer.h index 505b23827..e8d392439 100644 --- a/src/common/Utilities/Timer.h +++ b/src/common/Utilities/Timer.h @@ -231,7 +231,7 @@ private: struct TimeTrackerSmall { public: - TimeTrackerSmall(uint32 expiry = 0) + TimeTrackerSmall(int32 expiry = 0) : i_expiryTime(expiry) { } @@ -246,7 +246,7 @@ public: return i_expiryTime <= 0; } - void Reset(uint32 interval) + void Reset(int32 interval) { i_expiryTime = interval; } diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index 336733978..c038d5b98 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -26,11 +26,11 @@ // AggressorAI ///////////////// -int AggressorAI::Permissible(Creature const* creature) +int32 AggressorAI::Permissible(Creature const* creature) { // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight if (!creature->IsCivilian() && !creature->IsNeutralToAll()) - return PERMIT_BASE_PROACTIVE; + return PERMIT_BASE_REACTIVE; return PERMIT_BASE_NO; } @@ -320,3 +320,11 @@ void VehicleAI::CheckConditions(uint32 diff) else m_ConditionsTimer -= diff; } + +int32 VehicleAI::Permissible(Creature const* creature) +{ + if (creature->IsVehicle()) + return PERMIT_BASE_SPECIAL; + + return PERMIT_BASE_NO; +} diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h index 39c016bc9..6f5825385 100644 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -31,7 +31,7 @@ public: explicit AggressorAI(Creature* c) : CreatureAI(c) {} void UpdateAI(uint32) override; - static int Permissible(Creature const*); + static int32 Permissible(Creature const* creature); }; typedef std::vector SpellVct; @@ -47,7 +47,7 @@ public: void JustDied(Unit* killer) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } protected: EventMap events; @@ -73,7 +73,7 @@ public: void AttackStart(Unit* who) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } protected: float m_minRange; @@ -87,7 +87,7 @@ public: void AttackStart(Unit* who) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } protected: float m_minRange; @@ -105,7 +105,7 @@ public: void AttackStart(Unit*) override {} void OnCharmed(bool apply) override; - static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } + static int32 Permissible(Creature const* creature); private: void LoadConditions(); diff --git a/src/server/game/AI/CoreAI/GameObjectAI.cpp b/src/server/game/AI/CoreAI/GameObjectAI.cpp index 4594ce83a..ca5267331 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.cpp +++ b/src/server/game/AI/CoreAI/GameObjectAI.cpp @@ -17,12 +17,15 @@ #include "GameObjectAI.h" -//GameObjectAI::GameObjectAI(GameObject* g) : go(g) {} -int GameObjectAI::Permissible(GameObject const* go) +int32 GameObjectAI::Permissible(GameObject const* /*go*/) { - if (go->GetAIName() == "GameObjectAI") - return PERMIT_BASE_SPECIAL; return PERMIT_BASE_NO; } -NullGameObjectAI::NullGameObjectAI(GameObject* g) : GameObjectAI(g) {} +NullGameObjectAI::NullGameObjectAI(GameObject* go) : GameObjectAI(go) { } + +int32 NullGameObjectAI::Permissible(GameObject const* /*go*/) +{ + return PERMIT_BASE_IDLE; +} + diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index 1bf62bceb..3a2731105 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -49,7 +49,7 @@ public: virtual void SetGUID(ObjectGuid /*guid*/, int32 /*id = 0 */) {} virtual ObjectGuid GetGUID(int32 /*id = 0 */) const { return ObjectGuid::Empty; } - static int Permissible(GameObject const* go); + static int32 Permissible(GameObject const* go); virtual bool GossipHello(Player* /*player*/, bool /*reportUse*/) { return false; } virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { return false; } @@ -76,6 +76,6 @@ public: void UpdateAI(uint32 /*diff*/) override {} - static int Permissible(GameObject const* /*go*/) { return PERMIT_BASE_IDLE; } + static int32 Permissible(GameObject const* go); }; #endif diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp index 0253eb007..86c6fc1f0 100644 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -19,10 +19,10 @@ #include "CreatureAIImpl.h" #include "Player.h" -int GuardAI::Permissible(Creature const* creature) +int32 GuardAI::Permissible(Creature const* creature) { if (creature->IsGuard()) - return PERMIT_BASE_SPECIAL; + return PERMIT_BASE_PROACTIVE; return PERMIT_BASE_NO; } diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h index c48b93a9f..d8c7c9310 100644 --- a/src/server/game/AI/CoreAI/GuardAI.h +++ b/src/server/game/AI/CoreAI/GuardAI.h @@ -27,7 +27,7 @@ class GuardAI : public ScriptedAI public: explicit GuardAI(Creature* creature); - static int Permissible(Creature const* creature); + static int32 Permissible(Creature const* creature); void Reset() override; void EnterEvadeMode(EvadeReason /*why*/) override; diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp index 1a576f47e..d1ac8350f 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -23,6 +23,17 @@ PassiveAI::PassiveAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASS PossessedAI::PossessedAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } +int32 NullCreatureAI::Permissible(Creature const* creature) +{ + if (creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) + return PERMIT_BASE_PROACTIVE + 50; + + if (creature->IsTrigger()) + return PERMIT_BASE_REACTIVE; + + return PERMIT_BASE_IDLE; +} + void PassiveAI::UpdateAI(uint32) { if (me->IsInCombat() && me->getAttackers().empty()) @@ -84,8 +95,24 @@ void CritterAI::UpdateAI(uint32 diff) } } +int32 CritterAI::Permissible(Creature const* creature) +{ + if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + return PERMIT_BASE_PROACTIVE; + + return PERMIT_BASE_NO; +} + void TriggerAI::IsSummonedBy(Unit* summoner) { if (me->m_spells[0]) me->CastSpell(me, me->m_spells[0], false, 0, 0, summoner ? summoner->GetGUID() : ObjectGuid::Empty); } + +int32 TriggerAI::Permissible(Creature const* creature) +{ + if (creature->IsTrigger() && creature->m_spells[0]) + return PERMIT_BASE_SPECIAL; + + return PERMIT_BASE_NO; +} diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h index 9f17a5935..79046100e 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -30,7 +30,7 @@ public: void AttackStart(Unit*) override {} void UpdateAI(uint32) override; - static int Permissible(Creature const*) { return PERMIT_BASE_IDLE; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } }; class PossessedAI : public CreatureAI @@ -46,7 +46,7 @@ public: void JustDied(Unit*) override; void KilledUnit(Unit* victim) override; - static int Permissible(Creature const*) { return PERMIT_BASE_IDLE; } + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } }; class NullCreatureAI : public CreatureAI @@ -60,7 +60,7 @@ public: void EnterEvadeMode(EvadeReason /*why*/) override {} void OnCharmed(bool /*apply*/) override {} - static int Permissible(Creature const*) { return PERMIT_BASE_IDLE; } + static int32 Permissible(Creature const* creature); }; class CritterAI : public PassiveAI @@ -72,6 +72,7 @@ public: void EnterEvadeMode(EvadeReason why) override; void UpdateAI(uint32) override; + static int32 Permissible(Creature const* creature); // Xinef: Added private: uint32 _combatTimer; @@ -82,6 +83,8 @@ class TriggerAI : public NullCreatureAI public: explicit TriggerAI(Creature* c) : NullCreatureAI(c) {} void IsSummonedBy(Unit* summoner) override; + + static int32 Permissible(Creature const* creature); }; #endif diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index fe71ffadc..a60083a67 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -28,10 +28,14 @@ #include "SpellMgr.h" #include "Util.h" -int PetAI::Permissible(Creature const* creature) +int32 PetAI::Permissible(Creature const* creature) { - if (creature->IsPet()) - return PERMIT_BASE_SPECIAL; + if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) + { + if (reinterpret_cast(creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) + return PERMIT_BASE_PROACTIVE; + return PERMIT_BASE_REACTIVE; + } return PERMIT_BASE_NO; } diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index bf7685289..7db553adb 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -49,7 +49,7 @@ public: explicit PetAI(Creature* c); void UpdateAI(uint32) override; - static int Permissible(Creature const*); + static int32 Permissible(Creature const* creature); void KilledUnit(Unit* /*victim*/) override; void AttackStart(Unit* target) override; diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp index 37165d7f1..e50356f34 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.cpp +++ b/src/server/game/AI/CoreAI/ReactorAI.cpp @@ -19,7 +19,7 @@ #include "CreatureAIImpl.h" #include "Errors.h" -int ReactorAI::Permissible(Creature const* creature) +int32 ReactorAI::Permissible(Creature const* creature) { if (creature->IsCivilian() || creature->IsNeutralToAll()) return PERMIT_BASE_REACTIVE; diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h index fb65eb0fc..b6a203189 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.h +++ b/src/server/game/AI/CoreAI/ReactorAI.h @@ -30,6 +30,6 @@ public: void MoveInLineOfSight(Unit*) override {} void UpdateAI(uint32 diff) override; - static int Permissible(Creature const*); + static int32 Permissible(Creature const* creature); }; #endif diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 77560df6b..d12232f27 100644 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -25,7 +25,7 @@ #include "SpellMgr.h" #include "Totem.h" -int TotemAI::Permissible(Creature const* creature) +int32 TotemAI::Permissible(Creature const* creature) { if (creature->IsTotem()) return PERMIT_BASE_PROACTIVE; diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h index 837d5e0fd..36639a006 100644 --- a/src/server/game/AI/CoreAI/TotemAI.h +++ b/src/server/game/AI/CoreAI/TotemAI.h @@ -38,7 +38,7 @@ public: void DoAction(int32 param) override; void UpdateAI(uint32 diff) override; - static int Permissible(Creature const* creature); + static int32 Permissible(Creature const* creature); private: ObjectGuid i_victimGuid; diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 46ce5b842..14048b6f3 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -27,6 +27,7 @@ #include "Vehicle.h" #include "ScriptMgr.h" #include "Language.h" +#include "ZoneScript.h" class PhasedRespawn : public BasicEvent { @@ -306,7 +307,10 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/) me->SetLootRecipient(nullptr); me->ResetPlayerDamageReq(); me->SetLastDamagedTime(0); - me->SetCannotReachTarget(false); + me->SetCannotReachTarget(); + + if (ZoneScript* zoneScript = me->GetZoneScript() ? me->GetZoneScript() : (ZoneScript*)me->GetInstanceScript()) + zoneScript->OnCreatureEvade(me); if (me->IsInEvadeMode()) { diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index b03e25578..6db1fa404 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -88,6 +88,7 @@ public: EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty EVADE_REASON_BOUNDARY, // the creature has moved outside its evade boundary EVADE_REASON_SEQUENCE_BREAK, // this is a boss and the pre-requisite encounters for engaging it are not defeated yet + EVADE_REASON_NO_PATH, // the creature was unable to reach its target for over 5 seconds EVADE_REASON_OTHER }; @@ -210,6 +211,8 @@ public: virtual void CalculateThreat(Unit* /*hatedUnit*/, float& /*threat*/, SpellInfo const* /*threatSpell*/) { } + virtual bool OnTeleportUnreacheablePlayer(Player* /*player*/) { return false; } + protected: virtual void MoveInLineOfSight(Unit* /*who*/); @@ -222,7 +225,7 @@ private: bool m_MoveInLineOfSight_locked; }; -enum Permitions +enum Permitions : int32 { PERMIT_BASE_NO = -1, PERMIT_BASE_IDLE = 1, diff --git a/src/server/game/AI/CreatureAIFactory.h b/src/server/game/AI/CreatureAIFactory.h index 233d4c165..6ae188a7b 100644 --- a/src/server/game/AI/CreatureAIFactory.h +++ b/src/server/game/AI/CreatureAIFactory.h @@ -19,60 +19,32 @@ #define ACORE_CREATUREAIFACTORY_H #include "FactoryHolder.h" -#include "GameObjectAI.h" #include "ObjectRegistry.h" -struct SelectableAI : public FactoryHolder, public Permissible +typedef FactoryHolder CreatureAICreator; + +struct SelectableAI : public CreatureAICreator, public Permissible { - SelectableAI(const char* id) : FactoryHolder(id) {} + SelectableAI(std::string const& name) : CreatureAICreator(name), Permissible() { } }; template struct CreatureAIFactory : public SelectableAI { - CreatureAIFactory(const char* name) : SelectableAI(name) {} + CreatureAIFactory(std::string const& name) : SelectableAI(name) { } - CreatureAI* Create(void*) const; + inline CreatureAI* Create(Creature* c) const override + { + return new REAL_AI(c); + } - int Permit(Creature const* c) const { return REAL_AI::Permissible(c); } + int32 Permit(Creature const* c) const override + { + return REAL_AI::Permissible(c); + } }; -template -inline CreatureAI* -CreatureAIFactory::Create(void* data) const -{ - Creature* creature = reinterpret_cast(data); - return (new REAL_AI(creature)); -} - -typedef FactoryHolder CreatureAICreator; -typedef FactoryHolder::FactoryHolderRegistry CreatureAIRegistry; - -//GO -struct SelectableGameObjectAI : public FactoryHolder, public Permissible -{ - SelectableGameObjectAI(const char* id) : FactoryHolder(id) {} -}; - -template -struct GameObjectAIFactory : public SelectableGameObjectAI -{ - GameObjectAIFactory(const char* name) : SelectableGameObjectAI(name) {} - - GameObjectAI* Create(void*) const; - - int Permit(GameObject const* g) const { return REAL_GO_AI::Permissible(g); } -}; - -template -inline GameObjectAI* -GameObjectAIFactory::Create(void* data) const -{ - GameObject* go = reinterpret_cast(data); - return (new REAL_GO_AI(go)); -} - -typedef FactoryHolder GameObjectAICreator; -typedef FactoryHolder::FactoryHolderRegistry GameObjectAIRegistry; +typedef CreatureAICreator::FactoryHolderRegistry CreatureAIRegistry; +#define sCreatureAIRegistry CreatureAIRegistry::instance() #endif diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp index f3d29e5be..4e1f6fdc5 100644 --- a/src/server/game/AI/CreatureAIRegistry.cpp +++ b/src/server/game/AI/CreatureAIRegistry.cpp @@ -19,7 +19,7 @@ #include "CombatAI.h" #include "CreatureAIFactory.h" #include "GuardAI.h" -#include "MovementGeneratorImpl.h" +#include "MovementGenerator.h" #include "PassiveAI.h" #include "PetAI.h" #include "RandomMovementGenerator.h" @@ -27,6 +27,7 @@ #include "SmartAI.h" #include "TotemAI.h" #include "WaypointMovementGenerator.h" +#include "GameObjectAIFactory.h" namespace AIRegistry { @@ -47,10 +48,12 @@ namespace AIRegistry (new CreatureAIFactory("VehicleAI"))->RegisterSelf(); (new CreatureAIFactory("SmartAI"))->RegisterSelf(); + (new GameObjectAIFactory("NullGameObjectAI"))->RegisterSelf(); (new GameObjectAIFactory("GameObjectAI"))->RegisterSelf(); (new GameObjectAIFactory("SmartGameObjectAI"))->RegisterSelf(); - (new MovementGeneratorFactory >(RANDOM_MOTION_TYPE))->RegisterSelf(); - (new MovementGeneratorFactory >(WAYPOINT_MOTION_TYPE))->RegisterSelf(); + (new IdleMovementFactory())->RegisterSelf(); + (new MovementGeneratorFactory>(RANDOM_MOTION_TYPE))->RegisterSelf(); + (new MovementGeneratorFactory>(WAYPOINT_MOTION_TYPE))->RegisterSelf(); } } diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index a9ed9832c..c4436b840 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -15,132 +15,97 @@ * with this program. If not, see . */ -#include "CreatureAISelector.h" #include "Creature.h" +#include "CreatureAISelector.h" #include "CreatureAIFactory.h" + #include "MovementGenerator.h" -#include "PassiveAI.h" -#include "Pet.h" + +#include "GameObject.h" +#include "GameObjectAIFactory.h" + #include "ScriptMgr.h" -#include "TemporarySummon.h" namespace FactorySelector { - CreatureAI* selectAI(Creature* creature) + template + inline int32 GetPermitFor(T const* obj, Value const& value) { - const CreatureAICreator* ai_factory = nullptr; - CreatureAIRegistry& ai_registry(*CreatureAIRegistry::instance()); - - // xinef: if we have controlable guardian, define petai for players as they can steer him, otherwise db / normal ai - // xinef: dont remember why i changed this qq commented out as may break some quests - if (creature->IsPet()/* || (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)*/) - ai_factory = ai_registry.GetRegistryItem("PetAI"); - - //scriptname in db - if (!ai_factory) - if (CreatureAI* scriptedAI = sScriptMgr->GetCreatureAI(creature)) - return scriptedAI; - - // AIname in db - std::string ainame = creature->GetAIName(); - if (!ai_factory && !ainame.empty()) - ai_factory = ai_registry.GetRegistryItem(ainame); - - // select by NPC flags - if (!ai_factory) - { - if (creature->IsVehicle()) - ai_factory = ai_registry.GetRegistryItem("VehicleAI"); - else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) - ai_factory = ai_registry.GetRegistryItem("PetAI"); - else if (creature->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK)) - ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); - else if (creature->IsGuard()) - ai_factory = ai_registry.GetRegistryItem("GuardAI"); - else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) - ai_factory = ai_registry.GetRegistryItem("PetAI"); - else if (creature->IsTotem()) - ai_factory = ai_registry.GetRegistryItem("TotemAI"); - else if (creature->IsTrigger()) - { - if (creature->m_spells[0]) - ai_factory = ai_registry.GetRegistryItem("TriggerAI"); - else - ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); - } - else if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) - ai_factory = ai_registry.GetRegistryItem("CritterAI"); - } - - // select by permit check - if (!ai_factory) - { - int best_val = -1; - typedef CreatureAIRegistry::RegistryMapType RMT; - RMT const& l = ai_registry.GetRegisteredItems(); - for (RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter) - { - const CreatureAICreator* factory = iter->second; - const SelectableAI* p = dynamic_cast(factory); - ASSERT(p); - int val = p->Permit(creature); - if (val > best_val) - { - best_val = val; - ai_factory = p; - } - } - } - - // select NullCreatureAI if not another cases - ainame = (!ai_factory) ? "NullCreatureAI" : ai_factory->key(); - LOG_DEBUG("scripts.ai", "Creature {} used AI is {}.", creature->GetGUID().ToString(), ainame); - return (!ai_factory ? new NullCreatureAI(creature) : ai_factory->Create(creature)); + Permissible const* const p = ASSERT_NOTNULL(dynamic_cast const*>(value.second.get())); + return p->Permit(obj); } - MovementGenerator* selectMovementGenerator(Creature* creature) + template + struct PermissibleOrderPred { - MovementGeneratorRegistry& mv_registry(*MovementGeneratorRegistry::instance()); - ASSERT(creature->GetCreatureTemplate()); - const MovementGeneratorCreator* mv_factory = mv_registry.GetRegistryItem(creature->GetDefaultMovementType()); + public: + PermissibleOrderPred(T const* obj) : _obj(obj) { } - /* if (mv_factory == nullptr) + template + bool operator()(Value const& left, Value const& right) const { - int best_val = -1; - std::vector l; - mv_registry.GetRegisteredItems(l); - for (std::vector::iterator iter = l.begin(); iter != l.end(); ++iter) - { - const MovementGeneratorCreator *factory = mv_registry.GetRegistryItem((*iter).c_str()); - const SelectableMovement *p = dynamic_cast(factory); - ASSERT(p != nullptr); - int val = p->Permit(creature); - if (val > best_val) - { - best_val = val; - mv_factory = p; - } - } - }*/ + return GetPermitFor(_obj, left) < GetPermitFor(_obj, right); + } - return (!mv_factory ? nullptr : mv_factory->Create(creature)); + private: + T const* const _obj; + }; + + template + inline FactoryHolder const* SelectFactory(T* obj) + { + static_assert(std::is_same::value || std::is_same::value, "Invalid template parameter"); + static_assert(std::is_same::value == std::is_same::value, "Incompatible AI for type"); + static_assert(std::is_same::value == std::is_same::value, "Incompatible AI for type"); + + using AIRegistry = typename FactoryHolder::FactoryHolderRegistry; + + // AIName in db + std::string const& aiName = obj->GetAIName(); + if (!aiName.empty()) + return AIRegistry::instance()->GetRegistryItem(aiName); + + // select by permit check + typename AIRegistry::RegistryMapType const& items = AIRegistry::instance()->GetRegisteredItems(); + auto itr = std::max_element(items.begin(), items.end(), PermissibleOrderPred(obj)); + if (itr != items.end() && GetPermitFor(obj, *itr) >= 0) + return itr->second.get(); + + // should _never_ happen, Null AI types defined as PERMIT_BASE_IDLE, it must've been found + ABORT(); + return nullptr; + } + + CreatureAI* SelectAI(Creature* creature) + { + // special pet case, if a tamed creature uses AIName (example SmartAI) we need to override it + if (creature->IsPet()) + return ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(creature); + + // scriptname in db + if (CreatureAI* scriptedAI = sScriptMgr->GetCreatureAI(creature)) + return scriptedAI; + + return SelectFactory(creature)->Create(creature); + } + + MovementGenerator* SelectMovementGenerator(Unit* unit) + { + MovementGeneratorType type = IDLE_MOTION_TYPE; + if (Creature* creature = unit->ToCreature()) + if (!creature->GetCharmerOrOwnerPlayerOrPlayerItself()) + type = creature->GetDefaultMovementType(); + + MovementGeneratorCreator const* mv_factory = sMovementGeneratorRegistry->GetRegistryItem(type); + return ASSERT_NOTNULL(mv_factory)->Create(unit); } GameObjectAI* SelectGameObjectAI(GameObject* go) { - const GameObjectAICreator* ai_factory = nullptr; - GameObjectAIRegistry& ai_registry(*GameObjectAIRegistry::instance()); - + // scriptname in db if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) return scriptedAI; - ai_factory = ai_registry.GetRegistryItem(go->GetAIName()); - - //future goAI types go here - - std::string ainame = (!ai_factory || go->GetScriptId()) ? "NullGameObjectAI" : ai_factory->key(); - LOG_DEBUG("scripts.ai", "GameObject {} used AI is {}.", go->GetGUID().ToString(), ainame); - - return (!ai_factory ? new NullGameObjectAI(go) : ai_factory->Create(go)); + return SelectFactory(go)->Create(go); } } diff --git a/src/server/game/AI/CreatureAISelector.h b/src/server/game/AI/CreatureAISelector.h index 936587e12..a5df78f81 100644 --- a/src/server/game/AI/CreatureAISelector.h +++ b/src/server/game/AI/CreatureAISelector.h @@ -21,13 +21,14 @@ class CreatureAI; class Creature; class MovementGenerator; +class Unit; class GameObjectAI; class GameObject; namespace FactorySelector { - CreatureAI* selectAI(Creature*); - MovementGenerator* selectMovementGenerator(Creature*); - GameObjectAI* SelectGameObjectAI(GameObject*); + AC_GAME_API CreatureAI* SelectAI(Creature* creature); + AC_GAME_API MovementGenerator* SelectMovementGenerator(Unit* unit); + AC_GAME_API GameObjectAI* SelectGameObjectAI(GameObject* go); } #endif diff --git a/src/server/game/AI/GameObjectAIFactory.h b/src/server/game/AI/GameObjectAIFactory.h new file mode 100644 index 000000000..bfebd358b --- /dev/null +++ b/src/server/game/AI/GameObjectAIFactory.h @@ -0,0 +1,51 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef ACORE_GAMEOBJECTAIFACTORY_H +#define ACORE_GAMEOBJECTAIFACTORY_H + +#include "ObjectRegistry.h" +#include "FactoryHolder.h" + +typedef FactoryHolder GameObjectAICreator; + +struct SelectableGameObjectAI : public GameObjectAICreator, public Permissible +{ + SelectableGameObjectAI(std::string const& name) : GameObjectAICreator(name), Permissible() { } +}; + +template +struct GameObjectAIFactory : public SelectableGameObjectAI +{ + GameObjectAIFactory(std::string const& name) : SelectableGameObjectAI(name) { } + + GameObjectAI* Create(GameObject* go) const override + { + return new REAL_GO_AI(go); + } + + int32 Permit(GameObject const* go) const override + { + return REAL_GO_AI::Permissible(go); + } +}; + +typedef GameObjectAICreator::FactoryHolderRegistry GameObjectAIRegistry; + +#define sGameObjectAIRegistry GameObjectAIRegistry::instance() + +#endif diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 612981260..00d1fbb9f 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -297,12 +297,12 @@ void SmartAI::EndPath(bool fail) mEscortNPCFlags = 0; } - ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS); + ObjectVector const* targets = GetScript()->GetStoredTargetVector(SMART_ESCORT_TARGETS, *me); if (targets && mEscortQuestID) { if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin()))) { - Player* player = (*targets->begin())->ToPlayer(); + Player* player = targets->front()->ToPlayer(); if (Group* group = player->GetGroup()) { for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) @@ -327,11 +327,11 @@ void SmartAI::EndPath(bool fail) } else { - for (ObjectList::iterator iter = targets->begin(); iter != targets->end(); ++iter) + for (WorldObject* target : *targets) { - if (GetScript()->IsPlayer((*iter))) + if (GetScript()->IsPlayer(target)) { - Player* player = (*iter)->ToPlayer(); + Player* player = target->ToPlayer(); if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse()) player->AreaExploredOrEventHappens(mEscortQuestID); else if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE) @@ -535,8 +535,7 @@ void SmartAI::UpdateAI(uint32 diff) bool SmartAI::IsEscortInvokerInRange() { - ObjectList* targets = GetScript()->GetTargetList(SMART_ESCORT_TARGETS); - if (targets) + if (ObjectVector const* targets = GetScript()->GetStoredTargetVector(SMART_ESCORT_TARGETS, *me)) { float checkDist = me->GetInstanceScript() ? SMART_ESCORT_MAX_PLAYER_DIST * 2 : SMART_ESCORT_MAX_PLAYER_DIST; if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin()))) @@ -558,11 +557,11 @@ bool SmartAI::IsEscortInvokerInRange() } else { - for (ObjectList::iterator iter = targets->begin(); iter != targets->end(); ++iter) + for (WorldObject* target : *targets) { - if (GetScript()->IsPlayer((*iter))) + if (GetScript()->IsPlayer(target)) { - if (me->GetDistance((*iter)->ToPlayer()) <= checkDist) + if (me->GetDistance(target->ToPlayer()) <= checkDist) return true; } } @@ -763,13 +762,6 @@ void SmartAI::JustRespawned() mFollowArrivedAlive = true; } -int SmartAI::Permissible(Creature const* creature) -{ - if (creature->GetAIName() == "SmartAI") - return PERMIT_BASE_SPECIAL; - return PERMIT_BASE_NO; -} - void SmartAI::JustReachedHome() { GetScript()->OnReset(); @@ -1133,13 +1125,6 @@ void SmartGameObjectAI::SummonedCreatureDies(Creature* summon, Unit* /*killer*/) GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT_DIES, summon); } -int SmartGameObjectAI::Permissible(GameObject const* g) -{ - if (g->GetAIName() == "SmartGameObjectAI") - return PERMIT_BASE_SPECIAL; - return PERMIT_BASE_NO; -} - void SmartGameObjectAI::UpdateAI(uint32 diff) { GetScript()->OnUpdate(diff); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 7bc589ec5..38b07a19b 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -164,7 +164,7 @@ public: ObjectGuid GetGUID(int32 id = 0) const override; //core related - static int32 Permissible(Creature const*); + static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } // Called at movepoint reached void MovepointReached(uint32 id); @@ -259,7 +259,7 @@ public: void InitializeAI() override; void Reset() override; SmartScript* GetScript() { return &mScript; } - static int32 Permissible(GameObject const* g); + static int32 Permissible(GameObject const* /*go*/) { return PERMIT_BASE_NO; } bool GossipHello(Player* player, bool reportUse) override; bool GossipSelect(Player* player, uint32 sender, uint32 action) override; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index d1da549cf..29cda5530 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -44,7 +44,6 @@ SmartScript::SmartScript() trigger = nullptr; mEventPhase = 0; mPathId = 0; - mTargetStorage = new ObjectListMap(); mTextTimer = 0; mLastTextID = 0; mUseTextTimer = false; @@ -66,11 +65,7 @@ SmartScript::SmartScript() SmartScript::~SmartScript() { - for (ObjectListMap::iterator itr = mTargetStorage->begin(); itr != mTargetStorage->end(); ++itr) - delete itr->second; - delete mTargetStorage; - mCounterList.clear(); } void SmartScript::OnReset() @@ -135,1759 +130,1466 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u bool isControlled = e.action.moveToPos.controlled > 0; + ObjectVector targets; + GetTargets(targets, e, unit); + switch (e.GetActionType()) { case SMART_ACTION_TALK: + { + Creature* talker = e.target.type == 0 ? me : nullptr; + Unit* talkTarget = nullptr; + + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - Creature* talker = e.target.type == 0 ? me : nullptr; - Unit* talkTarget = nullptr; - if (targets) + if (IsCreature((target)) && !target->ToCreature()->IsPet()) // Prevented sending text to pets. { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (e.action.talk.useTalkTarget) { - if (IsCreature((*itr)) && !(*itr)->ToCreature()->IsPet()) // Prevented sending text to pets. - { - if (e.action.talk.useTalkTarget) - { - talker = me; - talkTarget = (*itr)->ToCreature(); - } - else - talker = (*itr)->ToCreature(); - break; - } - else if (IsPlayer((*itr))) - { - talker = me; // xinef: added - talkTarget = (*itr)->ToPlayer(); - break; - } + talker = me; + talkTarget = target->ToCreature(); } - - delete targets; - } - - if (!talkTarget) - talkTarget = GetLastInvoker(); - - if (!talker) + else + talker = target->ToCreature(); break; - - if (!sCreatureTextMgr->TextExist(talker->GetEntry(), uint8(e.action.talk.textGroupID))) + } + else if (IsPlayer((target))) { - LOG_ERROR("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_TALK: EntryOrGuid {} SourceType {} EventType {} TargetType {} using non-existent Text id {} for talker {}, ignored.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetTargetType(), e.action.talk.textGroupID, talker->GetEntry()); + talker = me; // xinef: added + talkTarget = target->ToPlayer(); break; } + } - mTalkerEntry = talker->GetEntry(); - mLastTextID = e.action.talk.textGroupID; - mTextTimer = e.action.talk.duration; - mUseTextTimer = true; - sCreatureTextMgr->SendChat(talker, uint8(e.action.talk.textGroupID), talkTarget); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: {} ({}), textId: {}", talker->GetName(), talker->GetGUID().ToString(), mLastTextID); + if (!talkTarget) + talkTarget = GetLastInvoker(); + + if (!talker) + break; + + if (!sCreatureTextMgr->TextExist(talker->GetEntry(), uint8(e.action.talk.textGroupID))) + { + LOG_ERROR("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_TALK: EntryOrGuid {} SourceType {} EventType {} TargetType {} using non-existent Text id {} for talker {}, ignored.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetTargetType(), e.action.talk.textGroupID, talker->GetEntry()); break; } + + mTalkerEntry = talker->GetEntry(); + mLastTextID = e.action.talk.textGroupID; + mTextTimer = e.action.talk.duration; + mUseTextTimer = true; + sCreatureTextMgr->SendChat(talker, uint8(e.action.talk.textGroupID), talkTarget); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: {} ({}), textId: {}", talker->GetName(), talker->GetGUID().ToString(), mLastTextID); + break; + } case SMART_ACTION_SIMPLE_TALK: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (targets) + if (IsCreature(target)) + sCreatureTextMgr->SendChat(target->ToCreature(), uint8(e.action.simpleTalk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : 0); + else if (IsPlayer(target) && me) { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsCreature(*itr)) - sCreatureTextMgr->SendChat((*itr)->ToCreature(), uint8(e.action.simpleTalk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : 0); - else if (IsPlayer(*itr) && me) - { - Unit* templastInvoker = GetLastInvoker(); - sCreatureTextMgr->SendChat(me, uint8(e.action.simpleTalk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, (*itr)->ToPlayer()); - } - - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: {} ({}), textGroupId: {}", - (*itr)->GetName(), (*itr)->GetGUID().ToString(), uint8(e.action.simpleTalk.textGroupID)); - } - - delete targets; + Unit* templastInvoker = GetLastInvoker(); + sCreatureTextMgr->SendChat(me, uint8(e.action.simpleTalk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, target->ToPlayer()); } - break; + + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: {} ({}), textGroupId: {}", + target->GetName(), target->GetGUID().ToString(), uint8(e.action.simpleTalk.textGroupID)); } + break; + } case SMART_ACTION_PLAY_EMOTE: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (targets) + if (IsUnit(target)) { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - { - (*itr)->ToUnit()->HandleEmoteCommand(e.action.emote.emote); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: {} ({}), emote: {}", - (*itr)->GetName(), (*itr)->GetGUID().ToString(), e.action.emote.emote); - } - } - - delete targets; + target->ToUnit()->HandleEmoteCommand(e.action.emote.emote); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: {} ({}), emote: {}", + target->GetName(), target->GetGUID().ToString(), e.action.emote.emote); } - break; } + break; + } case SMART_ACTION_SOUND: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (targets) + if (IsUnit(target)) { - for (auto& target : *targets) - { - if (IsUnit(target)) - { - if (e.action.sound.distance == 1) - target->PlayDistanceSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr); - else - target->PlayDirectSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SOUND: target: {} ({}), sound: {}, onlyself: {}", - target->GetName(), target->GetGUID().ToString(), e.action.sound.sound, e.action.sound.onlySelf); - } - } - - delete targets; + if (e.action.sound.distance == 1) + target->PlayDistanceSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr); + else + target->PlayDirectSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SOUND: target: {} ({}), sound: {}, onlyself: {}", + target->GetName(), target->GetGUID().ToString(), e.action.sound.sound, e.action.sound.onlySelf); } + } + break; + } + case SMART_ACTION_RANDOM_SOUND: + { + uint32 sounds[4]; + sounds[0] = e.action.randomSound.sound1; + sounds[1] = e.action.randomSound.sound2; + sounds[2] = e.action.randomSound.sound3; + sounds[3] = e.action.randomSound.sound4; + uint32 temp[4]; + uint32 count = 0; + for (unsigned int sound : sounds) + { + if (sound) + { + temp[count] = sound; + ++count; + } + } + + if (count == 0) + { break; } - case SMART_ACTION_RANDOM_SOUND: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - uint32 sounds[4]; - sounds[0] = e.action.randomSound.sound1; - sounds[1] = e.action.randomSound.sound2; - sounds[2] = e.action.randomSound.sound3; - sounds[3] = e.action.randomSound.sound4; - uint32 temp[4]; - uint32 count = 0; - for (uint8 i = 0; i < 4; i++) + for (WorldObject* target : targets) + { + if (IsUnit(target)) { - if (sounds[i]) + uint32 sound = temp[urand(0, count - 1)]; + target->PlayDirectSound(sound, e.action.randomSound.onlySelf ? target->ToPlayer() : nullptr); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: {} ({}), sound: {}, onlyself: {}", + target->GetName(), target->GetGUID().ToString(), sound, e.action.randomSound.onlySelf); + } + } + + break; + } + case SMART_ACTION_MUSIC: + { + ObjectVector targets; + + if (e.action.music.type > 0) + { + if (me && me->FindMap()) + { + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + + if (!players.IsEmpty()) { - temp[count] = sounds[i]; - ++count; + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + if (Player* player = i->GetSource()) + { + if (player->GetZoneId() == me->GetZoneId()) + { + if (e.action.music.type > 1) + { + if (player->GetAreaId() == me->GetAreaId()) + targets.push_back(player); + } + else + targets.push_back(player); + } + } } } + } + else + GetTargets(targets, e); - if (count == 0) - { - delete targets; - break; - } - - for (auto& target : *targets) + if (!targets.empty()) + { + for (WorldObject* target : targets) { if (IsUnit(target)) { - uint32 sound = temp[urand(0, count - 1)]; - if (e.action.randomSound.distance == 1) - target->PlayDistanceSound(sound, e.action.randomSound.onlySelf ? target->ToPlayer() : nullptr); - else - target->PlayDirectSound(sound, e.action.randomSound.onlySelf ? target->ToPlayer() : nullptr); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: {} ({}), sound: {}, onlyself: {}", - target->GetName(), target->GetGUID().ToString(), sound, e.action.randomSound.onlySelf); + target->SendPlayMusic(e.action.music.sound, e.action.music.onlySelf > 0); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_MUSIC: target: {} ({}), sound: {}, onlySelf: {}, type: {}", + target->GetName(), target->GetGUID().ToString(), e.action.music.sound, e.action.music.onlySelf, e.action.music.type); } } - - delete targets; - break; - } - case SMART_ACTION_MUSIC: - { - ObjectList* targets = nullptr; - - if (e.action.music.type > 0) - { - if (me && me->FindMap()) - { - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - targets = new ObjectList(); - - if (!players.IsEmpty()) - { - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - if (Player* player = i->GetSource()) - { - if (player->GetZoneId() == me->GetZoneId()) - { - if (e.action.music.type > 1) - { - if (player->GetAreaId() == me->GetAreaId()) - targets->push_back(player); - } - else - targets->push_back(player); - } - } - } - } - } - else - targets = GetTargets(e, unit); - - if (targets) - { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - { - (*itr)->SendPlayMusic(e.action.music.sound, e.action.music.onlySelf > 0); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_MUSIC: target: {} ({}), sound: {}, onlySelf: {}, type: {}", - (*itr)->GetName(), (*itr)->GetGUID().ToString(), e.action.music.sound, e.action.music.onlySelf, e.action.music.type); - } - } - - delete targets; - } - break; } + break; + } case SMART_ACTION_RANDOM_MUSIC: + { + ObjectVector targets; + + if (e.action.randomMusic.type > 0) { - ObjectList* targets = nullptr; - - if (e.action.randomMusic.type > 0) + if (me && me->FindMap()) { - if (me && me->FindMap()) - { - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - targets = new ObjectList(); + Map::PlayerList const& players = me->GetMap()->GetPlayers(); - if (!players.IsEmpty()) - { - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - if (Player* player = i->GetSource()) + if (!players.IsEmpty()) + { + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) + if (Player* player = i->GetSource()) + { + if (player->GetZoneId() == me->GetZoneId()) { - if (player->GetZoneId() == me->GetZoneId()) + if (e.action.randomMusic.type > 1) { - if (e.action.randomMusic.type > 1) - { - if (player->GetAreaId() == me->GetAreaId()) - targets->push_back(player); - } - else - targets->push_back(player); + if (player->GetAreaId() == me->GetAreaId()) + targets.push_back(player); } + else + targets.push_back(player); } - } + } } } - else - targets = GetTargets(e, unit); + } + else + GetTargets(targets, e); - if (!targets) - break; + if (targets.empty()) + break; - uint32 sounds[4]; - sounds[0] = e.action.randomMusic.sound1; - sounds[1] = e.action.randomMusic.sound2; - sounds[2] = e.action.randomMusic.sound3; - sounds[3] = e.action.randomMusic.sound4; - uint32 temp[4]; - uint32 count = 0; - for (uint8 i = 0; i < 4; i++) + uint32 sounds[4]; + sounds[0] = e.action.randomMusic.sound1; + sounds[1] = e.action.randomMusic.sound2; + sounds[2] = e.action.randomMusic.sound3; + sounds[3] = e.action.randomMusic.sound4; + uint32 temp[4]; + uint32 count = 0; + for (unsigned int sound : sounds) + { + if (sound) { - if (sounds[i]) - { - temp[count] = sounds[i]; - ++count; - } + temp[count] = sound; + ++count; } + } - if (count == 0) - { - delete targets; - break; - } - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - { - uint32 sound = temp[urand(0, count - 1)]; - (*itr)->SendPlayMusic(sound, e.action.randomMusic.onlySelf > 0); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_MUSIC: target: {} ({}), sound: {}, onlyself: {}, type: {}", - (*itr)->GetName(), (*itr)->GetGUID().ToString(), sound, e.action.randomMusic.onlySelf, e.action.randomMusic.type); - } - } - - delete targets; + if (count == 0) + { break; } + + for (WorldObject* target : targets) + { + if (IsUnit(target)) + { + uint32 sound = temp[urand(0, count - 1)]; + target->SendPlayMusic(sound, e.action.randomMusic.onlySelf > 0); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_MUSIC: target: {} ({}), sound: {}, onlyself: {}, type: {}", + target->GetName(), target->GetGUID().ToString(), sound, e.action.randomMusic.onlySelf, e.action.randomMusic.type); + } + } + + break; + } case SMART_ACTION_SET_FACTION: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (targets) + if (IsCreature(target)) { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (e.action.faction.factionID) { - if (IsCreature(*itr)) + target->ToCreature()->SetFaction(e.action.faction.factionID); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry {}, GuidLow {} set faction to {}", + target->GetEntry(), target->GetGUID().ToString(), e.action.faction.factionID); + } + else + { + if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->ToCreature()->GetEntry())) { - if (e.action.faction.factionID) + if (target->ToCreature()->GetFaction() != ci->faction) { - (*itr)->ToCreature()->SetFaction(e.action.faction.factionID); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry {} ({}) set faction to {}", - (*itr)->GetEntry(), (*itr)->GetGUID().ToString(), e.action.faction.factionID); + target->ToCreature()->SetFaction(ci->faction); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry {}, GuidLow {} set faction to {}", + target->GetEntry(), target->GetGUID().ToString(), ci->faction); } - else + } + } + } + } + break; + } + case SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: + { + for (WorldObject* target : targets) + { + if (!IsCreature(target)) + continue; + + if (e.action.morphOrMount.creature || e.action.morphOrMount.model) + { + //set model based on entry from creature_template + if (e.action.morphOrMount.creature) + { + if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) + { + uint32 displayId = ObjectMgr::ChooseDisplayId(ci); + target->ToCreature()->SetDisplayId(displayId); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {}, GuidLow {} set displayid to {}", + target->GetEntry(), target->GetGUID().ToString(), displayId); + } + } + //if no param1, then use value from param2 (modelId) + else + { + target->ToCreature()->SetDisplayId(e.action.morphOrMount.model); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {}, GuidLow {} set displayid to {}", + target->GetEntry(), target->GetGUID().ToString(), e.action.morphOrMount.model); + } + } + else + { + target->ToCreature()->DeMorph(); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {}, GuidLow {} demorphs.", + target->GetEntry(), target->GetGUID().ToString()); + } + } + break; + } + case SMART_ACTION_FAIL_QUEST: + { + for (WorldObject* target : targets) + { + if (IsPlayer(target)) + { + target->ToPlayer()->FailQuest(e.action.quest.quest); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player guidLow {} fails quest {}", + target->GetGUID().ToString(), e.action.quest.quest); + } + } + break; + } + case SMART_ACTION_OFFER_QUEST: + { + for (WorldObject* target : targets) + { + if (Player* player = target->ToPlayer()) + { + if (Quest const* q = sObjectMgr->GetQuestTemplate(e.action.questOffer.questID)) + { + if (me && e.action.questOffer.directAdd == 0) + { + if (player->CanTakeQuest(q, true)) { - if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*itr)->ToCreature()->GetEntry())) + if (WorldSession* session = player->GetSession()) { - if ((*itr)->ToCreature()->GetFaction() != ci->faction) - { - (*itr)->ToCreature()->SetFaction(ci->faction); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry {} ({}) set faction to {}", - (*itr)->GetEntry(), (*itr)->GetGUID().ToString(), ci->faction); - } + PlayerMenu menu(session); + menu.SendQuestGiverQuestDetails(q, me->GetGUID(), true); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player guidLow {} - offering quest {}", + player->GetGUID().ToString(), e.action.questOffer.questID); } } } - } - - delete targets; - } - break; - } - case SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsCreature(*itr)) - continue; - - if (e.action.morphOrMount.creature || e.action.morphOrMount.model) - { - //set model based on entry from creature_template - if (e.action.morphOrMount.creature) - { - if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) - { - uint32 displayId = ObjectMgr::ChooseDisplayId(ci); - (*itr)->ToCreature()->SetDisplayId(displayId); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {} ({}) set displayid to {}", - (*itr)->GetEntry(), (*itr)->GetGUID().ToString(), displayId); - } - } - //if no param1, then use value from param2 (modelId) else { - (*itr)->ToCreature()->SetDisplayId(e.action.morphOrMount.model); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {} ({}) set displayid to {}", - (*itr)->GetEntry(), (*itr)->GetGUID().ToString(), e.action.morphOrMount.model); - } - } - else - { - (*itr)->ToCreature()->DeMorph(); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {} ({}) demorphs.", - (*itr)->GetEntry(), (*itr)->GetGUID().ToString()); - } - } - - delete targets; - break; - } - case SMART_ACTION_FAIL_QUEST: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsPlayer(*itr)) - { - (*itr)->ToPlayer()->FailQuest(e.action.quest.quest); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player {} fails quest {}", - (*itr)->GetGUID().ToString(), e.action.quest.quest); - } - } - - delete targets; - break; - } - case SMART_ACTION_OFFER_QUEST: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (Player* pTarget = (*itr)->ToPlayer()) - { - if (Quest const* q = sObjectMgr->GetQuestTemplate(e.action.questOffer.questID)) - { - if (me && e.action.questOffer.directAdd == 0) - { - if (pTarget->CanTakeQuest(q, true)) - if (WorldSession* session = pTarget->GetSession()) - { - PlayerMenu menu(session); - menu.SendQuestGiverQuestDetails(q, me->GetGUID(), true); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player {}- offering quest {}", - (*itr)->GetGUID().ToString(), e.action.questOffer.questID); - } - } - else - { - (*itr)->ToPlayer()->AddQuestAndCheckCompletion(q, nullptr); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player {} - quest {} added", - (*itr)->GetGUID().ToString(), e.action.questOffer.questID); - } + player->AddQuestAndCheckCompletion(q, nullptr); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player guidLow {} - quest {} added", + player->GetGUID().ToString(), e.action.questOffer.questID); } } } - - delete targets; - break; } + break; + } case SMART_ACTION_SET_REACT_STATE: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + if (!IsCreature(target)) + continue; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsCreature(*itr)) - continue; - - (*itr)->ToCreature()->SetReactState(ReactStates(e.action.react.state)); - } - - delete targets; - break; + target->ToCreature()->SetReactState(ReactStates(e.action.react.state)); } + break; + } case SMART_ACTION_RANDOM_EMOTE: + { + std::vector emotes; + std::copy_if(e.action.randomEmote.emotes.begin(), e.action.randomEmote.emotes.end(), + std::back_inserter(emotes), [](uint32 emote) { return emote != 0; }); + + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - uint32 emotes[SMART_ACTION_PARAM_COUNT]; - emotes[0] = e.action.randomEmote.emote1; - emotes[1] = e.action.randomEmote.emote2; - emotes[2] = e.action.randomEmote.emote3; - emotes[3] = e.action.randomEmote.emote4; - emotes[4] = e.action.randomEmote.emote5; - emotes[5] = e.action.randomEmote.emote6; - uint32 temp[SMART_ACTION_PARAM_COUNT]; - uint32 count = 0; - for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT; i++) + if (IsUnit(target)) { - if (emotes[i]) - { - temp[count] = emotes[i]; - ++count; - } + uint32 emote = Acore::Containers::SelectRandomContainerElement(emotes); + target->ToUnit()->HandleEmoteCommand(emote); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature guidLow {} handle random emote {}", + target->GetGUID().ToString(), emote); } - - if (count == 0) - { - delete targets; - break; - } - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - { - uint32 emote = temp[urand(0, count - 1)]; - (*itr)->ToUnit()->HandleEmoteCommand(emote); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature {} handle random emote {}", - (*itr)->GetGUID().ToString(), emote); - } - } - - delete targets; - break; } + break; + } case SMART_ACTION_THREAT_ALL_PCT: - { - if (!me) - break; - - ThreatContainer::StorageType threatList = me->GetThreatMgr().getThreatList(); - for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid())) - { - me->GetThreatMgr().modifyThreatPercent(target, e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature {} modify threat for unit {}, value {}", - me->GetGUID().ToString(), target->GetGUID().ToString(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); - } - } + { + if (!me) break; + + ThreatContainer::StorageType threatList = me->GetThreatMgr().getThreatList(); + for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid())) + { + me->GetThreatMgr().modifyThreatPercent(target, e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature {} modify threat for unit {}, value {}", + me->GetGUID().ToString(), target->GetGUID().ToString(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + } } + break; + } case SMART_ACTION_THREAT_SINGLE_PCT: - { - if (!me) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - { - me->GetThreatMgr().modifyThreatPercent((*itr)->ToUnit(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature {} modify threat for unit {}, value {}", - me->GetGUID().ToString(), (*itr)->GetGUID().ToString(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); - } - } - - delete targets; + { + if (!me) break; + + for (WorldObject* target : targets) + { + if (IsUnit(target)) + { + me->GetThreatMgr().modifyThreatPercent(target->ToUnit(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature guidLow {} modify threat for unit {}, value %i", + me->GetGUID().ToString(), target->GetGUID().ToString(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + } } + break; + } case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + // Special handling for vehicles + if (IsUnit(target)) + if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit()) + for (auto & Seat : vehicle->Seats) + if (Player* player = ObjectAccessor::GetPlayer(*target, Seat.second.Passenger.Guid)) + player->AreaExploredOrEventHappens(e.action.quest.quest); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsPlayer(target)) { - // Special handling for vehicles - if (IsUnit(*itr)) - { - if (Vehicle* vehicle = (*itr)->ToUnit()->GetVehicleKit()) - for (SeatMap::iterator it = vehicle->Seats.begin(); it != vehicle->Seats.end(); ++it) - if (Player* player = ObjectAccessor::GetPlayer(*(*itr), it->second.Passenger.Guid)) - player->AreaExploredOrEventHappens(e.action.quest.quest); + target->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest); - if (Player* player = (*itr)->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself()) - { - player->GroupEventHappens(e.action.quest.quest, GetBaseObject()); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player {} credited quest {}", - (*itr)->GetGUID().ToString(), e.action.quest.quest); - } - } + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player guidLow {} credited quest {}", + target->GetGUID().ToString(), e.action.quest.quest); } - - delete targets; - break; } + break; + } case SMART_ACTION_CAST: + { + if (targets.empty()) + break; + + Unit* caster = me; + // Areatrigger Cast! + if (e.GetScriptType() == SMART_SCRIPT_TYPE_AREATRIGGER) + caster = unit->SummonTrigger(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetOrientation(), 5000); + + if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit) + Acore::Containers::RandomResize(targets, e.action.cast.targetsLimit); + + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - Unit* caster = me; - // Areatrigger Cast! - if (e.GetScriptType() == SMART_SCRIPT_TYPE_AREATRIGGER) - caster = unit->SummonTrigger(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetOrientation(), 5000); - - if (e.action.cast.targetsLimit > 0 && targets->size() > e.action.cast.targetsLimit) - Acore::Containers::RandomResize(*targets, e.action.cast.targetsLimit); - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + // may be nullptr + if (go) { - if (go) - { - // Xinef: may be nullptr! - go->CastSpell((*itr)->ToUnit(), e.action.cast.spell); - } - - if (!IsUnit(*itr)) - continue; - - if (caster && caster != me) // Areatrigger cast - { - caster->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); - } - else if (me && (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell))) - { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - me->InterruptNonMeleeSpells(false); - - // Xinef: flag usable only if caster has max dist set - if ((e.action.cast.flags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0) - { - // Xinef: check mana case only and operate movement accordingly, LoS and range is checked in targetet movement generator - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell); - int32 currentPower = me->GetPower(GetCasterPowerType()); - - if ((spellInfo && (currentPower < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()) || me->IsSpellProhibited(spellInfo->GetSchoolMask()))) || me->HasUnitFlag(UNIT_FLAG_SILENCED)) - { - SetCasterActualDist(0); - CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(0); - } - else if (GetCasterActualDist() == 0.0f && me->GetPowerPct(GetCasterPowerType()) > 30.0f) - { - RestoreCasterMaxDist(); - CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(GetCasterActualDist()); - } - } - - me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); - } + go->CastSpell(target->ToUnit(), e.action.cast.spell); } - delete targets; - break; + if (!IsUnit(target)) + continue; + + if (caster && caster != me) // Areatrigger cast + { + caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + } + else if (me && (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))) + { + if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + me->InterruptNonMeleeSpells(false); + + // Xinef: flag usable only if caster has max dist set + if ((e.action.cast.flags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0) + { + // Xinef: check mana case only and operate movement accordingly, LoS and range is checked in targetet movement generator + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell); + int32 currentPower = me->GetPower(GetCasterPowerType()); + + if ((spellInfo && (currentPower < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()) || me->IsSpellProhibited(spellInfo->GetSchoolMask()))) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) + { + SetCasterActualDist(0); + CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(0); + } + else if (GetCasterActualDist() == 0.0f && me->GetPowerPct(GetCasterPowerType()) > 30.0f) + { + RestoreCasterMaxDist(); + CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(GetCasterActualDist()); + } + } + + me->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + } } + + break; + } case SMART_ACTION_INVOKER_CAST: - { - Unit* tempLastInvoker = GetLastInvoker(unit); // xinef: can be used for area triggers cast - if (!tempLastInvoker) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - if (e.action.cast.targetsLimit > 0 && targets->size() > e.action.cast.targetsLimit) - Acore::Containers::RandomResize(*targets, e.action.cast.targetsLimit); - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsUnit(*itr)) - continue; - - if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell)) - { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - tempLastInvoker->InterruptNonMeleeSpells(false); - - tempLastInvoker->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); - } - } - - delete targets; + { + Unit* tempLastInvoker = GetLastInvoker(unit); // xinef: can be used for area triggers cast + if (!tempLastInvoker) break; + + if (targets.empty()) + break; + + if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit) + Acore::Containers::RandomResize(targets, e.action.cast.targetsLimit); + + for (WorldObject* target : targets) + { + if (!IsUnit(target)) + continue; + + if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)) + { + if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + tempLastInvoker->InterruptNonMeleeSpells(false); + + tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + } } + + break; + } case SMART_ACTION_ADD_AURA: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsUnit(target)) { - if (IsUnit(*itr)) - { - (*itr)->ToUnit()->AddAura(e.action.addAura.spell, (*itr)->ToUnit()); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ADD_AURA: Adding aura {} to unit {}", - e.action.addAura.spell, (*itr)->GetGUID().ToString()); - } + target->ToUnit()->AddAura(e.action.cast.spell, target->ToUnit()); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ADD_AURA: Adding aura {} to unit {}", + e.action.cast.spell, target->GetGUID().ToString()); } - - delete targets; - break; } + break; + } case SMART_ACTION_ACTIVATE_GOBJECT: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsGameObject(target)) { - if (IsGameObject(*itr)) + GameObject* go = target->ToGameObject(); + + // Activate + if (go->GetGoType() != GAMEOBJECT_TYPE_DOOR) { - GameObject* go = (*itr)->ToGameObject(); - - // Activate - if (go->GetGoType() != GAMEOBJECT_TYPE_DOOR) - { - go->SetLootState(GO_READY); - } - - go->UseDoorOrButton(0, !!e.action.activateObject.alternative, unit); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject {} activated", go->GetGUID().ToString()); + go->SetLootState(GO_READY); } - } - delete targets; - break; + go->UseDoorOrButton(0, !!e.action.activateObject.alternative, unit); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject {} activated", go->GetGUID().ToString()); + } } + + break; + } case SMART_ACTION_RESET_GOBJECT: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsGameObject(target)) { - if (IsGameObject(*itr)) - { - (*itr)->ToGameObject()->ResetDoorOrButton(); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. Gameobject {} reset", - (*itr)->GetGUID().ToString()); - } + target->ToGameObject()->ResetDoorOrButton(); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. Gameobject {} (entry: {}) reset", + target->GetGUID().ToString(), target->GetEntry()); } - - delete targets; - break; } + break; + } case SMART_ACTION_SET_EMOTE_STATE: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsUnit(target)) { - if (IsUnit(*itr)) - { - (*itr)->ToUnit()->SetUInt32Value(UNIT_NPC_EMOTESTATE, e.action.emote.emote); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. Unit {} set emotestate to {}", - (*itr)->GetGUID().ToString(), e.action.emote.emote); - } + target->ToUnit()->SetUInt32Value(UNIT_NPC_EMOTESTATE, e.action.emote.emote); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. Unit {} set emotestate to {}", + target->GetGUID().ToString(), e.action.emote.emote); } - - delete targets; - break; } + break; + } case SMART_ACTION_SET_UNIT_FLAG: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsUnit(target)) { - if (IsUnit(*itr)) + if (!e.action.unitFlag.type) { - if (!e.action.unitFlag.type) - { - (*itr)->ToUnit()->SetUnitFlag(UnitFlags(e.action.unitFlag.flag)); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit {} added flag {} to UNIT_FIELD_FLAGS", - (*itr)->GetGUID().ToString(), e.action.unitFlag.flag); - } - else - { - (*itr)->ToUnit()->SetUnitFlag2(UnitFlags2(e.action.unitFlag.flag)); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit {} added flag {} to UNIT_FIELD_FLAGS_2", - (*itr)->GetGUID().ToString(), e.action.unitFlag.flag); - } + target->ToUnit()->SetFlag(UNIT_FIELD_FLAGS, e.action.unitFlag.flag); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit {} added flag {} to UNIT_FIELD_FLAGS", + target->GetGUID().ToString(), e.action.unitFlag.flag); + } + else + { + target->ToUnit()->SetFlag(UNIT_FIELD_FLAGS_2, e.action.unitFlag.flag); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit {} added flag {} to UNIT_FIELD_FLAGS_2", + target->GetGUID().ToString(), e.action.unitFlag.flag); } } - - delete targets; - break; } + break; + } case SMART_ACTION_REMOVE_UNIT_FLAG: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsUnit(target)) { - if (IsUnit(*itr)) + if (!e.action.unitFlag.type) { - if (!e.action.unitFlag.type) - { - (*itr)->ToUnit()->RemoveUnitFlag(UnitFlags(e.action.unitFlag.flag)); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit {} removed flag {} to UNIT_FIELD_FLAGS", - (*itr)->GetGUID().ToString(), e.action.unitFlag.flag); - } - else - { - (*itr)->ToUnit()->RemoveUnitFlag2(UnitFlags2(e.action.unitFlag.flag)); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit {} removed flag {} to UNIT_FIELD_FLAGS_2", - (*itr)->GetGUID().ToString(), e.action.unitFlag.flag); - } + target->ToUnit()->RemoveFlag(UNIT_FIELD_FLAGS, e.action.unitFlag.flag); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit {} removed flag {} to UNIT_FIELD_FLAGS", + target->GetGUID().ToString(), e.action.unitFlag.flag); + } + else + { + target->ToUnit()->RemoveFlag(UNIT_FIELD_FLAGS_2, e.action.unitFlag.flag); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit {} removed flag {} to UNIT_FIELD_FLAGS_2", + target->GetGUID().ToString(), e.action.unitFlag.flag); } } - - delete targets; - break; } + break; + } case SMART_ACTION_AUTO_ATTACK: - { - if (!IsSmart()) - break; - - CAST_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: {} bool on = {}", - me->GetGUID().ToString(), e.action.autoAttack.attack); + { + if (!IsSmart()) break; - } + + CAST_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: {} bool on = {}", + me->GetGUID().ToString(), e.action.autoAttack.attack); + break; + } case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: - { - if (!IsSmart()) - break; - - // Xinef: Fix Combat Movement - bool move = e.action.combatMove.move; - if (move && GetMaxCombatDist() && e.GetEventType() == SMART_EVENT_MANA_PCT) - { - SetActualCombatDist(0); - CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(0); - } - else - CAST_AI(SmartAI, me->AI())->SetCombatMove(move); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature {} bool on = {}", - me->GetGUID().ToString(), e.action.combatMove.move); + { + if (!IsSmart()) break; + + // Xinef: Fix Combat Movement + bool move = e.action.combatMove.move; + if (move && GetMaxCombatDist() && e.GetEventType() == SMART_EVENT_MANA_PCT) + { + SetActualCombatDist(0); + CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(0); } + else + CAST_AI(SmartAI, me->AI())->SetCombatMove(move); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature {} bool on = {}", + me->GetGUID().ToString(), e.action.combatMove.move); + break; + } case SMART_ACTION_SET_EVENT_PHASE: - { - if (!GetBaseObject()) - break; - - SetPhase(e.action.setEventPhase.phase); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature {} set event phase {}", - GetBaseObject()->GetGUID().ToString(), e.action.setEventPhase.phase); + { + if (!GetBaseObject()) break; - } + + SetPhase(e.action.setEventPhase.phase); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature {} set event phase {}", + GetBaseObject()->GetGUID().ToString(), e.action.setEventPhase.phase); + break; + } case SMART_ACTION_INC_EVENT_PHASE: - { - if (!GetBaseObject()) - break; - - IncPhase(e.action.incEventPhase.inc); - DecPhase(e.action.incEventPhase.dec); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: Creature {} inc event phase by {}, " - "decrease by {}", GetBaseObject()->GetGUID().ToString(), e.action.incEventPhase.inc, e.action.incEventPhase.dec); + { + if (!GetBaseObject()) break; - } + + IncPhase(e.action.incEventPhase.inc); + DecPhase(e.action.incEventPhase.dec); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: Creature {} inc event phase by {}, " + "decrease by {}", GetBaseObject()->GetGUID().ToString(), e.action.incEventPhase.inc, e.action.incEventPhase.dec); + break; + } case SMART_ACTION_EVADE: - { - if (!GetBaseObject()) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature((*itr))) - if ((*itr)->ToCreature()->IsAIEnabled) - (*itr)->ToCreature()->AI()->EnterEvadeMode(); - - delete targets; + { + if (!GetBaseObject()) break; - } + + for (WorldObject* target : targets) + if (IsCreature(target)) + if (target->ToCreature()->IsAIEnabled) + target->ToCreature()->AI()->EnterEvadeMode(); + + break; + } case SMART_ACTION_FLEE_FOR_ASSIST: - { - // Xinef: do not allow to flee without control (stun, fear etc) - if (!me || me->HasUnitState(UNIT_STATE_LOST_CONTROL) || me->GetSpeed(MOVE_RUN) < 0.1f) - break; - - me->DoFleeToGetAssistance(); - if (e.action.flee.withEmote) - { - Acore::BroadcastTextBuilder builder(me, CHAT_MSG_MONSTER_EMOTE, BROADCAST_TEXT_FLEE_FOR_ASSIST, me->getGender()); - sCreatureTextMgr->SendChatPacket(me, builder, CHAT_MSG_MONSTER_EMOTE); - } - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature {} DoFleeToGetAssistance", me->GetGUID().ToString()); + { + // Xinef: do not allow to flee without control (stun, fear etc) + if (!me || me->HasUnitState(UNIT_STATE_LOST_CONTROL) || me->GetSpeed(MOVE_RUN) < 0.1f) break; + + me->DoFleeToGetAssistance(); + if (e.action.flee.withEmote) + { + Acore::BroadcastTextBuilder builder(me, CHAT_MSG_MONSTER_EMOTE, BROADCAST_TEXT_FLEE_FOR_ASSIST, me->getGender()); + sCreatureTextMgr->SendChatPacket(me, builder, CHAT_MSG_MONSTER_EMOTE); } + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature {} DoFleeToGetAssistance", me->GetGUID().ToString()); + break; + } case SMART_ACTION_COMBAT_STOP: - { - if (!me) - break; - - me->CombatStop(true); + { + if (!me) break; - } + + me->CombatStop(true); + break; + } case SMART_ACTION_CALL_GROUPEVENTHAPPENS: + { + for (WorldObject* target : targets) { - if (!GetBaseObject()) - break; + if (!IsUnit(target)) + continue; - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + Unit* unitTarget = target->ToUnit(); + // If invoker was pet or charm + Player* player = unitTarget->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (player && GetBaseObject()) { - if (IsUnit((*itr))) + player->GroupEventHappens(e.action.quest.quest, GetBaseObject()); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {}, group credit for quest {}", + unit->GetGUID().ToString(), e.action.quest.quest); + } + + // Special handling for vehicles + if (Vehicle* vehicle = unitTarget->GetVehicleKit()) + { + for (auto& Seat : vehicle->Seats) { - if (Player* player = (*itr)->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (Player* player = ObjectAccessor::GetPlayer(*unitTarget, Seat.second.Passenger.Guid)) + { player->GroupEventHappens(e.action.quest.quest, GetBaseObject()); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {}, group credit for quest {}", - (*itr)->GetGUID().ToString(), e.action.quest.quest); + } } } - - delete targets; - break; } + break; + } case SMART_ACTION_REMOVEAURASFROMSPELL: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + if (!IsUnit(target)) + continue; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (e.action.removeAura.spell) { - if (!IsUnit((*itr))) - continue; - - if (e.action.removeAura.spell) + if (e.action.removeAura.charges) { - if (e.action.removeAura.charges) - { - if (Aura* aur = (*itr)->ToUnit()->GetAura(e.action.removeAura.spell)) - aur->ModCharges(-static_cast(e.action.removeAura.charges), AURA_REMOVE_BY_EXPIRE); - } - else - (*itr)->ToUnit()->RemoveAurasDueToSpell(e.action.removeAura.spell); + if (Aura* aur = target->ToUnit()->GetAura(e.action.removeAura.spell)) + aur->ModCharges(-static_cast(e.action.removeAura.charges), AURA_REMOVE_BY_EXPIRE); } else - (*itr)->ToUnit()->RemoveAllAuras(); - - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: Unit {}, spell {}", - (*itr)->GetGUID().ToString(), e.action.removeAura.spell); - } - - delete targets; - break; - } - case SMART_ACTION_FOLLOW: - { - if (!IsSmart()) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - CAST_AI(SmartAI, me->AI())->StopFollow(false); - break; - } - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit((*itr))) - { - float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle; - CAST_AI(SmartAI, me->AI())->SetFollow((*itr)->ToUnit(), float(int32(e.action.follow.dist)) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType, e.action.follow.aliveState); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}", - me->GetGUID().ToString(), (*itr)->GetGUID().ToString()); - break; - } - } - - delete targets; - break; - } - case SMART_ACTION_RANDOM_PHASE: - { - if (!GetBaseObject()) - break; - - uint32 phases[SMART_ACTION_PARAM_COUNT]; - phases[0] = e.action.randomPhase.phase1; - phases[1] = e.action.randomPhase.phase2; - phases[2] = e.action.randomPhase.phase3; - phases[3] = e.action.randomPhase.phase4; - phases[4] = e.action.randomPhase.phase5; - phases[5] = e.action.randomPhase.phase6; - uint32 temp[SMART_ACTION_PARAM_COUNT]; - uint32 count = 0; - for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT; i++) - { - if (phases[i] > 0) - { - temp[count] = phases[i]; - ++count; - } - } - - if (count == 0) - break; - - uint32 phase = temp[urand(0, count - 1)]; - SetPhase(phase); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: Creature {} sets event phase to {}", - GetBaseObject()->GetGUID().ToString(), phase); - break; - } - case SMART_ACTION_RANDOM_PHASE_RANGE: - { - if (!GetBaseObject()) - break; - - uint32 phase = urand(e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax); - SetPhase(phase); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: Creature {} sets event phase to {}", - GetBaseObject()->GetGUID().ToString(), phase); - break; - } - case SMART_ACTION_CALL_KILLEDMONSTER: - { - if (trigger && IsPlayer(unit)) - { - unit->ToPlayer()->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, unit); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: (trigger == true) Player {}, Killcredit: {}", - unit->GetGUID().ToString(), e.action.killedMonster.creature); - } - else if (e.target.type == SMART_TARGET_NONE || e.target.type == SMART_TARGET_SELF) // Loot recipient and his group members - { - if (!me) - break; - - if (Player* player = me->GetLootRecipient()) - { - player->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, player); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}", - player->GetGUID().ToString(), e.action.killedMonster.creature); - } - } - else // Specific target type - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsUnit(*itr)) - continue; - - Player* player = (*itr)->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself(); - if (!player) - continue; - - player->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, player); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}", - (*itr)->GetGUID().ToString(), e.action.killedMonster.creature); - } - - delete targets; - } - break; - } - case SMART_ACTION_SET_INST_DATA: - { - WorldObject* obj = GetBaseObject(); - if (!obj) - obj = unit; - - if (!obj) - break; - - InstanceScript* instance = obj->GetInstanceScript(); - if (!instance) - { - LOG_ERROR("scripts.ai.sai", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid); - break; - } - - switch (e.action.setInstanceData.type) - { - case 0: - { - instance->SetData(e.action.setInstanceData.field, e.action.setInstanceData.data); - LOG_DEBUG("scripts.ai.sai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: Field: {}, data: {}", e.action.setInstanceData.field, e.action.setInstanceData.data); - } break; - case 1: - { - instance->SetBossState(e.action.setInstanceData.field, static_cast(e.action.setInstanceData.data)); - LOG_DEBUG("scripts.ai.sai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetBossState BossId: {}, State: {} ({})", e.action.setInstanceData.field, e.action.setInstanceData.data, InstanceScript::GetBossStateName(e.action.setInstanceData.data)); - } break; - default: - { - break; - } - } - break; - } - case SMART_ACTION_SET_INST_DATA64: - { - WorldObject* obj = GetBaseObject(); - if (!obj) - obj = unit; - - if (!obj) - break; - - InstanceScript* instance = obj->GetInstanceScript(); - if (!instance) - { - LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid); - break; - } - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - instance->SetGuidData(e.action.setInstanceData64.field, targets->front()->GetGUID()); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: {}, data: {}", e.action.setInstanceData64.field, targets->front()->GetGUID().GetRawValue()); - delete targets; - break; - } - case SMART_ACTION_UPDATE_TEMPLATE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->UpdateEntry(e.action.updateTemplate.creature, nullptr, e.action.updateTemplate.updateLevel != 0); - - delete targets; - break; - } - case SMART_ACTION_DIE: - { - if (me && !me->isDead()) - { - Unit::Kill(me, me); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString()); - } - break; - } - case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - if (!me->GetMap()->IsDungeon()) - { - ObjectList* units = GetWorldObjectsInDist((float)e.action.combatZone.range); - if (!units->empty() && GetBaseObject()) - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (IsPlayer(*itr) && !(*itr)->ToPlayer()->isDead()) - { - me->SetInCombatWith((*itr)->ToPlayer()); - (*itr)->ToPlayer()->SetInCombatWith(me); - me->AddThreat((*itr)->ToPlayer(), 0.0f); - } + target->ToUnit()->RemoveAurasDueToSpell(e.action.removeAura.spell); } else - { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->SetInCombatWithZone(); - } + target->ToUnit()->RemoveAllAuras(); - delete targets; + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: Unit {}, spell {}", + target->GetGUID().ToString(), e.action.removeAura.spell); + } + break; + } + case SMART_ACTION_FOLLOW: + { + if (!IsSmart()) + break; + + if (targets.empty()) + { + CAST_AI(SmartAI, me->AI())->StopFollow(false); break; } - case SMART_ACTION_CALL_FOR_HELP: + + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) + if (IsUnit(target)) + { + float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle; + CAST_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}", + me->GetGUID().ToString(), target->GetGUID().ToString()); + break; + } + } + break; + } + case SMART_ACTION_RANDOM_PHASE: + { + if (!GetBaseObject()) + break; + + std::vector phases; + std::copy_if(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(), + std::back_inserter(phases), [](uint32 phase) { return phase != 0; }); + + uint32 phase = Acore::Containers::SelectRandomContainerElement(phases); + SetPhase(phase); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: Creature {} sets event phase to {}", + GetBaseObject()->GetGUID().ToString(), phase); + break; + } + case SMART_ACTION_RANDOM_PHASE_RANGE: + { + if (!GetBaseObject()) + break; + + uint32 phase = urand(e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax); + SetPhase(phase); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: Creature {} sets event phase to {}", + GetBaseObject()->GetGUID().ToString(), phase); + break; + } + case SMART_ACTION_CALL_KILLEDMONSTER: + { + if (trigger && IsPlayer(unit)) + { + unit->ToPlayer()->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, unit); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: (trigger == true) Player {}, Killcredit: {}", + unit->GetGUID().ToString(), e.action.killedMonster.creature); + } + else if (e.target.type == SMART_TARGET_NONE || e.target.type == SMART_TARGET_SELF) // Loot recipient and his group members + { + if (!me) break; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (Player* player = me->GetLootRecipient()) { - if (IsCreature(*itr)) - { - (*itr)->ToCreature()->CallForHelp((float)e.action.callHelp.range, e.GetEventType() == SMART_EVENT_AGGRO ? unit : nullptr); - if (e.action.callHelp.withEmote) - { - Acore::BroadcastTextBuilder builder(*itr, CHAT_MSG_MONSTER_EMOTE, BROADCAST_TEXT_CALL_FOR_HELP, LANG_UNIVERSAL, nullptr); - sCreatureTextMgr->SendChatPacket(*itr, builder, CHAT_MSG_MONSTER_EMOTE); - } - } + player->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, player); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}", + player->GetGUID().ToString(), e.action.killedMonster.creature); } - - delete targets; - break; } - case SMART_ACTION_SET_SHEATH: + else // Specific target type { - if (me) + for (WorldObject* target : targets) { - me->SetSheath(SheathState(e.action.setSheath.sheath)); - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: Creature {}, State: {}", - me->GetGUID().ToString(), e.action.setSheath.sheath); - } - break; - } - case SMART_ACTION_FORCE_DESPAWN: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - Milliseconds despawnDelay(e.action.forceDespawn.delay); - - // Wait at least one world update tick before despawn, so it doesn't break linked actions. - if (despawnDelay <= 0ms) - { - despawnDelay = 1ms; - } - - Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer); - if (Creature* creature = (*itr)->ToCreature()) - { - creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer); - } - else if (GameObject* go = (*itr)->ToGameObject()) - { - go->DespawnOrUnsummon(despawnDelay, forceRespawnTimer); - } - } - - delete targets; - break; - } - case SMART_ACTION_SET_INGAME_PHASE_MASK: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetPhaseMask(e.action.ingamePhaseMask.mask, true); - else if (IsGameObject(*itr)) - (*itr)->ToGameObject()->SetPhaseMask(e.action.ingamePhaseMask.mask, true); - } - - delete targets; - break; - } - case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsUnit(*itr)) + if (!IsUnit(target)) continue; - if (e.action.morphOrMount.creature || e.action.morphOrMount.model) - { - if (e.action.morphOrMount.creature > 0) + Player* player = target->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!player) + continue; + + player->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, player); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}", + target->GetGUID().ToString(), e.action.killedMonster.creature); + } + } + break; + } + case SMART_ACTION_SET_INST_DATA: + { + WorldObject* obj = GetBaseObject(); + if (!obj) + obj = unit; + + if (!obj) + break; + + InstanceScript* instance = obj->GetInstanceScript(); + if (!instance) + { + LOG_ERROR("scripts.ai.sai", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid); + break; + } + + switch (e.action.setInstanceData.type) + { + case 0: + { + instance->SetData(e.action.setInstanceData.field, e.action.setInstanceData.data); + LOG_DEBUG("scripts.ai.sai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: Field: {}, data: {}", e.action.setInstanceData.field, e.action.setInstanceData.data); + } break; + case 1: + { + instance->SetBossState(e.action.setInstanceData.field, static_cast(e.action.setInstanceData.data)); + LOG_DEBUG("scripts.ai.sai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetBossState BossId: {}, State: {} ({})", e.action.setInstanceData.field, e.action.setInstanceData.data, InstanceScript::GetBossStateName(e.action.setInstanceData.data)); + } break; + default: + { + break; + } + } + break; + } + case SMART_ACTION_SET_INST_DATA64: + { + WorldObject* obj = GetBaseObject(); + if (!obj) + obj = unit; + + if (!obj) + break; + + InstanceScript* instance = obj->GetInstanceScript(); + if (!instance) + { + LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid); + break; + } + + if (targets.empty()) + break; + + instance->SetGuidData(e.action.setInstanceData64.field, targets.front()->GetGUID()); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: {}, data: {}", + e.action.setInstanceData64.field, targets.front()->GetGUID().ToString()); + break; + } + case SMART_ACTION_UPDATE_TEMPLATE: + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToCreature()->UpdateEntry(e.action.updateTemplate.creature, target->ToCreature()->GetCreatureData(), e.action.updateTemplate.updateLevel != 0); + break; + } + case SMART_ACTION_DIE: + { + if (me && !me->isDead()) + { + Unit::Kill(me, me); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString()); + } + break; + } + case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: + { + if (targets.empty()) + break; + + if (!me->GetMap()->IsDungeon()) + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.unitRange.maxDist)); + + if (!units.empty() && GetBaseObject()) + for (WorldObject* unit : units) + if (IsPlayer(unit) && !unit->ToPlayer()->isDead()) { - if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) - (*itr)->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo)); + me->SetInCombatWith(unit->ToPlayer()); + unit->ToPlayer()->SetInCombatWith(me); + me->AddThreat(unit->ToPlayer(), 0.0f); } - else - (*itr)->ToUnit()->Mount(e.action.morphOrMount.model); + } + else + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->SetInCombatWithZone(); + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature {}, target: {}", + me->GetGUID().ToString(), target->GetGUID().ToString()); + } + } + } + + break; + } + case SMART_ACTION_CALL_FOR_HELP: + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->CallForHelp(float(e.action.callHelp.range)); + if (e.action.callHelp.withEmote) + { + Acore::BroadcastTextBuilder builder(target, CHAT_MSG_MONSTER_EMOTE, BROADCAST_TEXT_CALL_FOR_HELP, LANG_UNIVERSAL, nullptr); + sCreatureTextMgr->SendChatPacket(target, builder, CHAT_MSG_MONSTER_EMOTE); + } + LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature {}, target: {}", + me->GetGUID().ToString(), target->GetGUID().ToString()); + } + } + break; + } + case SMART_ACTION_SET_SHEATH: + { + if (me) + { + me->SetSheath(SheathState(e.action.setSheath.sheath)); + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: Creature {}, State: {}", + me->GetGUID().ToString(), e.action.setSheath.sheath); + } + break; + } + case SMART_ACTION_FORCE_DESPAWN: + { + for (WorldObject* target : targets) + { + Milliseconds despawnDelay(e.action.forceDespawn.delay); + + // Wait at least one world update tick before despawn, so it doesn't break linked actions. + if (despawnDelay <= 0ms) + { + despawnDelay = 1ms; + } + + Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer); + if (Creature* creature = target->ToCreature()) + { + creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer); + } + else if (GameObject* go = target->ToGameObject()) + { + go->DespawnOrUnsummon(despawnDelay, forceRespawnTimer); + } + } + + break; + } + case SMART_ACTION_SET_INGAME_PHASE_MASK: + { + for (WorldObject* target : targets) + { + if (IsUnit(target)) + target->ToUnit()->SetPhaseMask(e.action.ingamePhaseMask.mask, true); + else if (IsGameObject(target)) + target->ToGameObject()->SetPhaseMask(e.action.ingamePhaseMask.mask, true); + } + break; + } + case SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL: + { + for (WorldObject* target : targets) + { + if (!IsUnit(target)) + continue; + + if (e.action.morphOrMount.creature || e.action.morphOrMount.model) + { + if (e.action.morphOrMount.creature > 0) + { + if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) + target->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo)); } else - (*itr)->ToUnit()->Dismount(); + target->ToUnit()->Mount(e.action.morphOrMount.model); } - - delete targets; - break; + else + target->ToUnit()->Dismount(); } + break; + } case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(target)) { - if (IsCreature(*itr)) - { - SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI()); - if (!ai) - continue; + SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()); + if (!ai) + continue; - if (e.action.invincHP.percent) - ai->SetInvincibilityHpLevel((*itr)->ToCreature()->CountPctFromMaxHealth(e.action.invincHP.percent)); - else - ai->SetInvincibilityHpLevel(e.action.invincHP.minHP); - } + if (e.action.invincHP.percent) + ai->SetInvincibilityHpLevel(target->ToCreature()->CountPctFromMaxHealth(e.action.invincHP.percent)); + else + ai->SetInvincibilityHpLevel(e.action.invincHP.minHP); } - - delete targets; - break; } + break; + } case SMART_ACTION_SET_DATA: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsCreature(*itr)) - (*itr)->ToCreature()->AI()->SetData(e.action.setData.field, e.action.setData.data); - else if (IsGameObject(*itr)) - (*itr)->ToGameObject()->AI()->SetData(e.action.setData.field, e.action.setData.data); - } - - delete targets; - break; + if (IsCreature(target)) + target->ToCreature()->AI()->SetData(e.action.setData.field, e.action.setData.data); + else if (IsGameObject(target)) + target->ToGameObject()->AI()->SetData(e.action.setData.field, e.action.setData.data); } + break; + } case SMART_ACTION_MOVE_FORWARD: - { - if (!me) - break; - - float x, y, z; - me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, (float)e.action.moveRandom.distance); - me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, x, y, z); + { + if (!me) break; - } + + float x, y, z; + me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, (float)e.action.moveRandom.distance); + me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, x, y, z); + break; + } case SMART_ACTION_RISE_UP: - { - if (!me) - break; - - me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + (float)e.action.moveRandom.distance); + { + if (!me) break; - } + + me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + (float)e.action.moveRandom.distance); + break; + } case SMART_ACTION_SET_VISIBILITY: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetVisible(!!e.action.visibility.state); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetVisible(!!e.action.visibility.state); - - delete targets; - break; - } + break; + } case SMART_ACTION_SET_ACTIVE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - (*itr)->setActive(!!e.action.setActive.state); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + target->setActive(!!e.action.setActive.state); + break; + } case SMART_ACTION_ATTACK_START: - { - if (!me) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - // xinef: attack random target - if (Unit* target = Acore::Containers::SelectRandomContainerElement(*targets)->ToUnit()) - me->AI()->AttackStart(target); - - delete targets; + { + if (!me) break; - } + + if (targets.empty()) + break; + + // attack random target + if (Unit* target = Acore::Containers::SelectRandomContainerElement(targets)->ToUnit()) + me->AI()->AttackStart(target); + break; + } case SMART_ACTION_ATTACK_STOP: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - break; - } + { + for (WorldObject* target : targets) + if (Unit* unitTarget = target->ToUnit()) + unitTarget->AttackStop(); + break; + } + case SMART_ACTION_SUMMON_CREATURE: + { + WorldObject* summoner = GetBaseObject() ? GetBaseObject() : unit; + if (!summoner) + break; - for (auto const& target : *targets) + if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT) + { + float range = (float)e.target.randomPoint.range; + Position randomPoint; + Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o }; + for (uint32 i = 0; i < e.target.randomPoint.amount; i++) { - if (Unit* unitTarget = target->ToUnit()) + if (e.target.randomPoint.self > 0) + randomPoint = me->GetRandomPoint(me->GetPosition(), range); + else + randomPoint = me->GetRandomPoint(srcPos, range); + if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, randomPoint, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) { - unitTarget->AttackStop(); + if (unit && e.action.summonCreature.attackInvoker) + summon->AI()->AttackStart(unit); + else if (me && e.action.summonCreature.attackScriptOwner) + summon->AI()->AttackStart(me); } } - - delete targets; break; } - case SMART_ACTION_SUMMON_CREATURE: + + float x, y, z, o; + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - WorldObject* summoner = GetBaseObject() ? GetBaseObject() : unit; - if (!summoner) - break; - - if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT) + target->GetPosition(x, y, z, o); + x += e.target.x; + y += e.target.y; + z += e.target.z; + o += e.target.o; + if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) { - float range = (float)e.target.randomPoint.range; - Position randomPoint; - Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o }; - for (uint32 i = 0; i < e.target.randomPoint.amount; i++) - { - if (e.target.randomPoint.self > 0) - randomPoint = me->GetRandomPoint(me->GetPosition(), range); - else - randomPoint = me->GetRandomPoint(srcPos, range); - if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, randomPoint, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) - { - if (unit && e.action.summonCreature.attackInvoker) - summon->AI()->AttackStart(unit); - else if (me && e.action.summonCreature.attackScriptOwner) - summon->AI()->AttackStart(me); - } - } - break; - } - - if (targets) - { - float x, y, z, o; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - (*itr)->GetPosition(x, y, z, o); - x += e.target.x; - y += e.target.y; - z += e.target.z; - o += e.target.o; - if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) - { - if (e.action.summonCreature.attackInvoker == 2) // pussywizard: proper attackInvoker implementation - summon->AI()->AttackStart(unit); - else if (e.action.summonCreature.attackInvoker) - summon->AI()->AttackStart((*itr)->ToUnit()); - else if (me && e.action.summonCreature.attackScriptOwner) - summon->AI()->AttackStart(me); - } - } - - delete targets; - } - - if (e.GetTargetType() != SMART_TARGET_POSITION) - break; - - if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) - { - if (unit && e.action.summonCreature.attackInvoker) + if (e.action.summonCreature.attackInvoker == 2) // pussywizard: proper attackInvoker implementation summon->AI()->AttackStart(unit); + else if (e.action.summonCreature.attackInvoker) + summon->AI()->AttackStart(target->ToUnit()); else if (me && e.action.summonCreature.attackScriptOwner) summon->AI()->AttackStart(me); } - break; } + + if (e.GetTargetType() != SMART_TARGET_POSITION) + break; + + if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) + { + if (unit && e.action.summonCreature.attackInvoker) + summon->AI()->AttackStart(unit); + else if (me && e.action.summonCreature.attackScriptOwner) + summon->AI()->AttackStart(me); + } + break; + } case SMART_ACTION_SUMMON_GO: - { - if (!GetBaseObject()) - break; - - ObjectList* targets = GetTargets(e, unit); - if (targets) - { - float x, y, z, o; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - // xinef: allow gameobjects to summon gameobjects! - //if(!IsUnit((*itr))) - // continue; - - (*itr)->GetPosition(x, y, z, o); - x += e.target.x; - y += e.target.y; - z += e.target.z; - o += e.target.o; - if (!e.action.summonGO.targetsummon) - GetBaseObject()->SummonGameObject(e.action.summonGO.entry, x, y, z, o, 0, 0, 0, 0, e.action.summonGO.despawnTime, GOSummonType(e.action.summonGO.summonType)); - else - (*itr)->SummonGameObject(e.action.summonGO.entry, GetBaseObject()->GetPositionX(), GetBaseObject()->GetPositionY(), GetBaseObject()->GetPositionZ(), GetBaseObject()->GetOrientation(), 0, 0, 0, 0, e.action.summonGO.despawnTime); - } - - delete targets; - } - - if (e.GetTargetType() != SMART_TARGET_POSITION) - break; - - GetBaseObject()->SummonGameObject(e.action.summonGO.entry, e.target.x, e.target.y, e.target.z, e.target.o, 0, 0, 0, 0, e.action.summonGO.despawnTime, GOSummonType(e.action.summonGO.summonType)); + { + if (!GetBaseObject()) break; + + if (!targets.empty()) + { + float x, y, z, o; + for (WorldObject* target : targets) + { + // xinef: allow gameobjects to summon gameobjects! + //if(!IsUnit((*itr))) + // continue; + + target->GetPosition(x, y, z, o); + x += e.target.x; + y += e.target.y; + z += e.target.z; + o += e.target.o; + if (!e.action.summonGO.targetsummon) + GetBaseObject()->SummonGameObject(e.action.summonGO.entry, x, y, z, o, 0, 0, 0, 0, e.action.summonGO.despawnTime); + else + target->SummonGameObject(e.action.summonGO.entry, GetBaseObject()->GetPositionX(), GetBaseObject()->GetPositionY(), GetBaseObject()->GetPositionZ(), GetBaseObject()->GetOrientation(), 0, 0, 0, 0, e.action.summonGO.despawnTime); + } } + + if (e.GetTargetType() != SMART_TARGET_POSITION) + break; + + GetBaseObject()->SummonGameObject(e.action.summonGO.entry, e.target.x, e.target.y, e.target.z, e.target.o, 0, 0, 0, 0, e.action.summonGO.despawnTime); + break; + } case SMART_ACTION_KILL_UNIT: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + if (!IsUnit(target)) + continue; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsUnit(*itr)) - continue; - - Unit::Kill((*itr)->ToUnit(), (*itr)->ToUnit()); - } - - delete targets; - break; + Unit::Kill(target->ToUnit(), target->ToUnit()); } + + break; + } case SMART_ACTION_INSTALL_AI_TEMPLATE: - { - InstallTemplate(e); - break; - } + { + InstallTemplate(e); + break; + } case SMART_ACTION_ADD_ITEM: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + if (!IsPlayer(target)) + continue; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsPlayer(*itr)) - continue; - - (*itr)->ToPlayer()->AddItem(e.action.item.entry, e.action.item.count); - } - - delete targets; - break; + target->ToPlayer()->AddItem(e.action.item.entry, e.action.item.count); } + break; + } case SMART_ACTION_REMOVE_ITEM: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + if (!IsPlayer(target)) + continue; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsPlayer(*itr)) - continue; - - (*itr)->ToPlayer()->DestroyItemCount(e.action.item.entry, e.action.item.count, true); - } - - delete targets; - break; + target->ToPlayer()->DestroyItemCount(e.action.item.entry, e.action.item.count, true); } + break; + } case SMART_ACTION_STORE_TARGET_LIST: - { - ObjectList* targets = GetTargets(e, unit); - StoreTargetList(targets, e.action.storeTargets.id); - break; - } + { + StoreTargetList(targets, e.action.storeTargets.id); + break; + } case SMART_ACTION_TELEPORT: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsPlayer(*itr)) - (*itr)->ToPlayer()->TeleportTo(e.action.teleport.mapID, e.target.x, e.target.y, e.target.z, e.target.o); - else if (IsUnit(*itr)) - (*itr)->ToUnit()->NearTeleportTo(e.target.x, e.target.y, e.target.z, e.target.o); - } - - delete targets; - break; + if (IsPlayer(target)) + target->ToPlayer()->TeleportTo(e.action.teleport.mapID, e.target.x, e.target.y, e.target.z, e.target.o); + else if (IsCreature(target)) + target->ToCreature()->NearTeleportTo(e.target.x, e.target.y, e.target.z, e.target.o); } + break; + } case SMART_ACTION_SET_FLY: - { - if (!IsSmart()) - break; - - CAST_AI(SmartAI, me->AI())->SetFly(e.action.setFly.fly); - // Xinef: Set speed if any - if (e.action.setFly.speed) - me->SetSpeed(MOVE_RUN, float(e.action.setFly.speed / 100.0f), true); - - // Xinef: this wil be executed only if state is different - me->SetDisableGravity(e.action.setFly.disableGravity); + { + if (!IsSmart()) break; - } + + CAST_AI(SmartAI, me->AI())->SetFly(e.action.setFly.fly); + // Xinef: Set speed if any + if (e.action.setFly.speed) + me->SetSpeed(MOVE_RUN, float(e.action.setFly.speed / 100.0f), true); + + // Xinef: this wil be executed only if state is different + me->SetDisableGravity(e.action.setFly.disableGravity); + break; + } case SMART_ACTION_SET_RUN: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(target)) { - if (IsCreature(*itr)) - { - if (IsSmart((*itr)->ToCreature())) - CAST_AI(SmartAI, (*itr)->ToCreature()->AI())->SetRun(e.action.setRun.run); - else - (*itr)->ToCreature()->SetWalk(e.action.setRun.run ? false : true); // Xinef: reversed - } + if (IsSmart(target->ToCreature())) + CAST_AI(SmartAI, target->ToCreature()->AI())->SetRun(e.action.setRun.run); + else + target->ToCreature()->SetWalk(e.action.setRun.run ? false : true); // Xinef: reversed } - - delete targets; - break; } + + break; + } case SMART_ACTION_SET_SWIM: - { - if (!IsSmart()) - break; - - CAST_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim); + { + if (!IsSmart()) break; - } + + CAST_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim); + break; + } case SMART_ACTION_SET_COUNTER: + { + if (!targets.empty()) { - if (ObjectList* targets = GetTargets(e, unit)) + for (WorldObject* target : targets) { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(target)) { - if (IsCreature(*itr)) - { - if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI())) - ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset, e.action.setCounter.subtract); - else - LOG_ERROR("scripts.ai.sai", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping"); - } - else if (IsGameObject(*itr)) - { - if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI())) - ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset, e.action.setCounter.subtract); - else - LOG_ERROR("scripts.ai.sai", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping"); - } + if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI())) + ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset, e.action.setCounter.subtract); + else + LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping"); + } + else if (IsGameObject(target)) + { + if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI())) + ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset, e.action.setCounter.subtract); + else + LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping"); } - delete targets; } - else - { - StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset, e.action.setCounter.subtract); - } - break; } + else + StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset, e.action.setCounter.subtract); + break; + } case SMART_ACTION_WP_START: - { - if (!IsSmart()) - break; - - bool run = e.action.wpStart.run; - uint32 entry = e.action.wpStart.pathID; - bool repeat = e.action.wpStart.repeat; - - // Xinef: ensure that SMART_ESCORT_TARGETS contains at least one player reference - bool stored = false; - ObjectList* targets = GetTargets(e, unit); - if (targets) - { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsPlayer(*itr)) - { - stored = true; - StoreTargetList(targets, SMART_ESCORT_TARGETS); - break; - } - } - if (!stored) - delete targets; - } - if (e.action.wpStart.reactState <= REACT_AGGRESSIVE) - { - me->SetReactState((ReactStates) e.action.wpStart.reactState); - } - CAST_AI(SmartAI, me->AI())->StartPath(run, entry, repeat, unit); - - uint32 quest = e.action.wpStart.quest; - uint32 DespawnTime = e.action.wpStart.despawnTime; - CAST_AI(SmartAI, me->AI())->mEscortQuestID = quest; - CAST_AI(SmartAI, me->AI())->SetDespawnTime(DespawnTime); + { + if (!IsSmart()) break; + + bool run = e.action.wpStart.run != 0; + uint32 entry = e.action.wpStart.pathID; + bool repeat = e.action.wpStart.repeat != 0; + + for (WorldObject* target : targets) + { + if (IsPlayer(target)) + { + StoreTargetList(targets, SMART_ESCORT_TARGETS); + break; + } } + + me->SetReactState((ReactStates)e.action.wpStart.reactState); + CAST_AI(SmartAI, me->AI())->StartPath(run, entry, repeat, unit); + + uint32 quest = e.action.wpStart.quest; + uint32 DespawnTime = e.action.wpStart.despawnTime; + CAST_AI(SmartAI, me->AI())->mEscortQuestID = quest; + CAST_AI(SmartAI, me->AI())->SetDespawnTime(DespawnTime); + break; + } case SMART_ACTION_WP_PAUSE: - { - if (!IsSmart()) - break; - - uint32 delay = e.action.wpPause.delay; - CAST_AI(SmartAI, me->AI())->PausePath(delay, e.GetEventType() == SMART_EVENT_WAYPOINT_REACHED ? false : true); + { + if (!IsSmart()) break; - } + + uint32 delay = e.action.wpPause.delay; + CAST_AI(SmartAI, me->AI())->PausePath(delay, e.GetEventType() == SMART_EVENT_WAYPOINT_REACHED ? false : true); + break; + } case SMART_ACTION_WP_STOP: - { - if (!IsSmart()) - break; - - uint32 DespawnTime = e.action.wpStop.despawnTime; - uint32 quest = e.action.wpStop.quest; - bool fail = e.action.wpStop.fail; - CAST_AI(SmartAI, me->AI())->StopPath(DespawnTime, quest, fail); + { + if (!IsSmart()) break; - } + + uint32 DespawnTime = e.action.wpStop.despawnTime; + uint32 quest = e.action.wpStop.quest; + bool fail = e.action.wpStop.fail; + CAST_AI(SmartAI, me->AI())->StopPath(DespawnTime, quest, fail); + break; + } case SMART_ACTION_WP_RESUME: - { - if (!IsSmart()) - break; - - CAST_AI(SmartAI, me->AI())->SetWPPauseTimer(0); + { + if (!IsSmart()) break; - } + + CAST_AI(SmartAI, me->AI())->SetWPPauseTimer(0); + break; + } case SMART_ACTION_SET_ORIENTATION: + { + if (!me) + break; + + if (e.action.orientation.random > 0) { - if (!me) - break; - - if (e.action.orientation.random > 0) - { - float randomOri = frand(0.0f, 2 * M_PI); - me->SetFacingTo(randomOri); - if (e.action.orientation.quickChange) - me->SetOrientation(randomOri); - break; - } - - if (e.GetTargetType() == SMART_TARGET_SELF) - { - me->SetFacingTo((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); - if (e.action.orientation.quickChange) - me->SetOrientation((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); - } - else if (e.GetTargetType() == SMART_TARGET_POSITION) - { - me->SetFacingTo(e.target.o); - if (e.action.orientation.quickChange) - me->SetOrientation(e.target.o); - } - else if (ObjectList* targets = GetTargets(e, unit)) - { - if (!targets->empty()) - { - me->SetFacingToObject(*targets->begin()); - if (e.action.orientation.quickChange) - me->SetInFront(*targets->begin()); - } - - delete targets; - } - + float randomOri = frand(0.0f, 2 * M_PI); + me->SetFacingTo(randomOri); + if (e.action.orientation.quickChange) + me->SetOrientation(randomOri); break; } + + if (e.GetTargetType() == SMART_TARGET_SELF) + { + me->SetFacingTo((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); + if (e.action.orientation.quickChange) + me->SetOrientation((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); + } + else if (e.GetTargetType() == SMART_TARGET_POSITION) + { + me->SetFacingTo(e.target.o); + if (e.action.orientation.quickChange) + me->SetOrientation(e.target.o); + } + else if (!targets.empty()) + { + me->SetFacingToObject(*targets.begin()); + if (e.action.orientation.quickChange) + me->SetInFront(*targets.begin()); + } + + break; + } case SMART_ACTION_PLAYMOVIE: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + if (!IsPlayer(target)) + continue; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (!IsPlayer(*itr)) - continue; - - (*itr)->ToPlayer()->SendMovieStart(e.action.movie.entry); - } - - delete targets; - break; + target->ToPlayer()->SendMovieStart(e.action.movie.entry); } + break; + } case SMART_ACTION_MOVE_TO_POS: + { + if (!IsSmart()) + break; + + WorldObject* target = nullptr; + + if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT) { - if (!IsSmart()) - break; - - WorldObject* target = nullptr; - - if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT) + if (me) { - if (me) - { - float range = (float)e.target.randomPoint.range; - Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o }; - Position randomPoint = me->GetRandomPoint(srcPos, range); - me->GetMotionMaster()->MovePoint( + float range = (float)e.target.randomPoint.range; + Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o }; + Position randomPoint = me->GetRandomPoint(srcPos, range); + me->GetMotionMaster()->MovePoint( e.action.moveToPos.pointId, randomPoint.m_positionX, randomPoint.m_positionY, @@ -1895,174 +1597,141 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE - ); - } - - break; + ); } - /*if (e.GetTargetType() == SMART_TARGET_CREATURE_RANGE || e.GetTargetType() == SMART_TARGET_CREATURE_GUID || - e.GetTargetType() == SMART_TARGET_CREATURE_DISTANCE || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_RANGE || - e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE || - e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT || - e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER || - e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY || - e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_STORED) // Xinef: bieda i rozpierdol TC)*/ - { - if (ObjectList* targets = GetTargets(e, unit)) - { - // xinef: we want to move to random element - target = Acore::Containers::SelectRandomContainerElement(*targets); - delete targets; - } - } - - if (!target) - { - G3D::Vector3 dest(e.target.x, e.target.y, e.target.z); - if (e.action.moveToPos.transport) - if (TransportBase* trans = me->GetDirectTransport()) - trans->CalculatePassengerPosition(dest.x, dest.y, dest.z); - - me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, true, - isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE, e.target.o); - } - else // Xinef: we can use dest.x, dest.y, dest.z to make offset - { - float x, y, z; - target->GetPosition(x, y, z); - if (e.action.moveToPos.ContactDistance > 0) - target->GetContactPoint(me, x, y, z, e.action.moveToPos.ContactDistance); - me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE); - } break; } + + /*if (e.GetTargetType() == SMART_TARGET_CREATURE_RANGE || e.GetTargetType() == SMART_TARGET_CREATURE_GUID || + e.GetTargetType() == SMART_TARGET_CREATURE_DISTANCE || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_RANGE || + e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE || + e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT || + e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER || + e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY || + e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_STORED) // Xinef: bieda i rozpierdol TC)*/ + { + // we want to move to random element + if (!targets.empty()) + target = Acore::Containers::SelectRandomContainerElement(targets); + } + + if (!target) + { + G3D::Vector3 dest(e.target.x, e.target.y, e.target.z); + if (e.action.moveToPos.transport) + if (TransportBase* trans = me->GetDirectTransport()) + trans->CalculatePassengerPosition(dest.x, dest.y, dest.z); + + me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, true, + isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE, e.target.o); + } + else // Xinef: we can use dest.x, dest.y, dest.z to make offset + { + float x, y, z; + target->GetPosition(x, y, z); + if (e.action.moveToPos.ContactDistance > 0) + target->GetContactPoint(me, x, y, z, e.action.moveToPos.ContactDistance); + me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE); + } + break; + } case SMART_ACTION_MOVE_TO_POS_TARGET: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - return; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(target)) { - if (IsCreature(*itr)) - { - Creature* target = (*itr)->ToCreature(); - target->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, e.target.x, e.target.y, e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE); - } + Creature* ctarget = target->ToCreature(); + ctarget->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, e.target.x, e.target.y, e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE); } - - delete targets; - break; } + + break; + } case SMART_ACTION_RESPAWN_TARGET: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(target)) + target->ToCreature()->Respawn(); + else if (IsGameObject(target)) { - if (IsCreature(*itr)) - (*itr)->ToCreature()->Respawn(e.action.RespawnTarget.goRespawnTime); - else if (IsGameObject(*itr)) - { - // Xinef: do not modify respawndelay of already spawned gameobjects QQ - if ((*itr)->ToGameObject()->isSpawnedByDefault()) - (*itr)->ToGameObject()->Respawn(); - else - (*itr)->ToGameObject()->SetRespawnTime(e.action.RespawnTarget.goRespawnTime); - } + // do not modify respawndelay of already spawned gameobjects + if (target->ToGameObject()->isSpawnedByDefault()) + target->ToGameObject()->Respawn(); + else + target->ToGameObject()->SetRespawnTime(e.action.RespawnTarget.goRespawnTime); } - - delete targets; - break; } + break; + } case SMART_ACTION_CLOSE_GOSSIP: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsPlayer(*itr)) - (*itr)->ToPlayer()->PlayerTalkClass->SendCloseGossip(); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsPlayer(target)) + target->ToPlayer()->PlayerTalkClass->SendCloseGossip(); + break; + } case SMART_ACTION_EQUIP: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (Creature* npc = target->ToCreature()) { - if (Creature* npc = (*itr)->ToCreature()) + std::array slot; + if (int8 equipId = static_cast(e.action.equip.entry)) { - uint32 slot[3]; - int8 equipId = (int8)e.action.equip.entry; - if (equipId) + EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId); + if (!eInfo) { - EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId); - if (!einfo) - { - LOG_ERROR("scripts.ai.sai", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}", equipId, npc->GetEntry()); - break; - } - npc->SetCurrentEquipmentId(equipId); - slot[0] = einfo->ItemEntry[0]; - slot[1] = einfo->ItemEntry[1]; - slot[2] = einfo->ItemEntry[2]; + LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}", equipId, npc->GetEntry()); + break; } - else - { - slot[0] = e.action.equip.slot1; - slot[1] = e.action.equip.slot2; - slot[2] = e.action.equip.slot3; - } - if (!e.action.equip.mask || (e.action.equip.mask & 1)) - npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, slot[0]); - if (!e.action.equip.mask || (e.action.equip.mask & 2)) - npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, slot[1]); - if (!e.action.equip.mask || (e.action.equip.mask & 4)) - npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, slot[2]); + + npc->SetCurrentEquipmentId(equipId); + + std::copy(std::begin(eInfo->ItemEntry), std::end(eInfo->ItemEntry), std::begin(slot)); } + else + std::copy(std::begin(e.action.equip.slots), std::end(e.action.equip.slots), std::begin(slot)); + + for (uint32 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i) + if (!e.action.equip.mask || (e.action.equip.mask & (1 << i))) + npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, slot[i]); } - - delete targets; - break; } + break; + } case SMART_ACTION_CREATE_TIMED_EVENT: - { - SmartEvent ne = SmartEvent(); - ne.type = (SMART_EVENT)SMART_EVENT_UPDATE; - ne.event_chance = e.action.timeEvent.chance; - if (!ne.event_chance) ne.event_chance = 100; + { + SmartEvent ne = SmartEvent(); + ne.type = (SMART_EVENT)SMART_EVENT_UPDATE; + ne.event_chance = e.action.timeEvent.chance; + if (!ne.event_chance) ne.event_chance = 100; - ne.minMaxRepeat.min = e.action.timeEvent.min; - ne.minMaxRepeat.max = e.action.timeEvent.max; - ne.minMaxRepeat.repeatMin = e.action.timeEvent.repeatMin; - ne.minMaxRepeat.repeatMax = e.action.timeEvent.repeatMax; + ne.minMaxRepeat.min = e.action.timeEvent.min; + ne.minMaxRepeat.max = e.action.timeEvent.max; + ne.minMaxRepeat.repeatMin = e.action.timeEvent.repeatMin; + ne.minMaxRepeat.repeatMax = e.action.timeEvent.repeatMax; - ne.event_flags = 0; - if (!ne.minMaxRepeat.repeatMin && !ne.minMaxRepeat.repeatMax) - ne.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE; + ne.event_flags = 0; + if (!ne.minMaxRepeat.repeatMin && !ne.minMaxRepeat.repeatMax) + ne.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE; - SmartAction ac = SmartAction(); - ac.type = (SMART_ACTION)SMART_ACTION_TRIGGER_TIMED_EVENT; - ac.timeEvent.id = e.action.timeEvent.id; + SmartAction ac = SmartAction(); + ac.type = (SMART_ACTION)SMART_ACTION_TRIGGER_TIMED_EVENT; + ac.timeEvent.id = e.action.timeEvent.id; - SmartScriptHolder ev = SmartScriptHolder(); - ev.event = ne; - ev.event_id = e.action.timeEvent.id; - ev.target = e.target; - ev.action = ac; - InitTimer(ev); - mStoredEvents.push_back(ev); - break; - } + SmartScriptHolder ev = SmartScriptHolder(); + ev.event = ne; + ev.event_id = e.action.timeEvent.id; + ev.target = e.target; + ev.action = ac; + InitTimer(ev); + mStoredEvents.push_back(ev); + break; + } case SMART_ACTION_TRIGGER_TIMED_EVENT: ProcessEventsFor((SMART_EVENT)SMART_EVENT_TIMED_EVENT_TRIGGERED, nullptr, e.action.timeEvent.id); @@ -2074,38 +1743,33 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u mRemIDs.push_back(e.action.timeEvent.id); break; case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(target)) { - if (IsCreature(*itr)) - { - if (!meOrigGUID) - meOrigGUID = me ? me->GetGUID() : ObjectGuid::Empty; - if (!goOrigGUID) - goOrigGUID = go ? go->GetGUID() : ObjectGuid::Empty; - go = nullptr; - me = (*itr)->ToCreature(); - break; - } - else if (IsGameObject(*itr)) - { - if (!meOrigGUID) - meOrigGUID = me ? me->GetGUID() : ObjectGuid::Empty; - if (!goOrigGUID) - goOrigGUID = go ? go->GetGUID() : ObjectGuid::Empty; - go = (*itr)->ToGameObject(); - me = nullptr; - break; - } + if (!meOrigGUID) + meOrigGUID = me ? me->GetGUID() : ObjectGuid::Empty; + if (!goOrigGUID) + goOrigGUID = go ? go->GetGUID() : ObjectGuid::Empty; + go = nullptr; + me = target->ToCreature(); + break; + } + else if (IsGameObject(target)) + { + if (!meOrigGUID) + meOrigGUID = me ? me->GetGUID() : ObjectGuid::Empty; + if (!goOrigGUID) + goOrigGUID = go ? go->GetGUID() : ObjectGuid::Empty; + go = target->ToGameObject(); + me = nullptr; + break; } - - delete targets; - break; } + + break; + } case SMART_ACTION_RESET_SCRIPT_BASE_OBJECT: ResetBaseObject(); break; @@ -2113,1291 +1777,919 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u OnReset(); break; case SMART_ACTION_SET_RANGED_MOVEMENT: - { - if (!IsSmart()) - break; - - float attackDistance = float(e.action.setRangedMovement.distance); - float attackAngle = float(e.action.setRangedMovement.angle) / 180.0f * M_PI; - - ObjectList* targets = GetTargets(e, unit); - if (targets) - { - for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (Creature* target = (*itr)->ToCreature()) - if (IsSmart(target) && target->GetVictim()) - if (CAST_AI(SmartAI, target->AI())->CanCombatMove()) - target->GetMotionMaster()->MoveChase(target->GetVictim(), attackDistance, attackAngle); - - delete targets; - } + { + if (!IsSmart()) break; - } + + float attackDistance = float(e.action.setRangedMovement.distance); + float attackAngle = float(e.action.setRangedMovement.angle) / 180.0f * float(M_PI); + + for (WorldObject* target : targets) + if (Creature* creature = target->ToCreature()) + if (IsSmart(creature) && creature->GetVictim()) + if (CAST_AI(SmartAI, creature->AI())->CanCombatMove()) + creature->GetMotionMaster()->MoveChase(creature->GetVictim(), attackDistance, attackAngle); + + break; + } case SMART_ACTION_CALL_TIMED_ACTIONLIST: + { + if (e.GetTargetType() == SMART_TARGET_NONE) { - if (e.GetTargetType() == SMART_TARGET_NONE) - { - LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); - break; - } - - if (ObjectList* targets = GetTargets(e, unit)) - { - for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (Creature* target = (*itr)->ToCreature()) - { - if (IsSmart(target)) - CAST_AI(SmartAI, target->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); - } - else if (GameObject* goTarget = (*itr)->ToGameObject()) - { - if (IsSmartGO(goTarget)) - CAST_AI(SmartGameObjectAI, goTarget->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); - } - } - - delete targets; - } + LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); break; } + + for (WorldObject* target : targets) + { + if (Creature* creature = target->ToCreature()) + { + if (IsSmart(creature)) + CAST_AI(SmartAI, creature->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); + } + else if (GameObject* go = target->ToGameObject()) + { + if (IsSmartGO(go)) + CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); + } + } + break; + } case SMART_ACTION_SET_NPC_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToUnit()->ReplaceAllNpcFlags(NPCFlags(e.action.flag.flag)); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToUnit()->SetUInt32Value(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + break; + } case SMART_ACTION_ADD_NPC_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToUnit()->SetNpcFlag(NPCFlags(e.action.flag.flag)); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToUnit()->SetFlag(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + break; + } case SMART_ACTION_REMOVE_NPC_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToUnit()->RemoveNpcFlag(NPCFlags(e.action.flag.flag)); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToUnit()->RemoveFlag(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + break; + } case SMART_ACTION_CROSS_CAST: + { + if (targets.empty()) + break; + + ObjectVector casters; + GetTargets(casters, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0, 0), unit); + + for (WorldObject* caster : casters) { - ObjectList* casters = GetTargets(CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0, 0), unit); - if (!casters) - break; + if (!IsUnit(caster)) + continue; - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - delete casters; // casters already validated, delete now - break; - } + Unit* casterUnit = caster->ToUnit(); - for (ObjectList::const_iterator itr = casters->begin(); itr != casters->end(); ++itr) + bool interruptedSpell = false; + + for (WorldObject* target : targets) { - if (!IsUnit(*itr)) + if (!IsUnit(target)) continue; - bool interruptedSpell = false; - - for (ObjectList::const_iterator it = targets->begin(); it != targets->end(); ++it) + if (!(e.action.crossCast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.crossCast.spell)) { - if (!IsUnit(*it)) - continue; - - if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*it)->ToUnit()->HasAura(e.action.cast.spell)) + if (!interruptedSpell && e.action.crossCast.flags & SMARTCAST_INTERRUPT_PREVIOUS) { - if (!interruptedSpell && e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - { - (*itr)->ToUnit()->InterruptNonMeleeSpells(false); - interruptedSpell = true; - } - - (*itr)->ToUnit()->CastSpell((*it)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + casterUnit->InterruptNonMeleeSpells(false); + interruptedSpell = true; } - else - LOG_DEBUG("sql.sql", "Spell {} not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura", - e.action.cast.spell, (*it)->GetGUID().ToString()); + + casterUnit->CastSpell(target->ToUnit(), e.action.crossCast.spell, (e.action.crossCast.flags & SMARTCAST_TRIGGERED) != 0); } - } - - delete targets; - delete casters; - break; - } - case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: - { - uint32 actions[SMART_ACTION_PARAM_COUNT]; - actions[0] = e.action.randTimedActionList.entry1; - actions[1] = e.action.randTimedActionList.entry2; - actions[2] = e.action.randTimedActionList.entry3; - actions[3] = e.action.randTimedActionList.entry4; - actions[4] = e.action.randTimedActionList.entry5; - actions[5] = e.action.randTimedActionList.entry6; - uint32 temp[SMART_ACTION_PARAM_COUNT]; - uint32 count = 0; - for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT; i++) - { - if (actions[i] > 0) - { - temp[count] = actions[i]; - ++count; - } - } - - if (count == 0) - break; - - uint32 id = temp[urand(0, count - 1)]; - if (e.GetTargetType() == SMART_TARGET_NONE) - { - LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); - break; - } - - ObjectList* targets = GetTargets(e, unit); - if (targets) - { - for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (Creature* target = (*itr)->ToCreature()) - { - if (IsSmart(target)) - CAST_AI(SmartAI, target->AI())->SetScript9(e, id, GetLastInvoker()); - } - else if (GameObject* goTarget = (*itr)->ToGameObject()) - { - if (IsSmartGO(goTarget)) - CAST_AI(SmartGameObjectAI, goTarget->AI())->SetScript9(e, id, GetLastInvoker()); - } - } - - delete targets; - } - break; - } - case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: - { - uint32 id = urand(e.action.randRangeTimedActionList.idMin, e.action.randRangeTimedActionList.idMax); - if (e.GetTargetType() == SMART_TARGET_NONE) - { - LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); - break; - } - - ObjectList* targets = GetTargets(e, unit); - if (targets) - { - for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (Creature* target = (*itr)->ToCreature()) - { - if (IsSmart(target)) - CAST_AI(SmartAI, target->AI())->SetScript9(e, id, GetLastInvoker()); - } - else if (GameObject* goTarget = (*itr)->ToGameObject()) - { - if (IsSmartGO(goTarget)) - CAST_AI(SmartGameObjectAI, goTarget->AI())->SetScript9(e, id, GetLastInvoker()); - } - } - - delete targets; - } - break; - } - case SMART_ACTION_ACTIVATE_TAXI: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsPlayer(*itr)) - (*itr)->ToPlayer()->ActivateTaxiPathTo(e.action.taxi.id); - - delete targets; - break; - } - case SMART_ACTION_RANDOM_MOVE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - bool foundTarget = false; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsCreature((*itr))) - { - foundTarget = true; - - if (e.action.moveRandom.distance) - (*itr)->ToCreature()->GetMotionMaster()->MoveRandom((float)e.action.moveRandom.distance); - else - (*itr)->ToCreature()->GetMotionMaster()->MoveIdle(); - } - } - - if (!foundTarget && me && IsCreature(me)) - { - if (e.action.moveRandom.distance) - me->GetMotionMaster()->MoveRandom((float)e.action.moveRandom.distance); else - me->GetMotionMaster()->MoveIdle(); + LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target ({}) already has the aura", e.action.crossCast.spell, target->GetGUID().ToString()); } + } + break; + } + case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: + { + std::vector actionLists; + std::copy_if(e.action.randTimedActionList.actionLists.begin(), e.action.randTimedActionList.actionLists.end(), + std::back_inserter(actionLists), [](uint32 actionList) { return actionList != 0; }); - delete targets; + uint32 id = Acore::Containers::SelectRandomContainerElement(actionLists); + if (e.GetTargetType() == SMART_TARGET_NONE) + { + LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); break; } - case SMART_ACTION_SET_UNIT_FIELD_BYTES_1: + + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetByteFlag(UNIT_FIELD_BYTES_1, e.action.setunitByte.type, e.action.setunitByte.byte1); - - delete targets; - break; - } - case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->RemoveByteFlag(UNIT_FIELD_BYTES_1, e.action.delunitByte.type, e.action.delunitByte.byte1); - - delete targets; - break; - } - case SMART_ACTION_INTERRUPT_SPELL: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->InterruptNonMeleeSpells(e.action.interruptSpellCasting.withDelayed, e.action.interruptSpellCasting.spell_id, e.action.interruptSpellCasting.withInstant); - - delete targets; - break; - } - case SMART_ACTION_SEND_GO_CUSTOM_ANIM: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsGameObject(*itr)) - (*itr)->ToGameObject()->SendCustomAnim(e.action.sendGoCustomAnim.anim); - - delete targets; - break; - } - case SMART_ACTION_SET_DYNAMIC_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->ReplaceAllDynamicFlags(e.action.flag.flag); - - delete targets; - break; - } - case SMART_ACTION_ADD_DYNAMIC_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetDynamicFlag(e.action.flag.flag); - - delete targets; - break; - } - case SMART_ACTION_REMOVE_DYNAMIC_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->RemoveDynamicFlag(e.action.flag.flag); - - delete targets; - break; - } - case SMART_ACTION_JUMP_TO_POS: - { - if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT) + if (Creature* creature = target->ToCreature()) { - if (me) - { - float range = (float)e.target.randomPoint.range; - Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o }; - Position randomPoint = me->GetRandomPoint(srcPos, range); - me->GetMotionMaster()->MoveJump(randomPoint, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); - } - - break; + if (IsSmart(creature)) + CAST_AI(SmartAI, creature->AI())->SetScript9(e, id, GetLastInvoker()); } - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - // xinef: my implementation - if (e.action.jump.selfJump) + else if (GameObject* go = target->ToGameObject()) { - if (WorldObject* target = Acore::Containers::SelectRandomContainerElement(*targets)) - if (me) - me->GetMotionMaster()->MoveJump(target->GetPositionX() + e.target.x, target->GetPositionY() + e.target.y, target->GetPositionZ() + e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + if (IsSmartGO(go)) + CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, id, GetLastInvoker()); } + } + break; + } + case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: + { + uint32 id = urand(e.action.randTimedActionList.actionLists[0], e.action.randTimedActionList.actionLists[1]); + if (e.GetTargetType() == SMART_TARGET_NONE) + { + LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); + break; + } + + for (WorldObject* target : targets) + { + if (Creature* creature = target->ToCreature()) + { + if (IsSmart(creature)) + CAST_AI(SmartAI, creature->AI())->SetScript9(e, id, GetLastInvoker()); + } + else if (GameObject* go = target->ToGameObject()) + { + if (IsSmartGO(go)) + CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, id, GetLastInvoker()); + } + } + break; + } + case SMART_ACTION_ACTIVATE_TAXI: + { + for (WorldObject* target : targets) + if (IsPlayer(target)) + target->ToPlayer()->ActivateTaxiPathTo(e.action.taxi.id); + break; + } + case SMART_ACTION_RANDOM_MOVE: + { + bool foundTarget = false; + + for (WorldObject* target : targets) + { + if (IsCreature((target))) + { + foundTarget = true; + + if (e.action.moveRandom.distance) + target->ToCreature()->GetMotionMaster()->MoveRandom(float(e.action.moveRandom.distance)); + else + target->ToCreature()->GetMotionMaster()->MoveIdle(); + } + } + + if (!foundTarget && me && IsCreature(me)) + { + if (e.action.moveRandom.distance) + me->GetMotionMaster()->MoveRandom(float(e.action.moveRandom.distance)); else + me->GetMotionMaster()->MoveIdle(); + } + break; + } + case SMART_ACTION_SET_UNIT_FIELD_BYTES_1: + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetByteFlag(UNIT_FIELD_BYTES_1, e.action.setunitByte.type, e.action.setunitByte.byte1); + break; + } + case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1: + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->RemoveByteFlag(UNIT_FIELD_BYTES_1, e.action.delunitByte.type, e.action.delunitByte.byte1); + break; + } + case SMART_ACTION_INTERRUPT_SPELL: + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->InterruptNonMeleeSpells(e.action.interruptSpellCasting.withDelayed != 0, e.action.interruptSpellCasting.spell_id, e.action.interruptSpellCasting.withInstant != 0); + break; + } + case SMART_ACTION_SEND_GO_CUSTOM_ANIM: + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->SendCustomAnim(e.action.sendGoCustomAnim.anim); + break; + } + case SMART_ACTION_SET_DYNAMIC_FLAG: + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetUInt32Value(UNIT_DYNAMIC_FLAGS, e.action.unitFlag.flag); + break; + } + case SMART_ACTION_ADD_DYNAMIC_FLAG: + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetFlag(UNIT_DYNAMIC_FLAGS, e.action.unitFlag.flag); + break; + } + case SMART_ACTION_REMOVE_DYNAMIC_FLAG: + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->RemoveFlag(UNIT_DYNAMIC_FLAGS, e.action.unitFlag.flag); + break; + } + case SMART_ACTION_JUMP_TO_POS: + { + if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT) + { + if (me) { - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (WorldObject* obj = (*itr)) - { - if (Creature* creature = obj->ToCreature()) - creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); - } + float range = (float)e.target.randomPoint.range; + Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o }; + Position randomPoint = me->GetRandomPoint(srcPos, range); + me->GetMotionMaster()->MoveJump(randomPoint, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); } - delete targets; break; } + + if (targets.empty()) + break; + + // xinef: my implementation + if (e.action.jump.selfJump) + { + if (WorldObject* target = Acore::Containers::SelectRandomContainerElement(targets)) + if (me) + me->GetMotionMaster()->MoveJump(target->GetPositionX() + e.target.x, target->GetPositionY() + e.target.y, target->GetPositionZ() + e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + } + else + { + for (WorldObject* target : targets) + if (WorldObject* obj = (target)) + { + if (Creature* creature = obj->ToCreature()) + creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + } + } + + break; + } case SMART_ACTION_GO_SET_LOOT_STATE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsGameObject(*itr)) - (*itr)->ToGameObject()->SetLootState((LootState)e.action.setGoLootState.state); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->SetLootState((LootState)e.action.setGoLootState.state); + break; + } case SMART_ACTION_GO_SET_GO_STATE: - { - ObjectList* targets = GetTargets(e, unit); - - if (!targets) - { - break; - } - - for (auto const& target : *targets) - { - if (IsGameObject(target)) - { - target->ToGameObject()->SetGoState((GOState)e.action.goState.state); - } - } - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->SetGoState((GOState)e.action.goState.state); + break; + } case SMART_ACTION_SEND_TARGET_TO_TARGET: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + WorldObject* ref = GetBaseObject(); - ObjectList* storedTargets = GetTargetList(e.action.sendTargetToTarget.id); - if (!storedTargets) - { - delete targets; - break; - } + if (!ref) + ref = unit; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsCreature(*itr)) - { - if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI())) - ai->GetScript()->StoreTargetList(new ObjectList(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list - else - LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping"); - } - else if (IsGameObject(*itr)) - { - if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI())) - ai->GetScript()->StoreTargetList(new ObjectList(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list - else - LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping"); - } - } - - delete targets; + if (!ref) break; + + ObjectVector const* storedTargets = GetStoredTargetVector(e.action.sendTargetToTarget.id, *ref); + if (!storedTargets) + break; + + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI())) + ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list + else + LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping"); + } + else if (IsGameObject(target)) + { + if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI())) + ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list + else + LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping"); + } } + break; + } case SMART_ACTION_SEND_GOSSIP_MENU: - { - if (!GetBaseObject()) - break; - - LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {}, gossipNpcTextId {}", - e.action.sendGossipMenu.gossipMenuId, e.action.sendGossipMenu.gossipNpcTextId); - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (Player* player = (*itr)->ToPlayer()) - { - if (e.action.sendGossipMenu.gossipMenuId) - player->PrepareGossipMenu(GetBaseObject(), e.action.sendGossipMenu.gossipMenuId, true); - else - ClearGossipMenuFor(player); - - SendGossipMenuFor(player, e.action.sendGossipMenu.gossipNpcTextId, GetBaseObject()->GetGUID()); - } - - delete targets; + { + if (!GetBaseObject()) break; - } + + LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {}, gossipNpcTextId {}", + e.action.sendGossipMenu.gossipMenuId, e.action.sendGossipMenu.gossipNpcTextId); + + for (WorldObject* target : targets) + if (Player* player = target->ToPlayer()) + { + if (e.action.sendGossipMenu.gossipMenuId) + player->PrepareGossipMenu(GetBaseObject(), e.action.sendGossipMenu.gossipMenuId, true); + else + ClearGossipMenuFor(player); + + SendGossipMenuFor(player, e.action.sendGossipMenu.gossipNpcTextId, GetBaseObject()->GetGUID()); + } + + break; + } case SMART_ACTION_SET_HOME_POS: + { + if (!targets.empty()) { - ObjectList* targets = GetTargets(e, unit); - if (targets) + float x, y, z, o; + for (WorldObject* target : targets) + if (IsCreature(target)) + { + if (e.action.setHomePos.spawnPos) + { + target->ToCreature()->GetRespawnPosition(x, y, z, &o); + target->ToCreature()->SetHomePosition(x, y, z, o); + } + else + target->ToCreature()->SetHomePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); + } + } + else if (me && e.GetTargetType() == SMART_TARGET_POSITION) + { + if (e.action.setHomePos.spawnPos) { float x, y, z, o; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - { - if (e.action.setHomePos.spawnPos) - { - (*itr)->ToCreature()->GetRespawnPosition(x, y, z, &o); - (*itr)->ToCreature()->SetHomePosition(x, y, z, o); - } - else - (*itr)->ToCreature()->SetHomePosition((*itr)->GetPositionX(), (*itr)->GetPositionY(), (*itr)->GetPositionZ(), (*itr)->GetOrientation()); - } - delete targets; + me->GetRespawnPosition(x, y, z, &o); + me->SetHomePosition(x, y, z, o); } - else if (me && e.GetTargetType() == SMART_TARGET_POSITION) - { - if (e.action.setHomePos.spawnPos) - { - float x, y, z, o; - me->GetRespawnPosition(x, y, z, &o); - me->SetHomePosition(x, y, z, o); - } - else - me->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); - } - break; + else + me->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); } - /*{ - ObjectList* movers = GetTargets(CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.sethome.targetType, e.action.sethome.targetParam1, e.action.sethome.targetParam2, e.action.sethome.targetParam3, 0), unit); - if (!movers) - break; - - if (e.GetTargetType() == SMART_TARGET_POSITION) - { - for (ObjectList::const_iterator itr = movers->begin(); itr != movers->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); + break; } - else if (ObjectList* targets = GetTargets(e, unit)) - { - if (WorldObject* target = targets->front()) - for (ObjectList::const_iterator itr = movers->begin(); itr != movers->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->SetHomePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); - - delete targets; - } - - delete movers; - break; - }*/ case SMART_ACTION_SET_HEALTH_REGEN: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToCreature()->SetRegeneratingHealth(e.action.setHealthRegen.regenHealth); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->SetRegeneratingHealth(e.action.setHealthRegen.regenHealth); - - delete targets; - break; - } + break; + } case SMART_ACTION_SET_ROOT: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->SetControlled(e.action.setRoot.root, UNIT_STATE_ROOT); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToCreature()->SetControlled(e.action.setRoot.root != 0, UNIT_STATE_ROOT); + break; + } case SMART_ACTION_SET_GO_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsGameObject(*itr)) - (*itr)->ToGameObject()->ReplaceAllGameObjectFlags((GameObjectFlags)e.action.goFlag.flag); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->SetUInt32Value(GAMEOBJECT_FLAGS, e.action.goFlag.flag); + break; + } case SMART_ACTION_ADD_GO_FLAG: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsGameObject(*itr)) - (*itr)->ToGameObject()->SetGameObjectFlag((GameObjectFlags)e.action.goFlag.flag); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->SetFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag); + break; + } case SMART_ACTION_REMOVE_GO_FLAG: + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->RemoveFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag); + break; + } + case SMART_ACTION_SUMMON_CREATURE_GROUP: + { + std::list summonList; + GetBaseObject()->SummonCreatureGroup(e.action.creatureGroup.group, &summonList); + + for (std::list::const_iterator itr = summonList.begin(); itr != summonList.end(); ++itr) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsGameObject(*itr)) - (*itr)->ToGameObject()->RemoveGameObjectFlag((GameObjectFlags)e.action.goFlag.flag); - - delete targets; - break; + if (unit && e.action.creatureGroup.attackInvoker) + (*itr)->AI()->AttackStart(unit); + else if (me && e.action.creatureGroup.attackScriptOwner) + (*itr)->AI()->AttackStart(me); } - case SMART_ACTION_SUMMON_CREATURE_GROUP: - { - std::list summonList; - GetBaseObject()->SummonCreatureGroup(e.action.creatureGroup.group, &summonList); - for (std::list::const_iterator itr = summonList.begin(); itr != summonList.end(); ++itr) - { - if (unit && e.action.creatureGroup.attackInvoker) - (*itr)->AI()->AttackStart(unit); - else if (me && e.action.creatureGroup.attackScriptOwner) - (*itr)->AI()->AttackStart(me); - } - - break; - } + break; + } case SMART_ACTION_SET_POWER: - { - ObjectList* targets = GetTargets(e, unit); - - if (targets) - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetPower(Powers(e.action.power.powerType), e.action.power.newPower); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetPower(Powers(e.action.power.powerType), e.action.power.newPower); + break; + } case SMART_ACTION_ADD_POWER: - { - ObjectList* targets = GetTargets(e, unit); - - if (targets) - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetPower(Powers(e.action.power.powerType), (*itr)->ToUnit()->GetPower(Powers(e.action.power.powerType)) + e.action.power.newPower); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetPower(Powers(e.action.power.powerType), target->ToUnit()->GetPower(Powers(e.action.power.powerType)) + e.action.power.newPower); + break; + } case SMART_ACTION_REMOVE_POWER: - { - ObjectList* targets = GetTargets(e, unit); - - if (targets) - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetPower(Powers(e.action.power.powerType), (*itr)->ToUnit()->GetPower(Powers(e.action.power.powerType)) - e.action.power.newPower); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetPower(Powers(e.action.power.powerType), target->ToUnit()->GetPower(Powers(e.action.power.powerType)) - e.action.power.newPower); + break; + } case SMART_ACTION_GAME_EVENT_STOP: + { + uint32 eventId = e.action.gameEventStop.id; + if (!sGameEventMgr->IsActiveEvent(eventId)) { - uint32 eventId = e.action.gameEventStop.id; - if (!sGameEventMgr->IsActiveEvent(eventId)) - { - LOG_ERROR("scripts.ai.sai", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_STOP, inactive event (id: {})", eventId); - break; - } - sGameEventMgr->StopEvent(eventId, true); + LOG_ERROR("scripts.ai.sai", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_STOP, inactive event (id: {})", eventId); break; } + sGameEventMgr->StopEvent(eventId, true); + break; + } case SMART_ACTION_GAME_EVENT_START: + { + uint32 eventId = e.action.gameEventStart.id; + if (sGameEventMgr->IsActiveEvent(eventId)) { - uint32 eventId = e.action.gameEventStart.id; - if (sGameEventMgr->IsActiveEvent(eventId)) - { - LOG_ERROR("scripts.ai.sai", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_START, already activated event (id: {})", eventId); - break; - } - sGameEventMgr->StartEvent(eventId, true); + LOG_ERROR("scripts.ai.sai", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_START, already activated event (id: {})", eventId); break; } + sGameEventMgr->StartEvent(eventId, true); + break; + } case SMART_ACTION_START_CLOSEST_WAYPOINT: + { + std::vector waypoints; + std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), + std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; }); + + float distanceToClosest = std::numeric_limits::max(); + WayPoint* closestWp = nullptr; + + for (WorldObject* target : targets) { - uint32 waypoints[SMART_ACTION_PARAM_COUNT]; - waypoints[0] = e.action.closestWaypointFromList.wp1; - waypoints[1] = e.action.closestWaypointFromList.wp2; - waypoints[2] = e.action.closestWaypointFromList.wp3; - waypoints[3] = e.action.closestWaypointFromList.wp4; - waypoints[4] = e.action.closestWaypointFromList.wp5; - waypoints[5] = e.action.closestWaypointFromList.wp6; - float distanceToClosest = std::numeric_limits::max(); - WayPoint* closestWp = nullptr; - - ObjectList* targets = GetTargets(e, unit); - if (targets) + if (Creature* creature = target->ToCreature()) { - for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsSmart(creature)) { - if (Creature* target = (*itr)->ToCreature()) + for (uint32 wp : waypoints) { - if (IsSmart(target)) + WPPath* path = sSmartWaypointMgr->GetPath(wp); + if (!path || path->empty()) + continue; + + auto itrWp = path->find(0); + if (itrWp != path->end()) { - for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT; i++) + if (WayPoint* wp = itrWp->second) { - if (!waypoints[i]) - continue; - - WPPath* path = sSmartWaypointMgr->GetPath(waypoints[i]); - - if (!path || path->empty()) - continue; - - WPPath::const_iterator itrWp = path->find(0); - - if (itrWp != path->end()) + float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z); + if (distToThisPath < distanceToClosest) { - if (WayPoint* wp = itrWp->second) - { - float distToThisPath = target->GetDistance(wp->x, wp->y, wp->z); - - if (distToThisPath < distanceToClosest) - { - distanceToClosest = distToThisPath; - closestWp = wp; - } - } + distanceToClosest = distToThisPath; + closestWp = wp; } } - - if (closestWp) - CAST_AI(SmartAI, target->AI())->StartPath(false, closestWp->id, true); } } - } - delete targets; + if (closestWp) + CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true); + } } - break; } + break; + } case SMART_ACTION_SET_GO_STATE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsGameObject(target)) + target->ToGameObject()->SetGoState((GOState)e.action.goState.state); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsGameObject(*itr)) - (*itr)->ToGameObject()->SetGoState((GOState)e.action.goState.state); - - delete targets; - break; - } + break; + } case SMART_ACTION_EXIT_VEHICLE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->ExitVehicle(); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->ExitVehicle(); - - delete targets; - break; - } + break; + } case SMART_ACTION_SET_UNIT_MOVEMENT_FLAGS: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsUnit(target)) + { + target->ToUnit()->SetUnitMovementFlags(e.action.movementFlag.flag); + target->ToUnit()->SendMovementFlagUpdate(); + } - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - { - (*itr)->ToUnit()->SetUnitMovementFlags(e.action.movementFlag.flag); - (*itr)->ToUnit()->SendMovementFlagUpdate(); - } - - delete targets; - break; - } + break; + } case SMART_ACTION_SET_COMBAT_DISTANCE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToCreature()->m_CombatDistance = e.action.combatDistance.dist; - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->m_CombatDistance = e.action.combatDistance.dist; - - delete targets; - break; - } + break; + } case SMART_ACTION_SET_CASTER_COMBAT_DIST: - { - if (e.action.casterDistance.reset) - RestoreCasterMaxDist(); - else - SetCasterActualDist(e.action.casterDistance.dist); + { + if (e.action.casterDistance.reset) + RestoreCasterMaxDist(); + else + SetCasterActualDist(e.action.casterDistance.dist); - if (me->GetVictim() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - me->GetMotionMaster()->MoveChase(me->GetVictim(), GetCasterActualDist()); - break; - } + if (me->GetVictim() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) + me->GetMotionMaster()->MoveChase(me->GetVictim(), GetCasterActualDist()); + break; + } case SMART_ACTION_SET_SIGHT_DIST: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->m_SightDistance = e.action.sightDistance.dist; - - delete targets; - break; - } + { + for (WorldObject* const target : targets) + if (IsCreature(target)) + target->ToCreature()->m_SightDistance = e.action.sightDistance.dist; + break; + } case SMART_ACTION_FLEE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->GetMotionMaster()->MoveFleeing(me, e.action.flee.withEmote); - - delete targets; - break; - } + { + for (WorldObject* const target : targets) + if (IsCreature(target)) + target->ToCreature()->GetMotionMaster()->MoveFleeing(me, e.action.flee.withEmote); + break; + } case SMART_ACTION_ADD_THREAT: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - me->AddThreat((*itr)->ToUnit(), (float)e.action.threat.threatINC - (float)e.action.threat.threatDEC); - - delete targets; - break; - } + { + for (WorldObject* const target : targets) + if (IsUnit(target)) + me->AddThreat(target->ToUnit(), float(e.action.threatPCT.threatINC) - float(e.action.threatPCT.threatDEC)); + break; + } case SMART_ACTION_LOAD_EQUIPMENT: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsCreature(*itr)) - (*itr)->ToCreature()->LoadEquipment(e.action.loadEquipment.id, e.action.loadEquipment.force); - - delete targets; - break; - } + { + for (WorldObject* const target : targets) + if (IsCreature(target)) + target->ToCreature()->LoadEquipment(e.action.loadEquipment.id, e.action.loadEquipment.force != 0); + break; + } case SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT: - { - uint32 eventId = urand(e.action.randomTimedEvent.minId, e.action.randomTimedEvent.maxId); - ProcessEventsFor((SMART_EVENT)SMART_EVENT_TIMED_EVENT_TRIGGERED, nullptr, eventId); - break; - } + { + uint32 eventId = urand(e.action.randomTimedEvent.minId, e.action.randomTimedEvent.maxId); + ProcessEventsFor((SMART_EVENT)SMART_EVENT_TIMED_EVENT_TRIGGERED, nullptr, eventId); + break; + } case SMART_ACTION_SET_HOVER: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->SetHover(e.action.setHover.state); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->SetHover(e.action.setHover.state); + break; + } case SMART_ACTION_ADD_IMMUNITY: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->ApplySpellImmune(e.action.immunity.id, e.action.immunity.type, e.action.immunity.value, true); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->ApplySpellImmune(e.action.immunity.id, e.action.immunity.type, e.action.immunity.value, true); - - delete targets; - break; - } + break; + } case SMART_ACTION_REMOVE_IMMUNITY: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->ApplySpellImmune(e.action.immunity.id, e.action.immunity.type, e.action.immunity.value, false); - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->ApplySpellImmune(e.action.immunity.id, e.action.immunity.type, e.action.immunity.value, false); + break; + } case SMART_ACTION_FALL: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->GetMotionMaster()->MoveFall(); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->GetMotionMaster()->MoveFall(); - - delete targets; - break; - } + break; + } case SMART_ACTION_SET_EVENT_FLAG_RESET: - { - SetPhaseReset(e.action.setActive.state); - break; - } + { + SetPhaseReset(e.action.setActive.state); + break; + } case SMART_ACTION_REMOVE_ALL_GAMEOBJECTS: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->RemoveAllGameObjects(); - - delete targets; - break; - } + { + for (WorldObject* const target : targets) + if (IsUnit(target)) + target->ToUnit()->RemoveAllGameObjects(); + break; + } case SMART_ACTION_STOP_MOTION: + { + for (WorldObject* const target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - { - if (e.action.stopMotion.stopMovement) - (*itr)->ToUnit()->StopMoving(); - if (e.action.stopMotion.movementExpired) - (*itr)->ToUnit()->GetMotionMaster()->MovementExpired(); - } - - delete targets; - break; + if (IsUnit(target)) + { + if (e.action.stopMotion.stopMovement) + target->ToUnit()->StopMoving(); + if (e.action.stopMotion.movementExpired) + target->ToUnit()->GetMotionMaster()->MovementExpired(); + } } + break; + } case SMART_ACTION_NO_ENVIRONMENT_UPDATE: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToUnit()->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - (*itr)->ToUnit()->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); - - delete targets; - break; - } + break; + } case SMART_ACTION_ZONE_UNDER_ATTACK: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsUnit(*itr)) - if (Player* player = (*itr)->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself()) - { - me->SendZoneUnderAttackMessage(player); - break; - } - - delete targets; - break; - } - case SMART_ACTION_LOAD_GRID: - { - if (me && me->FindMap()) - me->FindMap()->LoadGrid(e.target.x, e.target.y); - break; - } - case SMART_ACTION_PLAYER_TALK: - { - ObjectList* targets = GetTargets(e, unit); - char const* text = sObjectMgr->GetAcoreString(e.action.playerTalk.textId, DEFAULT_LOCALE); - - if (targets) - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - if (IsPlayer(*itr)) - !e.action.playerTalk.flag ? (*itr)->ToPlayer()->Say(text, LANG_UNIVERSAL) : (*itr)->ToPlayer()->Yell(text, LANG_UNIVERSAL); - - delete targets; - break; - } - case SMART_ACTION_CUSTOM_CAST: - { - if (!me) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (IsUnit(*itr)) - { - if (e.action.castCustom.flags & SMARTCAST_INTERRUPT_PREVIOUS) - me->InterruptNonMeleeSpells(false); - - if (e.action.castCustom.flags & SMARTCAST_COMBAT_MOVE) - { - // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed - // unless target is outside spell range, out of mana, or LOS. - - bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.castCustom.spell); // AssertSpellInfo? - int32 mana = me->GetPower(POWER_MANA); - - if (me->GetDistance((*itr)->ToUnit()) > spellInfo->GetMaxRange(true) || - me->GetDistance((*itr)->ToUnit()) < spellInfo->GetMinRange(true) || - !me->IsWithinLOSInMap((*itr)->ToUnit()) || - mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) - _allowMove = true; - - CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); - } - - if (!(e.action.castCustom.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.castCustom.spell)) - { - CustomSpellValues values; - if (e.action.castCustom.bp1) - values.AddSpellMod(SPELLVALUE_BASE_POINT0, e.action.castCustom.bp1); - if (e.action.castCustom.bp2) - values.AddSpellMod(SPELLVALUE_BASE_POINT1, e.action.castCustom.bp2); - if (e.action.castCustom.bp3) - values.AddSpellMod(SPELLVALUE_BASE_POINT2, e.action.castCustom.bp3); - me->CastCustomSpell(e.action.castCustom.spell, values, (*itr)->ToUnit(), (e.action.castCustom.flags & SMARTCAST_TRIGGERED) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE); - } - } - } - delete targets; - break; - } - case SMART_ACTION_VORTEX_SUMMON: - { - if (!me) - break; - - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - TempSummonType summon_type = (e.action.summonVortex.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN; - - float a = static_cast(e.action.summonVortex.a); - float k = static_cast(e.action.summonVortex.k) / 1000.0f; - float r_max = static_cast(e.action.summonVortex.r_max); - float delta_phi = M_PI * static_cast(e.action.summonVortex.phi_delta) / 180.0f; - - // r(phi) = a * e ^ (k * phi) - // r(phi + delta_phi) = a * e ^ (k * (phi + delta_phi)) - // r(phi + delta_phi) = a * e ^ (k * phi) * e ^ (k * delta_phi) - // r(phi + delta_phi) = r(phi) * e ^ (k * delta_phi) - float factor = std::exp(k * delta_phi); - - // r(0) = a * e ^ (k * 0) = a * e ^ 0 = a * 1 = a - float summonRadius = a; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - // Offset by orientation, should not count into radius calculation, - // but is needed for vortex direction (polar coordinates) - float phi = (*itr)->GetOrientation(); - - do - { - Position summonPosition(**itr); - summonPosition.RelocatePolarOffset(phi, summonRadius); - - me->SummonCreature(e.action.summonVortex.summonEntry, summonPosition, summon_type, e.action.summonVortex.summonDuration); - - phi += delta_phi; - summonRadius *= factor; - } while (summonRadius <= r_max); - } - - delete targets; - break; - } - case SMART_ACTION_CONE_SUMMON: - { - if (!me) - break; - - TempSummonType spawnType = (e.action.coneSummon.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN; - - float distInARow = static_cast(e.action.coneSummon.distanceBetweenSummons); - float coneAngle = static_cast(e.action.coneSummon.coneAngle) * M_PI / 180.0f; - - for (uint32 radius = 0; radius <= e.action.coneSummon.coneLength; radius += e.action.coneSummon.distanceBetweenRings) - { - float deltaAngle = 0.0f; - if (radius > 0) - deltaAngle = distInARow / radius; - - uint32 count = 1; - if (deltaAngle > 0) - count += coneAngle / deltaAngle; - - float currentAngle = -static_cast(count) * deltaAngle / 2.0f; - - if (e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_NONE) - currentAngle += G3D::fuzzyGt(e.target.o, 0.0f) ? (e.target.o - me->GetOrientation()) : 0.0f; - else if (ObjectList* targets = GetTargets(e, unit)) - { - currentAngle += (me->GetAngle(targets->front()) - me->GetOrientation()); - delete targets; - } - - for (uint32 index = 0; index < count; ++index) - { - Position spawnPosition(*me); - spawnPosition.RelocatePolarOffset(currentAngle, radius); - currentAngle += deltaAngle; - - me->SummonCreature(e.action.coneSummon.summonEntry, spawnPosition, spawnType, e.action.coneSummon.summonDuration); - } - } - - break; - } - case SMART_ACTION_CU_ENCOUNTER_START: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - break; - - for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) - { - if (Player* playerTarget = (*itr)->ToPlayer()) - { - playerTarget->RemoveArenaSpellCooldowns(); - playerTarget->RemoveAurasDueToSpell(57724); // Spell Shaman Debuff - Sated (Heroism) - playerTarget->RemoveAurasDueToSpell(57723); // Spell Shaman Debuff - Exhaustion (Bloodlust) - playerTarget->RemoveAurasDueToSpell(2825); // Bloodlust - playerTarget->RemoveAurasDueToSpell(32182); // Heroism - } - } - - delete targets; - break; - } - case SMART_ACTION_DO_ACTION: - { - int32 const actionId = e.action.doAction.isNegative ? -e.action.doAction.actionId : e.action.doAction.actionId; - if (!e.action.doAction.instanceTarget) - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) + { + for (WorldObject* target : targets) + if (IsUnit(target)) + if (Player* player = target->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself()) { + me->SendZoneUnderAttackMessage(player); break; } - for (WorldObject* objTarget : *targets) + break; + } + case SMART_ACTION_LOAD_GRID: + { + if (me && me->FindMap()) + me->FindMap()->LoadGrid(e.target.x, e.target.y); + break; + } + case SMART_ACTION_PLAYER_TALK: + { + char const* text = sObjectMgr->GetAcoreString(e.action.playerTalk.textId, DEFAULT_LOCALE); + + if (!targets.empty()) + for (WorldObject* target : targets) + if (IsPlayer(target)) + !e.action.playerTalk.flag ? target->ToPlayer()->Say(text, LANG_UNIVERSAL) : target->ToPlayer()->Yell(text, LANG_UNIVERSAL); + + break; + } + case SMART_ACTION_CUSTOM_CAST: + { + if (!me) + break; + + for (WorldObject* target : targets) + { + if (IsUnit(target)) + { + if (e.action.castCustom.flags & SMARTCAST_INTERRUPT_PREVIOUS) + me->InterruptNonMeleeSpells(false); + + if (e.action.castCustom.flags & SMARTCAST_COMBAT_MOVE) { - if (Creature const* unitTarget = objTarget->ToCreature()) - { - if (unitTarget->IsAIEnabled) - { - unitTarget->AI()->DoAction(actionId); - } - } - else if (GameObject const* gobjTarget = objTarget->ToGameObject()) - { - gobjTarget->AI()->DoAction(actionId); - } + // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed + // unless target is outside spell range, out of mana, or LOS. + + bool _allowMove = false; + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.castCustom.spell); // AssertSpellInfo? + int32 mana = me->GetPower(POWER_MANA); + + if (me->GetDistance(target->ToUnit()) > spellInfo->GetMaxRange(true) || + me->GetDistance(target->ToUnit()) < spellInfo->GetMinRange(true) || + !me->IsWithinLOSInMap(target->ToUnit()) || + mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) + _allowMove = true; + + CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); } - delete targets; - } - else - { - InstanceScript* instanceScript = nullptr; - if (WorldObject* baseObj = GetBaseObject()) + if (!(e.action.castCustom.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.castCustom.spell)) { - instanceScript = baseObj->GetInstanceScript(); + CustomSpellValues values; + if (e.action.castCustom.bp1) + values.AddSpellMod(SPELLVALUE_BASE_POINT0, e.action.castCustom.bp1); + if (e.action.castCustom.bp2) + values.AddSpellMod(SPELLVALUE_BASE_POINT1, e.action.castCustom.bp2); + if (e.action.castCustom.bp3) + values.AddSpellMod(SPELLVALUE_BASE_POINT2, e.action.castCustom.bp3); + me->CastCustomSpell(e.action.castCustom.spell, values, target->ToUnit(), (e.action.castCustom.flags & SMARTCAST_TRIGGERED) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE); } + } + } + break; + } + case SMART_ACTION_VORTEX_SUMMON: + { + if (!me) + break; + + if (targets.empty()) + break; + + TempSummonType summon_type = (e.action.summonVortex.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN; + + float a = static_cast(e.action.summonVortex.a); + float k = static_cast(e.action.summonVortex.k) / 1000.0f; + float r_max = static_cast(e.action.summonVortex.r_max); + float delta_phi = M_PI * static_cast(e.action.summonVortex.phi_delta) / 180.0f; + + // r(phi) = a * e ^ (k * phi) + // r(phi + delta_phi) = a * e ^ (k * (phi + delta_phi)) + // r(phi + delta_phi) = a * e ^ (k * phi) * e ^ (k * delta_phi) + // r(phi + delta_phi) = r(phi) * e ^ (k * delta_phi) + float factor = std::exp(k * delta_phi); + + // r(0) = a * e ^ (k * 0) = a * e ^ 0 = a * 1 = a + float summonRadius = a; + + for (WorldObject* target : targets) + { + // Offset by orientation, should not count into radius calculation, + // but is needed for vortex direction (polar coordinates) + float phi = target->GetOrientation(); + + do + { + Position summonPosition(*target); + summonPosition.RelocatePolarOffset(phi, summonRadius); + + me->SummonCreature(e.action.summonVortex.summonEntry, summonPosition, summon_type, e.action.summonVortex.summonDuration); + + phi += delta_phi; + summonRadius *= factor; + } while (summonRadius <= r_max); + } + + break; + } + case SMART_ACTION_CONE_SUMMON: + { + if (!me) + break; + + TempSummonType spawnType = (e.action.coneSummon.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN; + + float distInARow = static_cast(e.action.coneSummon.distanceBetweenSummons); + float coneAngle = static_cast(e.action.coneSummon.coneAngle) * M_PI / 180.0f; + + for (uint32 radius = 0; radius <= e.action.coneSummon.coneLength; radius += e.action.coneSummon.distanceBetweenRings) + { + float deltaAngle = 0.0f; + if (radius > 0) + deltaAngle = distInARow / radius; + + uint32 count = 1; + if (deltaAngle > 0) + count += coneAngle / deltaAngle; + + float currentAngle = -static_cast(count) * deltaAngle / 2.0f; + + if (e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_NONE) + currentAngle += G3D::fuzzyGt(e.target.o, 0.0f) ? (e.target.o - me->GetOrientation()) : 0.0f; + else if (!targets.empty()) + { + currentAngle += (me->GetAngle(targets.front()) - me->GetOrientation()); + } + + for (uint32 index = 0; index < count; ++index) + { + Position spawnPosition(*me); + spawnPosition.RelocatePolarOffset(currentAngle, radius); + currentAngle += deltaAngle; + + me->SummonCreature(e.action.coneSummon.summonEntry, spawnPosition, spawnType, e.action.coneSummon.summonDuration); + } + } + + break; + } + case SMART_ACTION_CU_ENCOUNTER_START: + { + for (WorldObject* target : targets) + { + if (Player* playerTarget = target->ToPlayer()) + { + playerTarget->RemoveArenaSpellCooldowns(); + playerTarget->RemoveAurasDueToSpell(57724); // Spell Shaman Debuff - Sated (Heroism) + playerTarget->RemoveAurasDueToSpell(57723); // Spell Shaman Debuff - Exhaustion (Bloodlust) + playerTarget->RemoveAurasDueToSpell(2825); // Bloodlust + playerTarget->RemoveAurasDueToSpell(32182); // Heroism + } + } + + break; + } + case SMART_ACTION_DO_ACTION: + { + int32 const actionId = e.action.doAction.isNegative ? -e.action.doAction.actionId : e.action.doAction.actionId; + if (!e.action.doAction.instanceTarget) + { + if (targets.empty()) + break; + + for (WorldObject* objTarget : targets) + { + if (Creature const* unitTarget = objTarget->ToCreature()) + { + if (unitTarget->IsAIEnabled) + { + unitTarget->AI()->DoAction(actionId); + } + } + else if (GameObject const* gobjTarget = objTarget->ToGameObject()) + { + gobjTarget->AI()->DoAction(actionId); + } + } + + } + else + { + InstanceScript* instanceScript = nullptr; + if (WorldObject* baseObj = GetBaseObject()) + { + instanceScript = baseObj->GetInstanceScript(); + } // Action is triggered by AreaTrigger - else if (trigger && IsPlayer(unit)) - { - instanceScript = unit->GetInstanceScript(); - } - - if (instanceScript) - { - instanceScript->DoAction(actionId); - } + else if (trigger && IsPlayer(unit)) + { + instanceScript = unit->GetInstanceScript(); + } + + if (instanceScript) + { + instanceScript->DoAction(actionId); } - break; } + break; + } case SMART_ACTION_DISABLE_EVADE: - { - if (!IsSmart()) - break; - - CAST_AI(SmartAI, me->AI())->SetEvadeDisabled(e.action.disableEvade.disable != 0); + { + if (!IsSmart()) break; - } + + CAST_AI(SmartAI, me->AI())->SetEvadeDisabled(e.action.disableEvade.disable != 0); + break; + } case SMART_ACTION_SET_CORPSE_DELAY: + { + for (WorldObject* const target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - break; - } - - for (auto const& target : *targets) - { - if (IsCreature(target)) - { - target->ToCreature()->SetCorpseDelay(e.action.corpseDelay.timer); - } - } - - delete targets; - break; + if (IsCreature(target)) + target->ToCreature()->SetCorpseDelay(e.action.corpseDelay.timer); } + break; + } case SMART_ACTION_SET_HEALTH_PCT: - { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - break; - } - - for (auto const& target : *targets) - { - if (Unit* targetUnit = target->ToUnit()) - { - targetUnit->SetHealth(targetUnit->CountPctFromMaxHealth(e.action.setHealthPct.percent)); - } - } - - delete targets; - break; - } + { + for (WorldObject* target : targets) + if (Unit* targetUnit = target->ToUnit()) + targetUnit->SetHealth(targetUnit->CountPctFromMaxHealth(e.action.setHealthPct.percent)); + break; + } case SMART_ACTION_SET_MOVEMENT_SPEED: - { - uint32 speedInteger = e.action.movementSpeed.speedInteger; - uint32 speedFraction = e.action.movementSpeed.speedFraction; - float speed = float(speedInteger) + float(speedFraction) / std::pow(10, std::floor(std::log10(float(speedFraction ? speedFraction : 1)) + 1)); + { + uint32 speedInteger = e.action.movementSpeed.speedInteger; + uint32 speedFraction = e.action.movementSpeed.speedFraction; + float speed = float(speedInteger) + float(speedFraction) / std::pow(10, std::floor(std::log10(float(speedFraction ? speedFraction : 1)) + 1)); - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - break; - } + for (WorldObject* target : targets) + if (IsCreature(target)) + target->ToCreature()->SetSpeed(UnitMoveType(e.action.movementSpeed.movementType), speed); - for (auto const& target : *targets) - { - if (IsCreature(target)) - { - me->SetSpeed(UnitMoveType(e.action.movementSpeed.movementType), speed); - } - } - - delete targets; - break; - } + break; + } case SMART_ACTION_PLAY_CINEMATIC: + { + for (WorldObject* target : targets) { - ObjectList* targets = GetTargets(e, unit); - if (!targets) - { - break; - } + if (!IsPlayer(target)) + continue; - for (auto const& target : *targets) - { - if (!IsPlayer(target)) - continue; - - target->ToPlayer()->SendCinematicStart(e.action.cinematic.entry); - } - break; + target->ToPlayer()->SendCinematicStart(e.action.cinematic.entry); } + break; + } default: LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); break; @@ -3432,7 +2724,7 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e) { if (!GetBaseObject()) return; - if (mTemplate) + if (mTemplate != SMARTAI_TEMPLATE_BASIC) { LOG_ERROR("sql.sql", "SmartScript::InstallTemplate: Entry {} SourceType {} AI Template can not be set more then once, skipped.", e.entryOrGuid, e.GetScriptType()); return; @@ -3539,7 +2831,7 @@ SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flag return script; } -ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*= nullptr*/) +void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e, Unit* invoker /*= nullptr*/) const { Unit* scriptTrigger = nullptr; if (invoker) @@ -3549,16 +2841,16 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* WorldObject* baseObject = GetBaseObject(); - ObjectList* l = new ObjectList(); switch (e.GetTargetType()) { case SMART_TARGET_SELF: if (baseObject) - l->push_back(baseObject); + targets.push_back(baseObject); break; case SMART_TARGET_VICTIM: - if (me && me->GetVictim()) - l->push_back(me->GetVictim()); + if (me) + if (Unit* victim = me->GetVictim()) + targets.push_back(victim); break; case SMART_TARGET_HOSTILE_SECOND_AGGRO: if (me) @@ -3566,10 +2858,10 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (e.target.hostileRandom.powerType) { if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))) - l->push_back(u); + targets.push_back(u); } else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)) - l->push_back(u); + targets.push_back(u); } break; case SMART_TARGET_HOSTILE_LAST_AGGRO: @@ -3578,10 +2870,10 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (e.target.hostileRandom.powerType) { if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))) - l->push_back(u); + targets.push_back(u); } else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)) - l->push_back(u); + targets.push_back(u); } break; case SMART_TARGET_HOSTILE_RANDOM: @@ -3590,10 +2882,10 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (e.target.hostileRandom.powerType) { if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))) - l->push_back(u); + targets.push_back(u); } else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)) - l->push_back(u); + targets.push_back(u); } break; case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP: @@ -3602,26 +2894,26 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (e.target.hostileRandom.powerType) { if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))) - l->push_back(u); + targets.push_back(u); } else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)) - l->push_back(u); + targets.push_back(u); } break; case SMART_TARGET_FARTHEST: if (me) { if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos))) - l->push_back(u); + targets.push_back(u); } break; case SMART_TARGET_ACTION_INVOKER: if (scriptTrigger) - l->push_back(scriptTrigger); + targets.push_back(scriptTrigger); break; case SMART_TARGET_ACTION_INVOKER_VEHICLE: if (scriptTrigger && scriptTrigger->GetVehicle() && scriptTrigger->GetVehicle()->GetBase()) - l->push_back(scriptTrigger->GetVehicle()->GetBase()); + targets.push_back(scriptTrigger->GetVehicle()->GetBase()); break; case SMART_TARGET_INVOKER_PARTY: if (scriptTrigger) @@ -3633,394 +2925,428 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) if (Player* member = groupRef->GetSource()) if (member->IsInMap(player)) - l->push_back(member); + targets.push_back(member); } // We still add the player to the list if there is no group. If we do // this even if there is a group (thus the else-check), it will add the // same player to the list twice. We don't want that to happen. else - l->push_back(scriptTrigger); + targets.push_back(scriptTrigger); } } break; case SMART_TARGET_CREATURE_RANGE: + { + WorldObject* ref = baseObject; + if (!ref) + ref = scriptTrigger; + + if (!ref) { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist((float)e.target.unitRange.maxDist); - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - { - if (!IsCreature(*itr)) - continue; - - if (me && me->GetGUID() == (*itr)->GetGUID()) - continue; - - // check alive state - 1 alive, 2 dead, 0 both - if (uint32 state = e.target.unitRange.livingState) - { - if ((*itr)->ToCreature()->IsAlive() && state == 2) - continue; - if (!(*itr)->ToCreature()->IsAlive() && state == 1) - continue; - } - - if (((e.target.unitRange.creature && (*itr)->ToCreature()->GetEntry() == e.target.unitRange.creature) || !e.target.unitRange.creature) && baseObject->IsInRange(*itr, (float)e.target.unitRange.minDist, (float)e.target.unitRange.maxDist)) - l->push_back(*itr); - } - - delete units; + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CREATURE_RANGE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.unitRange.maxDist)); + + for (WorldObject* unit : units) + { + if (!IsCreature(unit)) + continue; + + if (me && me->GetGUID() == unit->GetGUID()) + continue; + + // check alive state - 1 alive, 2 dead, 0 both + if (uint32 state = e.target.unitRange.livingState) + { + if (unit->ToCreature()->IsAlive() && state == 2) + continue; + if (!unit->ToCreature()->IsAlive() && state == 1) + continue; + } + + if (((e.target.unitRange.creature && unit->ToCreature()->GetEntry() == e.target.unitRange.creature) || !e.target.unitRange.creature) && ref->IsInRange(unit, (float)e.target.unitRange.minDist, (float)e.target.unitRange.maxDist)) + targets.push_back(unit); + } + + break; + } case SMART_TARGET_CREATURE_DISTANCE: + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.unitDistance.dist)); + + for (WorldObject* unit : units) { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist((float)e.target.unitDistance.dist); - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) + if (!IsCreature(unit)) + continue; + + if (me && me->GetGUID() == unit->GetGUID()) + continue; + + // check alive state - 1 alive, 2 dead, 0 both + if (uint32 state = e.target.unitDistance.livingState) { - if (!IsCreature(*itr)) + if (unit->ToCreature()->IsAlive() && state == 2) continue; - - if (me && me->GetGUID() == (*itr)->GetGUID()) + if (!unit->ToCreature()->IsAlive() && state == 1) continue; - - // check alive state - 1 alive, 2 dead, 0 both - if (uint32 state = e.target.unitDistance.livingState) - { - if ((*itr)->ToCreature()->IsAlive() && state == 2) - continue; - if (!(*itr)->ToCreature()->IsAlive() && state == 1) - continue; - } - - if ((e.target.unitDistance.creature && (*itr)->ToCreature()->GetEntry() == e.target.unitDistance.creature) || !e.target.unitDistance.creature) - l->push_back(*itr); } - delete units; - break; + if ((e.target.unitDistance.creature && unit->ToCreature()->GetEntry() == e.target.unitDistance.creature) || !e.target.unitDistance.creature) + targets.push_back(unit); } + + break; + } case SMART_TARGET_GAMEOBJECT_DISTANCE: + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.goDistance.dist)); + + for (WorldObject* unit : units) { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist((float)e.target.goDistance.dist); - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - { - if (!IsGameObject(*itr)) - continue; + if (!IsGameObject(unit)) + continue; - if (go && go->GetGUID() == (*itr)->GetGUID()) - continue; + if (go && go->GetGUID() == unit->GetGUID()) + continue; - if ((e.target.goDistance.entry && (*itr)->ToGameObject()->GetEntry() == e.target.goDistance.entry) || !e.target.goDistance.entry) - l->push_back(*itr); - } - - delete units; - break; + if ((e.target.goDistance.entry && unit->ToGameObject()->GetEntry() == e.target.goDistance.entry) || !e.target.goDistance.entry) + targets.push_back(unit); } + + break; + } case SMART_TARGET_GAMEOBJECT_RANGE: + { + + WorldObject* ref = baseObject; + if (!ref) + ref = scriptTrigger; + + if (!ref) { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist((float)e.target.goRange.maxDist); - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - { - if (!IsGameObject(*itr)) - continue; - - if (go && go->GetGUID() == (*itr)->GetGUID()) - continue; - - if (((e.target.goRange.entry && IsGameObject(*itr) && (*itr)->ToGameObject()->GetEntry() == e.target.goRange.entry) || !e.target.goRange.entry) && baseObject->IsInRange((*itr), (float)e.target.goRange.minDist, (float)e.target.goRange.maxDist)) - l->push_back(*itr); - } - - delete units; + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_GAMEOBJECT_RANGE: Entry: {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.goRange.maxDist)); + + for (WorldObject* unit : units) + { + if (!IsGameObject(unit)) + continue; + + if (go && go->GetGUID() == unit->GetGUID()) + continue; + + if (((e.target.goRange.entry && IsGameObject(unit) && unit->ToGameObject()->GetEntry() == e.target.goRange.entry) || !e.target.goRange.entry) && ref->IsInRange((unit), (float)e.target.goRange.minDist, (float)e.target.goRange.maxDist)) + targets.push_back(unit); + } + + break; + } case SMART_TARGET_CREATURE_GUID: + { + if (!scriptTrigger && !baseObject) { - if (!scriptTrigger && !baseObject) - { - LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CREATURE_GUID can not be used without invoker"); - break; - } - - Creature* target = FindCreatureNear(scriptTrigger ? scriptTrigger : GetBaseObject(), e.target.unitGUID.dbGuid); - if (target && (!e.target.unitGUID.entry || target->GetEntry() == e.target.unitGUID.entry)) - l->push_back(target); + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CREATURE_GUID: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + Creature* target = FindCreatureNear(scriptTrigger ? scriptTrigger : GetBaseObject(), e.target.unitGUID.dbGuid); + if (target && (!e.target.unitGUID.entry || target->GetEntry() == e.target.unitGUID.entry)) + targets.push_back(target); + break; + } case SMART_TARGET_GAMEOBJECT_GUID: + { + if (!scriptTrigger && !GetBaseObject()) { - if (!scriptTrigger && !GetBaseObject()) - { - LOG_ERROR("scripts.ai.sai", "SMART_TARGET_GAMEOBJECT_GUID can not be used without invoker"); - break; - } - - GameObject* target = FindGameObjectNear(scriptTrigger ? scriptTrigger : GetBaseObject(), e.target.goGUID.dbGuid); - if (target && (!e.target.goGUID.entry || target->GetEntry() == e.target.goGUID.entry)) - l->push_back(target); + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_GAMEOBJECT_GUID: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + GameObject* target = FindGameObjectNear(scriptTrigger ? scriptTrigger : GetBaseObject(), e.target.goGUID.dbGuid); + if (target && (!e.target.goGUID.entry || target->GetEntry() == e.target.goGUID.entry)) + targets.push_back(target); + break; + } case SMART_TARGET_PLAYER_RANGE: - { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist((float)e.target.playerRange.maxDist); - if (!units->empty() && GetBaseObject()) - { - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (IsPlayer(*itr) && GetBaseObject()->IsInRange(*itr, (float)e.target.playerRange.minDist, (float)e.target.playerRange.maxDist) && (*itr)->ToPlayer()->IsAlive() && !(*itr)->ToPlayer()->IsGameMaster()) - l->push_back(*itr); + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.playerRange.maxDist)); - // If Orientation is also set and we didnt find targets, try it with all the range - if (l->empty() && e.target.o > 0) - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (IsPlayer(*itr) && baseObject->IsInRange(*itr, 0.0f, float(e.target.playerRange.maxDist)) && (*itr)->ToPlayer()->IsAlive() && !(*itr)->ToPlayer()->IsGameMaster()) - l->push_back(*itr); - - if (e.target.playerRange.maxCount > 0) - Acore::Containers::RandomResize(*l, e.target.playerRange.maxCount); - } - - delete units; - break; - } + if (!units.empty() && baseObject) + for (WorldObject* unit : units) + if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist))) + targets.push_back(unit); + break; + } case SMART_TARGET_PLAYER_DISTANCE: - { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist((float)e.target.playerDistance.dist); - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (IsPlayer(*itr)) - l->push_back(*itr); + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.playerDistance.dist)); - delete units; - break; - } + for (WorldObject* unit : units) + if (IsPlayer(unit)) + targets.push_back(unit); + break; + } case SMART_TARGET_STORED: - { - ObjectListMap::iterator itr = mTargetStorage->find(e.target.stored.id); - if (itr != mTargetStorage->end()) - { - ObjectList* objectList = itr->second->GetObjectList(); - l->assign(objectList->begin(), objectList->end()); - } + { + WorldObject* ref = baseObject; + if (!ref) + ref = scriptTrigger; - // xinef: return l, what if list is empty? will return empty list instead of null pointer + if (!ref) + { + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_STORED: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + if (ObjectVector const* stored = GetStoredTargetVector(e.target.stored.id, *ref)) + targets.assign(stored->begin(), stored->end()); + break; + } case SMART_TARGET_CLOSEST_CREATURE: + { + WorldObject* ref = baseObject; + + if (!ref) + ref = scriptTrigger; + + if (!ref) { - Creature* target = GetClosestCreatureWithEntry(GetBaseObject(), e.target.unitClosest.entry, (float)(e.target.unitClosest.dist ? e.target.unitClosest.dist : 100), !e.target.unitClosest.dead); - if (target) - l->push_back(target); + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CLOSEST_CREATURE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + Creature* target = GetClosestCreatureWithEntry(ref, e.target.unitClosest.entry, (float)(e.target.unitClosest.dist ? e.target.unitClosest.dist : 100), !e.target.unitClosest.dead); + if (target) + targets.push_back(target); + break; + } case SMART_TARGET_CLOSEST_GAMEOBJECT: + { + WorldObject* ref = baseObject; + + if (!ref) + ref = scriptTrigger; + + if (!ref) { - GameObject* target = GetClosestGameObjectWithEntry(GetBaseObject(), e.target.goClosest.entry, (float)(e.target.goClosest.dist ? e.target.goClosest.dist : 100), e.target.goClosest.onlySpawned); - if (target) - l->push_back(target); + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CLOSEST_GAMEOBJECT: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + GameObject* target = GetClosestGameObjectWithEntry(ref, e.target.goClosest.entry, (float)(e.target.goClosest.dist ? e.target.goClosest.dist : 100), e.target.goClosest.onlySpawned); + if (target) + targets.push_back(target); + break; + } case SMART_TARGET_CLOSEST_PLAYER: + { + WorldObject* ref = baseObject; + + if (!ref) + ref = scriptTrigger; + + if (!ref) { - if (WorldObject* obj = GetBaseObject()) - { - Player* target = obj->SelectNearestPlayer((float)e.target.playerDistance.dist); - if (target) - l->push_back(target); - } + LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CLOSEST_PLAYER: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); break; } + + if (Player* target = ref->SelectNearestPlayer((float)e.target.playerDistance.dist)) + targets.push_back(target); + break; + } case SMART_TARGET_OWNER_OR_SUMMONER: - /* - * Owners/Summoners should be WorldObjects. This allows to have other objects - * such as gameobjects to execute SmartScripts using this type of target. - * Otherwise, only Units like creatures can summon other creatures. - */ + /* + * Owners/Summoners should be WorldObjects. This allows to have other objects + * such as gameobjects to execute SmartScripts using this type of target. + * Otherwise, only Units like creatures can summon other creatures. + */ + { + if (me) { - if (me) + if (WorldObject* owner = ObjectAccessor::GetWorldObject(*me, me->GetCharmerOrOwnerGUID())) { - if (WorldObject* owner = ObjectAccessor::GetWorldObject(*me, me->GetCharmerOrOwnerGUID())) - { - l->push_back(owner); - } - else if (me->IsSummon() && me->ToTempSummon()->GetSummonerUnit()) - { - l->push_back(me->ToTempSummon()->GetSummonerUnit()); - } + targets.push_back(owner); } - else if (go) - { - if (WorldObject* owner = ObjectAccessor::GetWorldObject(*go, go->GetOwnerGUID())) - { - l->push_back(owner); - } - } - - // xinef: Get owner of owner - if (e.target.owner.useCharmerOrOwner && !l->empty()) - { - if (Unit* owner = l->front()->ToUnit()) - { - l->clear(); - - if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->GetCharmerOrOwnerGUID())) - { - l->push_back(base); - } - } - } - break; } + else if (go) + { + if (WorldObject* owner = ObjectAccessor::GetWorldObject(*go, go->GetOwnerGUID())) + { + targets.push_back(owner); + } + } + + // xinef: Get owner of owner + if (e.target.owner.useCharmerOrOwner && !targets.empty()) + { + if (Unit* owner = targets.front()->ToUnit()) + { + targets.clear(); + + if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->GetCharmerOrOwnerGUID())) + { + targets.push_back(base); + } + } + } + break; + } case SMART_TARGET_THREAT_LIST: + { + if (me) { - if (me) - { - ThreatContainer::StorageType threatList = me->GetThreatMgr().getThreatList(); - for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i) - if (Unit* temp = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid())) - // Xinef: added distance check - if (e.target.threatList.maxDist == 0 || me->IsWithinCombatRange(temp, (float)e.target.threatList.maxDist)) - l->push_back(temp); - } - break; + ThreatContainer::StorageType threatList = me->GetThreatMgr().getThreatList(); + for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i) + if (Unit* temp = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid())) + // Xinef: added distance check + if (e.target.threatList.maxDist == 0 || me->IsWithinCombatRange(temp, (float)e.target.threatList.maxDist)) + targets.push_back(temp); } + break; + } case SMART_TARGET_CLOSEST_ENEMY: - { - if (me) - if (Unit* target = me->SelectNearestTarget(e.target.closestAttackable.maxDist, e.target.closestAttackable.playerOnly)) - l->push_back(target); + { + if (me) + if (Unit* target = me->SelectNearestTarget(e.target.closestAttackable.maxDist, e.target.closestAttackable.playerOnly)) + targets.push_back(target); - break; - } + break; + } case SMART_TARGET_CLOSEST_FRIENDLY: - { - if (me) - if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist, e.target.closestFriendly.playerOnly)) - l->push_back(target); + { + if (me) + if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist, e.target.closestFriendly.playerOnly)) + targets.push_back(target); - break; - } + break; + } case SMART_TARGET_PLAYER_WITH_AURA: - { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist(e.target.z ? e.target.z : float(e.target.playerWithAura.distMax)); - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (IsPlayer(*itr) && (*itr)->ToPlayer()->IsAlive() && !(*itr)->ToPlayer()->IsGameMaster()) - if (GetBaseObject()->IsInRange(*itr, (float)e.target.playerWithAura.distMin, (float)e.target.playerWithAura.distMax)) - if (bool(e.target.playerWithAura.negation) != (*itr)->ToPlayer()->HasAura(e.target.playerWithAura.spellId)) - l->push_back(*itr); + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.playerDistance.dist)); - if (e.target.o > 0) - Acore::Containers::RandomResize(*l, e.target.o); + for (WorldObject* unit : units) + if (IsPlayer(unit) && unit->ToPlayer()->IsAlive() && !unit->ToPlayer()->IsGameMaster()) + if (GetBaseObject()->IsInRange(unit, (float)e.target.playerWithAura.distMin, (float)e.target.playerWithAura.distMax)) + if (bool(e.target.playerWithAura.negation) != unit->ToPlayer()->HasAura(e.target.playerWithAura.spellId)) + targets.push_back(unit); - delete units; - break; - } + if (e.target.o > 0) + Acore::Containers::RandomResize(targets, e.target.o); + + break; + } case SMART_TARGET_ROLE_SELECTION: - { - // will always return a valid pointer, even if empty list - ObjectList* units = GetWorldObjectsInDist(float(e.target.roleSelection.maxDist)); - // 1 = Tanks, 2 = Healer, 4 = Damage - uint32 roleMask = e.target.roleSelection.roleMask; - for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (Player* targetPlayer = (*itr)->ToPlayer()) - if (targetPlayer->IsAlive() && !targetPlayer->IsGameMaster()) + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.target.playerDistance.dist)); + // 1 = Tanks, 2 = Healer, 4 = Damage + uint32 roleMask = e.target.roleSelection.roleMask; + for (WorldObject* unit : units) + if (Player* targetPlayer = unit->ToPlayer()) + if (targetPlayer->IsAlive() && !targetPlayer->IsGameMaster()) + { + if (roleMask & SMART_TARGET_ROLE_FLAG_TANKS) { - if (roleMask & SMART_TARGET_ROLE_FLAG_TANKS) + if (targetPlayer->HasTankSpec()) { - if (targetPlayer->HasTankSpec()) - { - l->push_back(*itr); - continue; - } - } - if (roleMask & SMART_TARGET_ROLE_FLAG_HEALERS) - { - if (targetPlayer->HasHealSpec()) - { - l->push_back(*itr); - continue; - } - } - if (roleMask & SMART_TARGET_ROLE_FLAG_DAMAGERS) - { - if (targetPlayer->HasCasterSpec() || targetPlayer->HasMeleeSpec()) - { - l->push_back(*itr); - continue; - } + targets.push_back(unit); + continue; } } + if (roleMask & SMART_TARGET_ROLE_FLAG_HEALERS) + { + if (targetPlayer->HasHealSpec()) + { + targets.push_back(unit); + continue; + } + } + if (roleMask & SMART_TARGET_ROLE_FLAG_DAMAGERS) + { + if (targetPlayer->HasCasterSpec() || targetPlayer->HasMeleeSpec()) + { + targets.push_back(unit); + continue; + } + } + } - if (e.target.roleSelection.resize > 0) - Acore::Containers::RandomResize(*l, e.target.roleSelection.resize); + if (e.target.roleSelection.resize > 0) + Acore::Containers::RandomResize(targets, e.target.roleSelection.resize); - delete units; - break; - } + break; + } case SMART_TARGET_VEHICLE_PASSENGER: + { + if (me && me->IsVehicle()) { - if (me && me->IsVehicle()) + if (Unit* target = me->GetVehicleKit()->GetPassenger(e.target.vehicle.seatMask)) { - if (Unit* target = me->GetVehicleKit()->GetPassenger(e.target.vehicle.seatMask)) - { - l->push_back(target); - } + targets.push_back(target); } - break; } + break; + } case SMART_TARGET_LOOT_RECIPIENTS: + { + if (me) { - if (me) + if (Group* lootGroup = me->GetLootRecipientGroup()) { - if (Group* lootGroup = me->GetLootRecipientGroup()) + for (GroupReference* it = lootGroup->GetFirstMember(); it != nullptr; it = it->next()) { - for (GroupReference* it = lootGroup->GetFirstMember(); it != nullptr; it = it->next()) + if (Player* recipient = it->GetSource()) { - if (Player* recipient = it->GetSource()) - { - l->push_back(recipient); - } - } - } - else - { - if (Player* recipient = me->GetLootRecipient()) - { - l->push_back(recipient); + targets.push_back(recipient); } } } + else + { + if (Player* recipient = me->GetLootRecipient()) + { + targets.push_back(recipient); + } + } } + } case SMART_TARGET_NONE: case SMART_TARGET_POSITION: default: break; } - - if (l->empty()) - { - delete l; - l = nullptr; - } - - return l; } -ObjectList* SmartScript::GetWorldObjectsInDist(float dist) +void SmartScript::GetWorldObjectsInDist(ObjectVector& targets, float dist) const { - ObjectList* targets = new ObjectList(); WorldObject* obj = GetBaseObject(); - if (obj) - { - Acore::AllWorldObjectsInRange u_check(obj, dist); - Acore::WorldObjectListSearcher searcher(obj, *targets, u_check); - Cell::VisitAllObjects(obj, searcher, dist); - } - return targets; + if (!obj) + return; + + Acore::AllWorldObjectsInRange u_check(obj, dist); + Acore::WorldObjectListSearcher searcher(obj, targets, u_check); + Cell::VisitAllObjects(obj, searcher, dist); } void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, uint32 var1, bool bvar, SpellInfo const* spell, GameObject* gob) @@ -4142,26 +3468,26 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!me || !me->IsEngaged()) return; - std::list pList; - DoFindFriendlyCC(pList, (float)e.event.friendlyCC.radius); - if (pList.empty()) + std::vector creatures; + DoFindFriendlyCC(creatures, float(e.event.friendlyCC.radius)); + if (creatures.empty()) { // Xinef: if there are at least two same npcs, they will perform the same action immediately even if this is useless... RecalcTimer(e, 1000, 3000); return; } - ProcessTimedAction(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax, Acore::Containers::SelectRandomContainerElement(pList)); + ProcessTimedAction(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax, Acore::Containers::SelectRandomContainerElement(creatures)); break; } case SMART_EVENT_FRIENDLY_MISSING_BUFF: { - std::list pList; - DoFindFriendlyMissingBuff(pList, (float)e.event.missingBuff.radius, e.event.missingBuff.spell); + std::vector creatures; + DoFindFriendlyMissingBuff(creatures, float(e.event.missingBuff.radius), e.event.missingBuff.spell); - if (pList.empty()) + if (creatures.empty()) return; - ProcessTimedAction(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax, Acore::Containers::SelectRandomContainerElement(pList)); + ProcessTimedAction(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax, Acore::Containers::SelectRandomContainerElement(creatures)); break; } case SMART_EVENT_HAS_AURA: @@ -4510,7 +3836,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!me || !me->IsEngaged()) return; - Unit* target = nullptr; + ObjectVector targets; switch (e.GetTargetType()) { case SMART_TARGET_CREATURE_RANGE: @@ -4521,10 +3847,9 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui case SMART_TARGET_PLAYER_RANGE: case SMART_TARGET_PLAYER_DISTANCE: { - ObjectList* targets = GetTargets(e); - if (!targets) + if (targets.empty()) return; - for (WorldObject* target : *targets) + for (WorldObject* target : targets) { if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat()) { @@ -4539,21 +3864,20 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui } } - delete targets; break; } case SMART_TARGET_SELF: case SMART_TARGET_ACTION_INVOKER: - target = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct); + DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct); break; default: return; } - if (!target) + if (targets.empty()) return; - ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax, target); + ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax); break; } case SMART_EVENT_DISTANCE_CREATURE: @@ -4625,33 +3949,37 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessTimedAction(e, e.event.counter.cooldownMin, e.event.counter.cooldownMax); break; case SMART_EVENT_NEAR_PLAYERS: - { - float range = (float)e.event.nearPlayer.radius; - ObjectList* units = GetWorldObjectsInDist(range); - if (!units->empty()) - { - units->remove_if([](WorldObject * unit) { return unit->GetTypeId() != TYPEID_PLAYER; }); + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.event.nearPlayer.radius)); - if (units->size() >= e.event.nearPlayer.minCount) - ProcessAction(e, unit); - } - RecalcTimer(e, e.event.nearPlayer.checkTimer, e.event.nearPlayer.checkTimer); - break; + if (!units.empty()) + { + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return; + + if (units.size() >= e.event.nearPlayer.minCount) + ProcessAction(e, unit); } + RecalcTimer(e, e.event.nearPlayer.checkTimer, e.event.nearPlayer.checkTimer); + break; + } case SMART_EVENT_NEAR_PLAYERS_NEGATION: - { - float range = (float)e.event.nearPlayerNegation.radius; - ObjectList* units = GetWorldObjectsInDist(range); - if (!units->empty()) - { - units->remove_if([](WorldObject * unit) { return unit->GetTypeId() != TYPEID_PLAYER; }); + { + ObjectVector units; + GetWorldObjectsInDist(units, static_cast(e.event.nearPlayerNegation.radius)); - if (units->size() < e.event.nearPlayerNegation.minCount) - ProcessAction(e, unit); - } - RecalcTimer(e, e.event.nearPlayerNegation.checkTimer, e.event.nearPlayerNegation.checkTimer); - break; + if (!units.empty()) + { + if (!unit || unit->GetTypeId() != TYPEID_PLAYER) + return; + + if (units.size() < e.event.nearPlayerNegation.minCount) + ProcessAction(e, unit); } + RecalcTimer(e, e.event.nearPlayerNegation.checkTimer, e.event.nearPlayerNegation.checkTimer); + break; + } default: LOG_ERROR("sql.sql", "SmartScript::ProcessEvent: Unhandled Event type {}", e.GetEventType()); break; @@ -5030,7 +4358,7 @@ uint32 SmartScript::DoChat(int8 id, ObjectGuid whisperGuid) }*/ // SmartScript end -Unit* SmartScript::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) +Unit* SmartScript::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) const { if (!me) return nullptr; @@ -5057,27 +4385,27 @@ Unit* SmartScript::DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, return unit; } -void SmartScript::DoFindFriendlyCC(std::list& _list, float range) +void SmartScript::DoFindFriendlyCC(std::vector& creatures, float range) const { if (!me) return; Acore::FriendlyCCedInRange u_check(me, range); - Acore::CreatureListSearcher searcher(me, _list, u_check); + Acore::CreatureListSearcher searcher(me, creatures, u_check); Cell::VisitGridObjects(me, searcher, range); } -void SmartScript::DoFindFriendlyMissingBuff(std::list& list, float range, uint32 spellid) +void SmartScript::DoFindFriendlyMissingBuff(std::vector& creatures, float range, uint32 spellid) const { if (!me) return; Acore::FriendlyMissingBuffInRange u_check(me, range, spellid); - Acore::CreatureListSearcher searcher(me, list, u_check); + Acore::CreatureListSearcher searcher(me, creatures, u_check); Cell::VisitGridObjects(me, searcher, range); } -Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) +Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) const { if (!me) return nullptr; @@ -5124,7 +4452,7 @@ void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry) } } -Unit* SmartScript::GetLastInvoker(Unit* invoker) +Unit* SmartScript::GetLastInvoker(Unit* invoker) const { // Xinef: Look for invoker only on map of base object... Prevents multithreaded crashes if (GetBaseObject()) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index cd564b72b..92142ec35 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -39,19 +39,19 @@ public: void ProcessEventsFor(SMART_EVENT e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr); void ProcessEvent(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr); bool CheckTimer(SmartScriptHolder const& e) const; - void RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max); + static void RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max); void UpdateTimer(SmartScriptHolder& e, uint32 const diff); - void InitTimer(SmartScriptHolder& e); + static void InitTimer(SmartScriptHolder& e); void ProcessAction(SmartScriptHolder& e, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr); void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = nullptr, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, SpellInfo const* spell = nullptr, GameObject* gob = nullptr); - ObjectList* GetTargets(SmartScriptHolder const& e, Unit* invoker = nullptr); - ObjectList* GetWorldObjectsInDist(float dist); + void GetTargets(ObjectVector& targets, SmartScriptHolder const& e, Unit* invoker = nullptr) const; + void GetWorldObjectsInDist(ObjectVector& objects, float dist) const; void InstallTemplate(SmartScriptHolder const& e); - SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); + static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); void SetPathId(uint32 id) { mPathId = id; } uint32 GetPathId() const { return mPathId; } - WorldObject* GetBaseObject() + WorldObject* GetBaseObject() const { WorldObject* obj = nullptr; if (me) @@ -70,27 +70,17 @@ public: void OnUpdate(const uint32 diff); void OnMoveInLineOfSight(Unit* who); - Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff); + Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) const; Unit* DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, uint32 maxHpPct) const; - void DoFindFriendlyCC(std::list& _list, float range); - void DoFindFriendlyMissingBuff(std::list& list, float range, uint32 spellid); - Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly); + void DoFindFriendlyCC(std::vector& creatures, float range) const; + void DoFindFriendlyMissingBuff(std::vector& creatures, float range, uint32 spellid) const; + Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly) const; - void StoreTargetList(ObjectList* targets, uint32 id) + void StoreTargetList(ObjectVector const& targets, uint32 id) { - if (!targets) - return; - - if (mTargetStorage->find(id) != mTargetStorage->end()) - { - // check if already stored - if ((*mTargetStorage)[id]->Equals(targets)) - return; - - delete (*mTargetStorage)[id]; - } - - (*mTargetStorage)[id] = new ObjectGuidList(targets, GetBaseObject()); + // insert or replace + _storedTargets.erase(id); + _storedTargets.emplace(id, ObjectGuidVector(targets)); } bool IsSmart(Creature* c = nullptr) @@ -122,11 +112,11 @@ public: return smart; } - ObjectList* GetTargetList(uint32 id) + ObjectVector const* GetStoredTargetVector(uint32 id, WorldObject const& ref) const { - ObjectListMap::iterator itr = mTargetStorage->find(id); - if (itr != mTargetStorage->end()) - return (*itr).second->GetObjectList(); + auto itr = _storedTargets.find(id); + if (itr != _storedTargets.end()) + return itr->second.GetObjectVector(ref); return nullptr; } @@ -187,8 +177,6 @@ public: return creatureItr != bounds.second ? creatureItr->second : bounds.first->second; } - ObjectListMap* mTargetStorage; - void OnReset(); void ResetBaseObject() { @@ -223,7 +211,7 @@ public: //TIMED_ACTIONLIST (script type 9 aka script9) void SetScript9(SmartScriptHolder& e, uint32 entry); - Unit* GetLastInvoker(Unit* invoker = nullptr); + Unit* GetLastInvoker(Unit* invoker = nullptr) const; ObjectGuid mLastInvoker; typedef std::unordered_map CounterMap; CounterMap mCounterList; @@ -284,6 +272,8 @@ private: // Xinef: misc bool _allowPhaseReset; + ObjectVectorMap _storedTargets; + SMARTAI_TEMPLATE mTemplate; void InstallEvents(); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 82292262d..92c24beaa 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -679,7 +679,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_SEND_GOSSIP_MENU: return sizeof(SmartAction::sendGossipMenu); case SMART_ACTION_GO_SET_LOOT_STATE: return sizeof(SmartAction::setGoLootState); case SMART_ACTION_SEND_TARGET_TO_TARGET: return sizeof(SmartAction::sendTargetToTarget); - case SMART_ACTION_SET_HOME_POS: return NO_PARAMS; + case SMART_ACTION_SET_HOME_POS: return sizeof(SmartAction::setHomePos); case SMART_ACTION_SET_HEALTH_REGEN: return sizeof(SmartAction::setHealthRegen); case SMART_ACTION_SET_ROOT: return sizeof(SmartAction::setRoot); case SMART_ACTION_SET_GO_FLAG: return sizeof(SmartAction::goFlag); @@ -1358,24 +1358,39 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) break; } case SMART_ACTION_RANDOM_EMOTE: - if (e.action.randomEmote.emote1 && !IsEmoteValid(e, e.action.randomEmote.emote1)) - return false; + { + if (std::all_of(e.action.randomEmote.emotes.begin(), e.action.randomEmote.emotes.end(), [](uint32 emote) { return emote == 0; })) + { + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero emote", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; + } - if (e.action.randomEmote.emote2 && !IsEmoteValid(e, e.action.randomEmote.emote2)) - return false; - - if (e.action.randomEmote.emote3 && !IsEmoteValid(e, e.action.randomEmote.emote3)) - return false; - - if (e.action.randomEmote.emote4 && !IsEmoteValid(e, e.action.randomEmote.emote4)) - return false; - - if (e.action.randomEmote.emote5 && !IsEmoteValid(e, e.action.randomEmote.emote5)) - return false; - - if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6)) - return false; - break; + for (uint32 emote : e.action.randomEmote.emotes) + if (emote && !IsEmoteValid(e, emote)) + return false; + break; + } + case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: + { + if (std::all_of(e.action.randTimedActionList.actionLists.begin(), e.action.randTimedActionList.actionLists.end(), [](uint32 actionList) { return actionList == 0; })) + { + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero action list", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; + } + break; + } + case SMART_ACTION_START_CLOSEST_WAYPOINT: + { + if (std::all_of(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), [](uint32 wp) { return wp == 0; })) + { + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; + } + break; + } case SMART_ACTION_CAST: case SMART_ACTION_INVOKER_CAST: if (!IsSpellValid(e, e.action.cast.spell)) @@ -1434,36 +1449,29 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) break; case SMART_ACTION_RANDOM_PHASE: { - if (e.action.randomPhase.phase1 >= SMART_EVENT_PHASE_MAX || - e.action.randomPhase.phase2 >= SMART_EVENT_PHASE_MAX || - e.action.randomPhase.phase3 >= SMART_EVENT_PHASE_MAX || - e.action.randomPhase.phase4 >= SMART_EVENT_PHASE_MAX || - e.action.randomPhase.phase5 >= SMART_EVENT_PHASE_MAX || - e.action.randomPhase.phase6 >= SMART_EVENT_PHASE_MAX) - { - LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); - return false; - } - if (e.action.randomPhase.phase1 == 0 && - e.action.randomPhase.phase2 == 0 && - e.action.randomPhase.phase3 == 0 && - e.action.randomPhase.phase4 == 0 && - e.action.randomPhase.phase5 == 0 && - e.action.randomPhase.phase6 == 0) + if (std::all_of(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(), [](uint32 phase) { return phase == 0; })) + { + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero phase", + e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; + } + + if (std::any_of(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(), [](uint32 phase) { return phase >= SMART_EVENT_PHASE_MAX; })) { LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } + break; } - break; case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax { if (e.action.randomPhaseRange.phaseMin >= SMART_EVENT_PHASE_MAX || - e.action.randomPhaseRange.phaseMax >= SMART_EVENT_PHASE_MAX) + e.action.randomPhaseRange.phaseMax >= SMART_EVENT_PHASE_MAX) { LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } + if (!IsMinMaxValid(e, e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax)) return false; break; @@ -1570,7 +1578,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: { - if (!IsMinMaxValid(e, e.action.randRangeTimedActionList.idMin, e.action.randRangeTimedActionList.idMax)) + if (!IsMinMaxValid(e, e.action.randTimedActionList.actionLists[0], e.action.randTimedActionList.actionLists[1])) return false; break; } @@ -1625,12 +1633,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) { if (e.GetScriptType() == SMART_SCRIPT_TYPE_CREATURE) { - int8 equipId = (int8)e.action.equip.entry; - - if (equipId) + if (int8 equipId = static_cast(e.action.equip.entry)) { - EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId); - if (!einfo) + EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId); + if (!eInfo) { LOG_ERROR("scripts.ai.sai", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}, skipped.", equipId, e.entryOrGuid); return false; @@ -1783,7 +1789,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_MOVE_TO_POS: case SMART_ACTION_EVADE: case SMART_ACTION_SET_ACTIVE: - case SMART_ACTION_START_CLOSEST_WAYPOINT: case SMART_ACTION_FOLLOW: case SMART_ACTION_SET_ORIENTATION: case SMART_ACTION_STORE_TARGET_LIST: @@ -1818,7 +1823,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SET_NPC_FLAG: case SMART_ACTION_ADD_NPC_FLAG: case SMART_ACTION_REMOVE_NPC_FLAG: - case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: case SMART_ACTION_RANDOM_MOVE: case SMART_ACTION_SET_UNIT_FIELD_BYTES_1: case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index c8f3f2609..5bb07ec3e 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -49,6 +49,16 @@ struct WayPoint uint32 delay; }; +enum eSmartAI +{ + SMART_EVENT_PARAM_COUNT = 4, + SMART_ACTION_PARAM_COUNT = 6, + SMART_SUMMON_COUNTER = 0xFFFFFF, + SMART_ESCORT_LAST_OOC_POINT = 0xFFFFFF, + SMART_RANDOM_POINT = 0xFFFFFE, + SMART_ESCORT_TARGETS = 0xFFFFFF +}; + enum SMART_EVENT_PHASE { SMART_EVENT_PHASE_ALWAYS = 0, @@ -758,12 +768,7 @@ struct SmartAction struct { - uint32 emote1; - uint32 emote2; - uint32 emote3; - uint32 emote4; - uint32 emote5; - uint32 emote6; + std::array emotes; } randomEmote; struct @@ -858,12 +863,7 @@ struct SmartAction struct { - uint32 phase1; - uint32 phase2; - uint32 phase3; - uint32 phase4; - uint32 phase5; - uint32 phase6; + std::array phases; } randomPhase; struct @@ -1049,9 +1049,7 @@ struct SmartAction { uint32 entry; uint32 mask; - uint32 slot1; - uint32 slot2; - uint32 slot3; + std::array slots; } equip; struct @@ -1086,12 +1084,7 @@ struct SmartAction struct { - uint32 entry1; - uint32 entry2; - uint32 entry3; - uint32 entry4; - uint32 entry5; - uint32 entry6; + std::array actionLists; } randTimedActionList; struct @@ -1209,12 +1202,7 @@ struct SmartAction struct { - uint32 wp1; - uint32 wp2; - uint32 wp3; - uint32 wp4; - uint32 wp5; - uint32 wp6; + std::array wps; } closestWaypointFromList; struct @@ -1584,16 +1572,6 @@ enum SmartTargetRoleFlags SMART_TARGET_ROLE_FLAG_DAMAGERS = 0x004 }; -enum eSmartAI -{ - SMART_EVENT_PARAM_COUNT = 4, - SMART_ACTION_PARAM_COUNT = 6, - SMART_SUMMON_COUNTER = 0xFFFFFF, - SMART_ESCORT_LAST_OOC_POINT = 0xFFFFFF, - SMART_RANDOM_POINT = 0xFFFFFE, - SMART_ESCORT_TARGETS = 0xFFFFFF -}; - enum SmartScriptType { SMART_SCRIPT_TYPE_CREATURE = 0, //done @@ -1802,60 +1780,42 @@ public: typedef std::unordered_map WPPath; -typedef std::list ObjectList; +typedef std::vector ObjectVector; -class ObjectGuidList +class ObjectGuidVector { - ObjectList* m_objectList; - GuidList* m_guidList; - WorldObject* m_baseObject; - public: - ObjectGuidList(ObjectList* objectList, WorldObject* baseObject) + explicit ObjectGuidVector(ObjectVector const& objectVector) : _objectVector(objectVector) { - ASSERT(objectList); - m_objectList = objectList; - m_baseObject = baseObject; - m_guidList = new GuidList(); - - for (ObjectList::iterator itr = objectList->begin(); itr != objectList->end(); ++itr) - { - m_guidList->push_back((*itr)->GetGUID()); - } + _guidVector.reserve(_objectVector.size()); + for (WorldObject* obj : _objectVector) + _guidVector.push_back(obj->GetGUID()); } - ObjectList* GetObjectList() + ObjectVector const* GetObjectVector(WorldObject const& ref) const { - if (m_baseObject) - { - //sanitize list using m_guidList - m_objectList->clear(); - - for (GuidList::iterator itr = m_guidList->begin(); itr != m_guidList->end(); ++itr) - { - if (WorldObject* obj = ObjectAccessor::GetWorldObject(*m_baseObject, *itr)) - m_objectList->push_back(obj); - //else - // LOG_DEBUG("scripts.ai", "SmartScript::mTargetStorage stores a guid to an invalid object: {}", (*itr).ToString()); - } - } - - return m_objectList; + UpdateObjects(ref); + return &_objectVector; } - bool Equals(ObjectList* objectList) - { - return m_objectList == objectList; - } + ~ObjectGuidVector() { } - ~ObjectGuidList() +private: + mutable ObjectVector _objectVector; + + GuidVector _guidVector; + + //sanitize vector using _guidVector + void UpdateObjects(WorldObject const& ref) const { - delete m_objectList; - delete m_guidList; + _objectVector.clear(); + + for (ObjectGuid const& guid : _guidVector) + if (WorldObject* obj = ObjectAccessor::GetWorldObject(ref, guid)) + _objectVector.push_back(obj); } }; - -typedef std::unordered_map ObjectListMap; +typedef std::unordered_map ObjectVectorMap; class SmartWaypointMgr { diff --git a/src/server/game/Combat/ThreatMgr.cpp b/src/server/game/Combat/ThreatMgr.cpp index 87af1c4d4..7cbbcd94d 100644 --- a/src/server/game/Combat/ThreatMgr.cpp +++ b/src/server/game/Combat/ThreatMgr.cpp @@ -261,12 +261,18 @@ HostileReference* ThreatContainer::getReferenceByTarget(Unit* victim) const if (!victim) return nullptr; - ObjectGuid const guid = victim->GetGUID(); + return getReferenceByTarget(victim->GetGUID()); +} + +HostileReference* ThreatContainer::getReferenceByTarget(ObjectGuid const& guid) const +{ for (ThreatContainer::StorageType::const_iterator i = iThreatList.begin(); i != iThreatList.end(); ++i) { HostileReference* ref = (*i); if (ref && ref->getUnitGuid() == guid) + { return ref; + } } return nullptr; diff --git a/src/server/game/Combat/ThreatMgr.h b/src/server/game/Combat/ThreatMgr.h index 5f87b094c..6844b08d1 100644 --- a/src/server/game/Combat/ThreatMgr.h +++ b/src/server/game/Combat/ThreatMgr.h @@ -164,6 +164,7 @@ public: } HostileReference* getReferenceByTarget(Unit* victim) const; + HostileReference* getReferenceByTarget(ObjectGuid const& guid) const; [[nodiscard]] StorageType const& getThreatList() const { return iThreatList; } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index d48dc275b..f777f860e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -219,8 +219,8 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), - m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false), - m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0), + m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false), + m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0), _isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false) { m_regenTimer = CREATURE_REGEN_INTERVAL; @@ -628,207 +628,238 @@ void Creature::Update(uint32 diff) LOG_ERROR("entities.unit", "Creature ({}) in wrong state: JUST_DEAD (1)", GetGUID().ToString()); break; case DEAD: + { + time_t now = GameTime::GetGameTime().count(); + if (m_respawnTime <= now) { - time_t now = GameTime::GetGameTime().count(); - if (m_respawnTime <= now) + + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_RESPAWN, GetEntry()); + + if (!sConditionMgr->IsObjectMeetToConditions(this, conditions)) { - - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_RESPAWN, GetEntry()); - - if (!sConditionMgr->IsObjectMeetToConditions(this, conditions)) - { - // Creature should not respawn, reset respawn timer. Conditions will be checked again the next time it tries to respawn. - m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay; - break; - } - - bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning - if (!allowed) // Will be rechecked on next Update call - break; - - ObjectGuid dbtableHighGuid = ObjectGuid::Create(GetEntry(), m_spawnId); - time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid); - if (!linkedRespawntime) // Can respawn - Respawn(); - else // the master is dead - { - ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid); - if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day) - SetRespawnTime(DAY); - else - m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little - SaveRespawnTime(); // also save to DB immediately - } + // Creature should not respawn, reset respawn timer. Conditions will be checked again the next time it tries to respawn. + m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay; + break; + } + + bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning + if (!allowed) // Will be rechecked on next Update call + break; + + ObjectGuid dbtableHighGuid = ObjectGuid::Create(GetEntry(), m_spawnId); + time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid); + if (!linkedRespawntime) // Can respawn + Respawn(); + else // the master is dead + { + ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid); + if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day) + SetRespawnTime(DAY); + else + m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little + SaveRespawnTime(); // also save to DB immediately } - break; } + break; + } case CORPSE: - { - Unit::Update(diff); - // deathstate changed on spells update, prevent problems - if (m_deathState != CORPSE) - break; - - if (m_groupLootTimer && lootingGroupLowGUID) - { - if (m_groupLootTimer <= diff) - { - Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID); - if (group) - group->EndRoll(&loot, GetMap()); - m_groupLootTimer = 0; - lootingGroupLowGUID = 0; - } - else - { - m_groupLootTimer -= diff; - } - } - else if (m_corpseRemoveTime <= GameTime::GetGameTime().count()) - { - RemoveCorpse(false); - LOG_DEBUG("entities.unit", "Removing corpse... {} ", GetUInt32Value(OBJECT_FIELD_ENTRY)); - } + { + Unit::Update(diff); + // deathstate changed on spells update, prevent problems + if (m_deathState != CORPSE) break; - } - case ALIVE: + + if (m_groupLootTimer && lootingGroupLowGUID) { - Unit::Update(diff); - - // creature can be dead after Unit::Update call - // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) - if (!IsAlive()) - break; - - // if creature is charmed, switch to charmed AI - if (NeedChangeAI) + if (m_groupLootTimer <= diff) { - UpdateCharmAI(); - NeedChangeAI = false; - IsAIEnabled = true; + Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID); + if (group) + group->EndRoll(&loot, GetMap()); + m_groupLootTimer = 0; + lootingGroupLowGUID = 0; + } + else + { + m_groupLootTimer -= diff; + } + } + else if (m_corpseRemoveTime <= GameTime::GetGameTime().count()) + { + RemoveCorpse(false); + LOG_DEBUG("entities.unit", "Removing corpse... {} ", GetUInt32Value(OBJECT_FIELD_ENTRY)); + } + break; + } + case ALIVE: + { + Unit::Update(diff); - // xinef: update combat state, if npc is not in combat - return to spawn correctly by calling EnterEvadeMode - SelectVictim(); + // creature can be dead after Unit::Update call + // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) + if (!IsAlive()) + break; + + // if creature is charmed, switch to charmed AI + if (NeedChangeAI) + { + UpdateCharmAI(); + NeedChangeAI = false; + IsAIEnabled = true; + + // xinef: update combat state, if npc is not in combat - return to spawn correctly by calling EnterEvadeMode + SelectVictim(); + } + + // periodic check to see if the creature has passed an evade boundary + if (IsAIEnabled && !IsInEvadeMode() && IsEngaged()) + { + if (diff >= m_boundaryCheckTime) + { + AI()->CheckInRoom(); + m_boundaryCheckTime = 2500; + } + else + m_boundaryCheckTime -= diff; + } + + Unit* owner = GetCharmerOrOwner(); + if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false)) + { + RemoveCharmAuras(); + } + + if (Unit* victim = GetVictim()) + { + // If we are closer than 50% of the combat reach we are going to reposition the victim + if (diff >= m_moveBackwardsMovementTime) + { + float MaxRange = GetCollisionRadius() + GetVictim()->GetCollisionRadius(); + + if (IsInDist(victim, MaxRange)) + AI()->MoveBackwardsChecks(); + + m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3); + } + else + { + m_moveBackwardsMovementTime -= diff; } - // periodic check to see if the creature has passed an evade boundary - if (IsAIEnabled && !IsInEvadeMode() && IsEngaged()) + // Circling the target + if (diff >= m_moveCircleMovementTime) { - if (diff >= m_boundaryCheckTime) - { - AI()->CheckInRoom(); - m_boundaryCheckTime = 2500; - } else - m_boundaryCheckTime -= diff; + AI()->MoveCircleChecks(); + m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2); } - - Unit* owner = GetCharmerOrOwner(); - if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false)) + else { - RemoveCharmAuras(); + m_moveCircleMovementTime -= diff; } + } - if (Unit *victim = GetVictim()) + // Call for assistance if not disabled + if (m_assistanceTimer) + { + if (m_assistanceTimer <= diff) { - // If we are closer than 50% of the combat reach we are going to reposition the victim - if (diff >= m_moveBackwardsMovementTime) + if (CanPeriodicallyCallForAssistance()) { - float MaxRange = GetCollisionRadius() + GetVictim()->GetCollisionRadius(); - - if (IsInDist(victim, MaxRange)) - AI()->MoveBackwardsChecks(); - - m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3); - } - else - { - m_moveBackwardsMovementTime -= diff; - } - - // Circling the target - if (diff >= m_moveCircleMovementTime) - { - AI()->MoveCircleChecks(); - m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2); - } - else - { - m_moveCircleMovementTime -= diff; + SetNoCallAssistance(false); + CallAssistance(); } + m_assistanceTimer = sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD); } - - // Call for assistance if not disabled - if (m_assistanceTimer) + else { - if (m_assistanceTimer <= diff) + m_assistanceTimer -= diff; + } + } + + if (!IsInEvadeMode() && IsAIEnabled) + { + // do not allow the AI to be changed during update + m_AI_locked = true; + i_AI->UpdateAI(diff); + m_AI_locked = false; + } + + // creature can be dead after UpdateAI call + // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) + if (!IsAlive()) + break; + + m_regenTimer -= diff; + if (m_regenTimer <= 0) + { + if (!IsInEvadeMode()) + { + // regenerate health if not in combat or if polymorphed) + if (!IsInCombat() || IsPolymorphed()) + RegenerateHealth(); + else if (IsNotReachableAndNeedRegen()) { - if (CanPeriodicallyCallForAssistance()) + // regenerate health if cannot reach the target and the setting is set to do so. + // this allows to disable the health regen of raid bosses if pathfinding has issues for whatever reason + if (sWorld->getBoolConfig(CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID) || !GetMap()->IsRaid()) { - SetNoCallAssistance(false); - CallAssistance(); - } - m_assistanceTimer = sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD); - } - else - { - m_assistanceTimer -= diff; - } - } - - if (!IsInEvadeMode() && IsAIEnabled) - { - // do not allow the AI to be changed during update - m_AI_locked = true; - i_AI->UpdateAI(diff); - m_AI_locked = false; - } - - // creature can be dead after UpdateAI call - // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly) - if (!IsAlive()) - break; - - m_regenTimer -= diff; - if (m_regenTimer <= 0) - { - if (!IsInEvadeMode()) - { - // regenerate health if not in combat or if polymorphed) - if (!IsInCombat() || IsPolymorphed()) RegenerateHealth(); - else if (IsNotReachableAndNeedRegen()) + LOG_DEBUG("entities.unit", "RegenerateHealth() enabled because Creature cannot reach the target. Detail: {}", GetDebugInfo()); + } + else + LOG_DEBUG("entities.unit", "RegenerateHealth() disabled even if the Creature cannot reach the target. Detail: {}", GetDebugInfo()); + } + } + + if (getPowerType() == POWER_ENERGY) + Regenerate(POWER_ENERGY); + else + Regenerate(POWER_MANA); + + m_regenTimer += CREATURE_REGEN_INTERVAL; + } + + if (CanNotReachTarget() && !IsInEvadeMode()) + { + m_cannotReachTimer += diff; + if (m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_EVADE_IF_NOT_REACHABLE) * IN_MILLISECONDS)) + { + Player* cannotReachPlayer = ObjectAccessor::GetPlayer(*this, m_cannotReachTarget); + if (cannotReachPlayer && IsEngagedBy(cannotReachPlayer) && IsAIEnabled && AI()->OnTeleportUnreacheablePlayer(cannotReachPlayer)) + { + SetCannotReachTarget(); + } + else if (!GetMap()->IsRaid()) + { + auto EnterEvade = [&]() { - // regenerate health if cannot reach the target and the setting is set to do so. - // this allows to disable the health regen of raid bosses if pathfinding has issues for whatever reason - if (sWorld->getBoolConfig(CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID) || !GetMap()->IsRaid()) + if (CreatureAI* ai = AI()) { - RegenerateHealth(); - LOG_DEBUG("entities.unit", "RegenerateHealth() enabled because Creature cannot reach the target. Detail: {}", GetDebugInfo()); + ai->EnterEvadeMode(CreatureAI::EvadeReason::EVADE_REASON_NO_PATH); + } + }; + + if (GetThreatMgr().getThreatList().size() <= 1) + { + EnterEvade(); + } + else + { + if (HostileReference* ref = GetThreatMgr().getOnlineContainer().getReferenceByTarget(m_cannotReachTarget)) + { + ref->removeReference(); + SetCannotReachTarget(); } else - LOG_DEBUG("entities.unit", "RegenerateHealth() disabled even if the Creature cannot reach the target. Detail: {}", GetDebugInfo()); + { + EnterEvade(); + } } } - - if (getPowerType() == POWER_ENERGY) - Regenerate(POWER_ENERGY); - else - Regenerate(POWER_MANA); - - m_regenTimer += CREATURE_REGEN_INTERVAL; } - - if (CanNotReachTarget() && !IsInEvadeMode() && !GetMap()->IsRaid()) - { - m_cannotReachTimer += diff; - if (IsNotReachable() && IsAIEnabled) - { - AI()->EnterEvadeMode(); - } - } - - break; } + break; + } default: break; } @@ -883,6 +914,11 @@ void Creature::Regenerate(Powers power) if (!HasUnitFlag2(UNIT_FLAG2_REGENERATE_POWER) && !GetOwnerGUID().IsPlayer()) return; + if (!m_regenPower) + { + return; + } + if (curValue >= maxValue) return; @@ -1020,7 +1056,7 @@ bool Creature::AIM_Initialize(CreatureAI* ai) // Xinef: called in add to world //Motion_Initialize(); - i_AI = ai ? ai : FactorySelector::selectAI(this); + i_AI = ai ? ai : FactorySelector::SelectAI(this); delete oldAI; IsAIEnabled = true; i_AI->InitializeAI(); @@ -1927,7 +1963,7 @@ void Creature::setDeathState(DeathState s, bool despawn) SetFullHealth(); SetLootRecipient(nullptr); ResetPlayerDamageReq(); - SetCannotReachTarget(false); + SetCannotReachTarget(); CreatureTemplate const* cinfo = GetCreatureTemplate(); // Xinef: npc run by default //SetWalk(true); @@ -2861,7 +2897,7 @@ uint8 Creature::getLevelForTarget(WorldObject const* target) const return uint8(level); } -std::string Creature::GetAIName() const +std::string const& Creature::GetAIName() const { return sObjectMgr->GetCreatureTemplate(GetEntry())->AIName; } @@ -3468,7 +3504,24 @@ bool Creature::SetCannotReachTarget(bool cannotReach, bool isChase /*= true*/) m_cannotReachTimer = 0; if (cannotReach) + { LOG_DEBUG("entities.unit", "Creature::SetCannotReachTarget() called with true. Details: {}", GetDebugInfo()); + } +} + +bool Creature::CanNotReachTarget() const +{ + return m_cannotReachTarget; +} + +bool Creature::IsNotReachableAndNeedRegen() const +{ + if (CanNotReachTarget()) + { + return m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_REGEN_TIME_IF_NOT_REACHABLE_IN_RAID) * IN_MILLISECONDS); + } + + return false; } time_t Creature::GetLastDamagedTime() const diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index da59caf67..f63b54179 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -198,7 +198,7 @@ public: void SetDetectionDistance(float dist){ m_detectionDistance = dist; } [[nodiscard]] CreatureAddon const* GetCreatureAddon() const; - [[nodiscard]] std::string GetAIName() const; + [[nodiscard]] std::string const& GetAIName() const; [[nodiscard]] std::string GetScriptName() const; [[nodiscard]] uint32 GetScriptId() const; @@ -300,6 +300,7 @@ public: bool isRegeneratingHealth() { return m_regenHealth; } void SetRegeneratingHealth(bool c) { m_regenHealth = c; } + void SetRegeneratingPower(bool c) { m_regenPower = c; } [[nodiscard]] virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; } [[nodiscard]] virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const { @@ -417,6 +418,7 @@ protected: bool m_AlreadyCallAssistance; bool m_AlreadySearchedAssistance; bool m_regenHealth; + bool m_regenPower; bool m_AI_locked; SpellSchoolMask m_meleeDamageSchoolMask; @@ -455,7 +457,7 @@ private: mutable std::shared_ptr _lastDamagedTime; // Part of Evade mechanics - bool m_cannotReachTarget; + ObjectGuid m_cannotReachTarget; uint32 m_cannotReachTimer; Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 0892d6f3c..a24f422bb 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -80,8 +80,7 @@ enum CreatureFlagsExtra : uint32 CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000, // Masks - CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_26 | - CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28), // SKIP + CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_26 | CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28), // SKIP CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP }; diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 030134f26..a181c571a 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -381,3 +381,40 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z, bool run) } } } + +void CreatureGroup::RespawnFormation(bool force) +{ + for (auto const& itr : m_members) + { + if (itr.first && !itr.first->IsAlive()) + { + itr.first->Respawn(force); + } + } +} + +bool CreatureGroup::IsFormationInCombat() +{ + for (auto const& itr : m_members) + { + if (itr.first && itr.first->IsInCombat()) + { + return true; + } + } + + return false; +} + +bool CreatureGroup::IsAnyMemberAlive() +{ + for (auto const& itr : m_members) + { + if (itr.first && itr.first->IsAlive()) + { + return true; + } + } + + return false; +} diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index 9a4db6736..9fe3398f5 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -109,6 +109,9 @@ public: void LeaderMoveTo(float x, float y, float z, bool run); void MemberEngagingTarget(Creature* member, Unit* target); void MemberEvaded(Creature* member); + void RespawnFormation(bool force = false); + [[nodiscard]] bool IsFormationInCombat(); + [[nodiscard]] bool IsAnyMemberAlive(); private: Creature* m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 8f01e7014..f7dae5606 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -96,7 +96,7 @@ bool GameObject::AIM_Initialize() return true; } -std::string GameObject::GetAIName() const +std::string const& GameObject::GetAIName() const { return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName; } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 6f26f7245..d74f7cccd 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -1001,7 +1001,7 @@ public: [[nodiscard]] virtual uint32 GetScriptId() const; [[nodiscard]] GameObjectAI* AI() const { return m_AI; } - [[nodiscard]] std::string GetAIName() const; + [[nodiscard]] std::string const& GetAIName() const; void SetDisplayId(uint32 displayid); [[nodiscard]] uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); } diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index dccb099bd..79ea17ede 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1154,7 +1154,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) { // xinef: Glyph of Felguard, so ugly im crying... no appropriate spell if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_FELGUARD)) - SetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, 1.0f + float(aurEff->GetAmount() / 100.0f)); + { + HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true); + } break; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index dae6a6032..949fc9707 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8911,7 +8911,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) return; } - if (returnreagent && (pet || m_temporaryUnsummonedPetNumber) && !InBattleground()) + if (returnreagent && (pet || (m_temporaryUnsummonedPetNumber && (!m_session || !m_session->PlayerLogout()))) && !InBattleground()) { //returning of reagents only for players, so best done here uint32 spellId = pet ? pet->GetUInt32Value(UNIT_CREATED_BY_SPELL) : m_oldpetspell; @@ -12573,8 +12573,13 @@ void Player::SetMover(Unit* target) LOG_INFO("misc", "Player::SetMover (B2) - {}, {}, {}, {}, {}, {}, {}, {}", target->GetGUID().ToString(), target->GetMapId(), target->GetInstanceId(), target->FindMap()->GetId(), target->IsInWorld() ? 1 : 0, target->IsDuringRemoveFromWorld() ? 1 : 0, (target->ToPlayer() && target->ToPlayer()->IsBeingTeleported() ? 1 : 0), target->isBeingLoaded() ? 1 : 0); } m_mover->m_movedByPlayer = nullptr; + if (m_mover->GetTypeId() == TYPEID_UNIT) + m_mover->GetMotionMaster()->Initialize(); + m_mover = target; m_mover->m_movedByPlayer = this; + if (m_mover->GetTypeId() == TYPEID_UNIT) + m_mover->GetMotionMaster()->Initialize(); } uint32 Player::GetCorpseReclaimDelay(bool pvp) const diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7b5252a8e..89124e9c7 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -289,8 +289,8 @@ typedef std::list PlayerCreateInfoItems; struct PlayerClassLevelInfo { PlayerClassLevelInfo() = default; - uint16 basehealth{0}; - uint16 basemana{0}; + uint32 basehealth{0}; + uint32 basemana{0}; }; struct PlayerClassInfo @@ -302,9 +302,12 @@ struct PlayerClassInfo struct PlayerLevelInfo { - PlayerLevelInfo() { for (unsigned char & stat : stats) stat = 0; } + PlayerLevelInfo() + { + stats.fill(0); + } - uint8 stats[MAX_STATS]; + std::array stats = { }; }; typedef std::list PlayerCreateInfoSpells; @@ -2732,7 +2735,7 @@ public: ActionButtonList m_actionButtons; float m_auraBaseMod[BASEMOD_END][MOD_END]; - int16 m_baseRatingValue[MAX_COMBAT_RATING]; + int32 m_baseRatingValue[MAX_COMBAT_RATING]; uint32 m_baseSpellPower; uint32 m_baseFeralAP; uint32 m_baseManaRegen; diff --git a/src/server/game/Entities/Player/PlayerSettings.cpp b/src/server/game/Entities/Player/PlayerSettings.cpp index 46130b115..f81bfe9a9 100644 --- a/src/server/game/Entities/Player/PlayerSettings.cpp +++ b/src/server/game/Entities/Player/PlayerSettings.cpp @@ -108,12 +108,11 @@ void Player::_SavePlayerSettings(CharacterDatabaseTransaction trans) void Player::UpdatePlayerSetting(std::string source, uint8 index, uint32 value) { auto itr = m_charSettingsMap.find(source); + uint8 size = index + 1; if (itr == m_charSettingsMap.end()) { // Settings not found, initialize a new entry. - uint8 size = index ? index : index + 1; - PlayerSettingVector setting; setting.resize(size); @@ -129,6 +128,10 @@ void Player::UpdatePlayerSetting(std::string source, uint8 index, uint32 value) } else { + if (size > itr->second.size()) + { + itr->second.resize(size); + } itr->second[index].value = value; } } diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index 1ed444bb4..73486f979 100644 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -34,20 +34,13 @@ Totem::Totem(SummonPropertiesEntry const* properties, ObjectGuid owner) : Minion void Totem::Update(uint32 time) { Unit* owner = GetOwner(); - if (!owner || !owner->IsAlive() || !IsAlive()) + if (!owner || !owner->IsAlive() || !IsAlive() || m_duration <= time) { UnSummon(); // remove self return; } - if (m_duration <= time) - { - UnSummon(); // remove self - return; - } - else - m_duration -= time; - + m_duration -= time; Creature::Update(time); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 3d9b9a7ff..488dda03c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1034,7 +1034,14 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime().count() + MAX_AGGRO_RESET_TIME); if (attacker) + { + if (spellProto && !victim->IsInCombatWith(attacker)) + { + victim->CombatStart(attacker, !(spellProto->AttributesEx3 & SPELL_ATTR3_SUPRESS_TARGET_PROCS)); + } + victim->AddThreat(attacker, float(damage), damageSchoolMask, spellProto); + } } else // victim is a player { @@ -8921,6 +8928,15 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg // Lightning Shield (overwrite non existing triggered spell call in spell.dbc if (auraSpellInfo->SpellFamilyFlags[0] & 0x400) { + // Do not proc off from self-casted items + if (Spell const* spell = eventInfo.GetProcSpell()) + { + if (spell->m_castItemGUID && victim->GetGUID() == GetGUID()) + { + return false; + } + } + trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, auraSpellInfo->GetRank()); } // Nature's Guardian diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 568597c34..c82efc403 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -22,10 +22,12 @@ #include "CharacterCache.h" #include "Chat.h" #include "Common.h" +#include "CreatureAIFactory.h" #include "Config.h" #include "Containers.h" #include "DatabaseEnv.h" #include "DisableMgr.h" +#include "GameObjectAIFactory.h" #include "GameEventMgr.h" #include "GameTime.h" #include "GossipDef.h" @@ -979,6 +981,12 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) ok = true; } + if (!cInfo->AIName.empty() && !sCreatureAIRegistry->HasItem(cInfo->AIName)) + { + LOG_ERROR("sql.sql", "Creature (Entry: {}) has non-registered `AIName` '{}' set, removing", cInfo->Entry, cInfo->AIName); + const_cast(cInfo)->AIName.clear(); + } + FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction); if (!factionTemplate) LOG_ERROR("sql.sql", "Creature (Entry: {}) has non-existing faction template ({}).", cInfo->Entry, cInfo->faction); @@ -2162,6 +2170,11 @@ void ObjectMgr::LoadCreatures() LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with a `creature_template`.`flags_extra` in one or more entries including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.", spawnId, data.id1, data.id2, data.id3); } + if (data.movementType >= MAX_DB_MOTION_TYPE) + { + LOG_ERROR("sql.sql", "Table `creature` has creature (SpawnId: {} Entries: {}, {}, {}) with wrong movement generator type ({}), ignored and set to IDLE.", spawnId, data.id1, data.id2, data.id3, data.movementType); + data.movementType = IDLE_MOTION_TYPE; + } if (data.wander_distance < 0.0f) { LOG_ERROR("sql.sql", "Table `creature` have creature (SpawnId: {} Entries: {}, {}, {}) with `wander_distance`< 0, set to 0.", spawnId, data.id1, data.id2, data.id3); @@ -2665,7 +2678,7 @@ void ObjectMgr::LoadItemTemplates() for (uint8 i = 0; i < itemTemplate.StatsCount; ++i) { itemTemplate.ItemStat[i].ItemStatType = uint32(fields[28 + i * 2].Get()); - itemTemplate.ItemStat[i].ItemStatValue = int32(fields[29 + i * 2].Get()); + itemTemplate.ItemStat[i].ItemStatValue = fields[29 + i * 2].Get(); } itemTemplate.ScalingStatDistribution = uint32(fields[48].Get()); @@ -2678,13 +2691,13 @@ void ObjectMgr::LoadItemTemplates() itemTemplate.Damage[i].DamageType = uint32(fields[52 + i * 3].Get()); } - itemTemplate.Armor = uint32(fields[56].Get()); - itemTemplate.HolyRes = uint32(fields[57].Get()); - itemTemplate.FireRes = uint32(fields[58].Get()); - itemTemplate.NatureRes = uint32(fields[59].Get()); - itemTemplate.FrostRes = uint32(fields[60].Get()); - itemTemplate.ShadowRes = uint32(fields[61].Get()); - itemTemplate.ArcaneRes = uint32(fields[62].Get()); + itemTemplate.Armor = fields[56].Get(); + itemTemplate.HolyRes = fields[57].Get(); + itemTemplate.FireRes = fields[58].Get(); + itemTemplate.NatureRes = fields[59].Get(); + itemTemplate.FrostRes = fields[60].Get(); + itemTemplate.ShadowRes = fields[61].Get(); + itemTemplate.ArcaneRes = fields[62].Get(); itemTemplate.Delay = uint32(fields[63].Get()); itemTemplate.AmmoType = uint32(fields[64].Get()); itemTemplate.RangedModRange = fields[65].Get(); @@ -3435,14 +3448,14 @@ void ObjectMgr::LoadPetLevelInfo() // data for level 1 stored in [0] array element, ... PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level - 1]; - pLevelInfo->health = fields[2].Get(); - pLevelInfo->mana = fields[3].Get(); + pLevelInfo->health = fields[2].Get(); + pLevelInfo->mana = fields[3].Get(); pLevelInfo->armor = fields[9].Get(); - pLevelInfo->min_dmg = fields[10].Get(); - pLevelInfo->max_dmg = fields[11].Get(); - for (int i = 0; i < MAX_STATS; i++) + pLevelInfo->min_dmg = fields[10].Get(); + pLevelInfo->max_dmg = fields[11].Get(); + for (uint8 i = 0; i < MAX_STATS; i++) { - pLevelInfo->stats[i] = fields[i + 4].Get(); + pLevelInfo->stats[i] = fields[i + 4].Get(); } ++count; @@ -3960,8 +3973,8 @@ void ObjectMgr::LoadPlayerInfo() PlayerClassLevelInfo& levelInfo = info->levelInfo[current_level - 1]; - levelInfo.basehealth = fields[2].Get(); - levelInfo.basemana = fields[3].Get(); + levelInfo.basehealth = fields[2].Get(); + levelInfo.basemana = fields[3].Get(); ++count; } while (result->NextRow()); @@ -4051,8 +4064,8 @@ void ObjectMgr::LoadPlayerInfo() info->levelInfo = new PlayerLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)]; PlayerLevelInfo& levelInfo = info->levelInfo[current_level - 1]; - for (int i = 0; i < MAX_STATS; i++) - levelInfo.stats[i] = fields[i + 3].Get(); + for (uint8 i = 0; i < MAX_STATS; i++) + levelInfo.stats[i] = fields[i + 3].Get(); } ++count; @@ -7040,6 +7053,10 @@ void ObjectMgr::LoadGameObjectTemplate() got.IsForQuests = false; // Checks + if (!got.AIName.empty() && !sGameObjectAIRegistry->HasItem(got.AIName)) + { + LOG_ERROR("sql.sql", "GameObject (Entry: {}) has non-registered `AIName` '{}' set, removing", got.entry, got.AIName); + } switch (got.type) { @@ -9342,7 +9359,7 @@ void ObjectMgr::LoadCreatureClassLevelStats() for (uint8 i = 0; i < MAX_EXPANSIONS; ++i) { - stats.BaseHealth[i] = fields[2 + i].Get(); + stats.BaseHealth[i] = fields[2 + i].Get(); if (stats.BaseHealth[i] == 0) { @@ -9372,11 +9389,11 @@ void ObjectMgr::LoadCreatureClassLevelStats() } } - stats.BaseMana = fields[5].Get(); - stats.BaseArmor = fields[6].Get(); + stats.BaseMana = fields[5].Get(); + stats.BaseArmor = fields[6].Get(); - stats.AttackPower = fields[7].Get(); - stats.RangedAttackPower = fields[8].Get(); + stats.AttackPower = fields[7].Get(); + stats.RangedAttackPower = fields[8].Get(); _creatureBaseStatsStore[MAKE_PAIR16(Level, Class)] = stats; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 190050df4..a5e36b690 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -520,14 +520,17 @@ typedef std::pair stats = { }; + uint32 health{0}; + uint32 mana{0}; uint32 armor{0}; - uint16 min_dmg{0}; - uint16 max_dmg{0}; + uint32 min_dmg{0}; + uint32 max_dmg{0}; }; struct MailLevelReward diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index d93c476b3..ab72656b9 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1448,7 +1448,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap) roll->getLoot()->NotifyItemRemoved(roll->itemSlot); roll->getLoot()->unlootedCount--; AllowedLooterSet looters = item->GetAllowedLooters(); - player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters); + Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters); + sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), NEED, roll); player->UpdateLootAchievements(item, roll->getLoot()); } else @@ -1516,7 +1517,8 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap) roll->getLoot()->NotifyItemRemoved(roll->itemSlot); roll->getLoot()->unlootedCount--; AllowedLooterSet looters = item->GetAllowedLooters(); - player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters); + Item* _item = player->StoreNewItem(dest, roll->itemid, true, item->randomPropertyId, looters); + sScriptMgr->OnGroupRollRewardItem(player, _item, _item->GetCount(), GREED, roll); player->UpdateLootAchievements(item, roll->getLoot()); } else diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index b7e4f8193..0846f2281 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2965,6 +2965,11 @@ bool InstanceMap::AddPlayerToMap(Player* player) return false; } } + else if (player->GetSession()->PlayerLoading() && playerBind && playerBind->save != mapSave) + { + // Prevent "Convert to Raid" exploit to reset instances + return false; + } else { playerBind = sInstanceSaveMgr->PlayerBindToInstance(player->GetGUID(), mapSave, false, player); diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index 7a52ba113..ae795f6aa 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -39,6 +39,7 @@ public: virtual void OnGameObjectRemove(GameObject*) { } virtual void OnUnitDeath(Unit*) { } + virtual void OnCreatureEvade(Creature*) { } //All-purpose data storage 64 bit virtual ObjectGuid GetGuidData(uint32 /*DataId*/) const { return ObjectGuid::Empty; } diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 6d2cdcb95..fe8075ddb 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -32,6 +32,11 @@ #include "TargetedMovementGenerator.h" #include "WaypointMovementGenerator.h" +inline MovementGenerator* GetIdleMovementGenerator() +{ + return sMovementGeneratorRegistry->GetRegistryItem(IDLE_MOTION_TYPE)->Create(); +} + // ---- ChaseRange ---- // ChaseRange::ChaseRange(float range) : MinRange(range > CONTACT_DISTANCE ? 0 : range - CONTACT_DISTANCE), MinTolerance(range), MaxRange(range + CONTACT_DISTANCE), MaxTolerance(range) { } @@ -59,9 +64,9 @@ bool ChaseAngle::IsAngleOkay(float relativeAngle) const return (std::min(diff, float(2 * M_PI) - diff) <= Tolerance); } -inline bool isStatic(MovementGenerator* mv) +inline bool isStatic(MovementGenerator* movement) { - return (mv == &si_idleMovement); + return (movement == GetIdleMovementGenerator()); } void MotionMaster::Initialize() @@ -80,16 +85,7 @@ void MotionMaster::Initialize() // set new default movement generator void MotionMaster::InitDefault() { - // Xinef: Do not allow to initialize any motion generator for dead creatures - if (_owner->GetTypeId() == TYPEID_UNIT && _owner->IsAlive()) - { - MovementGenerator* movement = FactorySelector::selectMovementGenerator(_owner->ToCreature()); - Mutate(!movement ? &si_idleMovement : movement, MOTION_SLOT_IDLE); - } - else - { - Mutate(&si_idleMovement, MOTION_SLOT_IDLE); - } + Mutate(FactorySelector::SelectMovementGenerator(_owner), MOTION_SLOT_IDLE); } MotionMaster::~MotionMaster() @@ -236,7 +232,7 @@ void MotionMaster::MoveIdle() { //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active if (empty() || !isStatic(top())) - Mutate(&si_idleMovement, MOTION_SLOT_IDLE); + Mutate(GetIdleMovementGenerator(), MOTION_SLOT_IDLE); } void MotionMaster::MoveRandom(float wanderDistance) diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp index 3e80ab121..a14578b26 100644 --- a/src/server/game/Movement/MovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerator.cpp @@ -16,7 +16,14 @@ */ #include "MovementGenerator.h" +#include "IdleMovementGenerator.h" MovementGenerator::~MovementGenerator() { } + +MovementGenerator* IdleMovementFactory::Create(Unit* /*object*/) const +{ + static IdleMovementGenerator instance; + return &instance; +} diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index 5ea148e2c..2f317ec48 100644 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -82,19 +82,28 @@ public: } }; -struct SelectableMovement : public FactoryHolder +typedef FactoryHolder MovementGeneratorCreator; + +template +struct MovementGeneratorFactory : public MovementGeneratorCreator { - SelectableMovement(MovementGeneratorType mgt) : FactoryHolder(mgt) {} + MovementGeneratorFactory(MovementGeneratorType movementGeneratorType) : MovementGeneratorCreator(movementGeneratorType) { } + + MovementGenerator* Create(Unit* /*object*/) const + { + return new Movement(); + } }; -template -struct MovementGeneratorFactory : public SelectableMovement +struct IdleMovementFactory : public MovementGeneratorCreator { - MovementGeneratorFactory(MovementGeneratorType mgt) : SelectableMovement(mgt) {} + IdleMovementFactory() : MovementGeneratorCreator(IDLE_MOTION_TYPE) { } - MovementGenerator* Create(void*) const; + MovementGenerator* Create(Unit* object) const override; }; -typedef FactoryHolder MovementGeneratorCreator; -typedef FactoryHolder::FactoryHolderRegistry MovementGeneratorRegistry; +typedef MovementGeneratorCreator::FactoryHolderRegistry MovementGeneratorRegistry; + +#define sMovementGeneratorRegistry MovementGeneratorRegistry::instance() + #endif diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h deleted file mode 100644 index d566fbbcb..000000000 --- a/src/server/game/Movement/MovementGeneratorImpl.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef ACORE_MOVEMENTGENERATOR_IMPL_H -#define ACORE_MOVEMENTGENERATOR_IMPL_H - -#include "MovementGenerator.h" - -template -inline MovementGenerator* -MovementGeneratorFactory::Create(void* /*data*/) const -{ - return (new MOVEMENT_GEN()); -} -#endif diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp index da3058c76..5f64daef3 100644 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp @@ -19,8 +19,6 @@ #include "Creature.h" #include "CreatureAI.h" -IdleMovementGenerator si_idleMovement; - // StopMoving is needed to make unit stop if its last movement generator expires // But it should not be sent otherwise there are many redundent packets void IdleMovementGenerator::Initialize(Unit* owner) diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h index b1571f66d..293862bdd 100644 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h @@ -30,8 +30,6 @@ public: MovementGeneratorType GetMovementGeneratorType() override { return IDLE_MOTION_TYPE; } }; -extern IdleMovementGenerator si_idleMovement; - class RotateMovementGenerator : public MovementGenerator { public: diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 6e8f80065..5e06523fa 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -41,7 +41,7 @@ void PointMovementGenerator::DoInitialize(T* unit) unit->StopMoving(); unit->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - if (id == EVENT_CHARGE) + if (id == EVENT_CHARGE || id == EVENT_CHARGE_PREPATH) { unit->AddUnitState(UNIT_STATE_CHARGING); } @@ -158,7 +158,7 @@ template void PointMovementGenerator::DoFinalize(T* unit) { unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - if (id == EVENT_CHARGE) + if (id == EVENT_CHARGE || id == EVENT_CHARGE_PREPATH) { unit->ClearUnitState(UNIT_STATE_CHARGING); @@ -182,7 +182,7 @@ void PointMovementGenerator::DoReset(T* unit) unit->StopMoving(); unit->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - if (id == EVENT_CHARGE) + if (id == EVENT_CHARGE || id == EVENT_CHARGE_PREPATH) { unit->AddUnitState(UNIT_STATE_CHARGING); } diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 40a57f888..215040b46 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -61,7 +61,10 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) { owner->StopMoving(); _lastTargetPosition.reset(); - owner->SetCannotReachTarget(false); + if (Creature* cOwner2 = owner->ToCreature()) + { + cOwner2->SetCannotReachTarget(); + } return true; } @@ -88,9 +91,17 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) if (i_recalculateTravel && PositionOkay(owner, target, _movingTowards ? maxTarget : Optional(), angle)) { + if (Creature* cOwner2 = owner->ToCreature()) + { + cOwner2->SetCannotReachTarget(i_path && i_path->GetPathType() & PATHFIND_INCOMPLETE ? target->GetGUID() : ObjectGuid::Empty); + } + i_recalculateTravel = false; i_path = nullptr; - owner->SetCannotReachTarget(false); + if (Creature* cOwner2 = owner->ToCreature()) + { + cOwner2->SetCannotReachTarget(false); + } owner->StopMoving(); owner->SetInFront(target); @@ -101,14 +112,24 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) && owner->movespline->Finalized()) { - i_recalculateTravel = false; - i_path = nullptr; owner->ClearUnitState(UNIT_STATE_CHASE_MOVE); owner->SetInFront(target); MovementInform(owner); if (owner->IsWithinMeleeRange(this->i_target.getTarget())) + { owner->Attack(this->i_target.getTarget(), true); + } + else if (i_path && i_path->GetPathType() & PATHFIND_INCOMPLETE) + { + if (Creature* cOwner2 = owner->ToCreature()) + { + cOwner2->SetCannotReachTarget(this->i_target.getTarget()->GetGUID()); + } + } + + i_recalculateTravel = false; + i_path = nullptr; } if (_lastTargetPosition && i_target->GetPosition() == _lastTargetPosition.value() && mutualChase == _mutualChase) @@ -133,7 +154,7 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) // can we get to the target? if (cOwner && !target->isInAccessiblePlaceFor(cOwner)) { - cOwner->SetCannotReachTarget(true); + cOwner->SetCannotReachTarget(target->GetGUID()); cOwner->StopMoving(); i_path = nullptr; return true; @@ -169,14 +190,21 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) bool success = i_path->CalculatePath(x, y, z, forceDest); if (!success || i_path->GetPathType() & PATHFIND_NOPATH) { - owner->SetCannotReachTarget(true); + if (cOwner) + { + cOwner->SetCannotReachTarget(target->GetGUID()); + } + return true; } if (shortenPath) i_path->ShortenPathUntilDist(G3D::Vector3(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), maxTarget); - owner->SetCannotReachTarget(false); + if (cOwner) + { + cOwner->SetCannotReachTarget(); + } bool walk = false; if (cOwner && !cOwner->IsPet()) @@ -230,7 +258,10 @@ template void ChaseMovementGenerator::DoFinalize(T* owner) { owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE); - owner->SetCannotReachTarget(false); + if (Creature* cOwner = owner->ToCreature()) + { + cOwner->SetCannotReachTarget(); + } } template diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index 867a278e4..b62d36864 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -598,6 +598,14 @@ void ScriptMgr::OnQuestRewardItem(Player* player, Item* item, uint32 count) }); } +void ScriptMgr::OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnGroupRollRewardItem(player, item, count, voteType, roll); + }); +} + void ScriptMgr::OnFirstLogin(Player* player) { ExecuteScript([&](PlayerScript* script) diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index d0bf853e9..36939d1b9 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -26,6 +26,7 @@ #include "DBCStores.h" #include "DynamicObject.h" #include "GameEventMgr.h" +#include "Group.h" #include "LFGMgr.h" #include "ObjectMgr.h" #include "PetDefines.h" @@ -1174,6 +1175,9 @@ public: // After receiving item as a quest reward virtual void OnQuestRewardItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/) { } + // After receiving item as a group roll reward + virtual void OnGroupRollRewardItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/, RollVote /*voteType*/, Roll* /*roll*/) { } + // After completed a quest [[nodiscard]] virtual bool OnBeforeQuestComplete(Player* /*player*/, uint32 /*quest_id*/) { return true; } @@ -2285,6 +2289,7 @@ public: /* PlayerScript */ void OnLootItem(Player* player, Item* item, uint32 count, ObjectGuid lootguid); void OnCreateItem(Player* player, Item* item, uint32 count); void OnQuestRewardItem(Player* player, Item* item, uint32 count); + void OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll); bool OnBeforePlayerQuestComplete(Player* player, uint32 quest_id); void OnQuestComputeXP(Player* player, Quest const* quest, uint32& xpValue); void OnBeforePlayerDurabilityRepair(Player* player, ObjectGuid npcGUID, ObjectGuid itemGUID, float& discountMod, uint8 guildBank); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index b1058e4c6..647f9f865 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -682,11 +682,12 @@ void WorldSession::LogoutPlayer(bool save) _player->GetGroup()->SendUpdate(); _player->GetGroup()->ResetMaxEnchantingLevel(); - Map::PlayerList const& playerList = _player->GetMap()->GetPlayers(); - if (_player->GetMap()->IsDungeon() || _player->GetMap()->IsRaidOrHeroicDungeon()) + { + Map::PlayerList const &playerList = _player->GetMap()->GetPlayers(); if (playerList.IsEmpty()) _player->TeleportToEntryPoint(); + } } //! Broadcast a logout message to the player's friends diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index 17542822f..30ca46693 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4323,6 +4323,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].MiscValue = 8; }); + // Elemental Mastery + ApplySpellFix({ 16166 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(0x00000003, 0x00001000); + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 78d46ebe9..dbd56b23c 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1568,6 +1568,9 @@ void World::SetInitialWorldSettings() LOG_INFO("server.loading", "Initializing PlayerDump tables..."); PlayerDump::InitializeTables(); + ///- Initilize static helper structures + AIRegistry::Initialize(); + LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); @@ -2036,9 +2039,6 @@ void World::SetInitialWorldSettings() mail_expire_check_timer = GameTime::GetGameTime() + 6h; - ///- Initilize static helper structures - AIRegistry::Initialize(); - ///- Initialize MapMgr LOG_INFO("server.loading", "Starting Map System"); LOG_INFO("server.loading", " "); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 09c252580..15ded917f 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -186,6 +186,7 @@ public: static ChatCommandTable npcCommandTable = { { "info", HandleNpcInfoCommand, SEC_GAMEMASTER, Console::No }, + { "guid", HandleNpcGuidCommand, SEC_GAMEMASTER, Console::No }, { "near", HandleNpcNearCommand, SEC_GAMEMASTER, Console::No }, { "move", HandleNpcMoveCommand, SEC_GAMEMASTER, Console::No }, { "playemote", HandleNpcPlayEmoteCommand, SEC_GAMEMASTER, Console::No }, @@ -652,6 +653,36 @@ public: return true; } + static bool HandleNpcGuidCommand(ChatHandler* handler) + { + Creature* target = handler->getSelectedCreature(); + + if (!target) + { + handler->SendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + uint32 faction = target->GetFaction(); + uint32 npcflags = target->GetNpcFlags(); + uint32 displayid = target->GetDisplayId(); + uint32 nativeid = target->GetNativeDisplayId(); + uint32 entry = target->GetEntry(); + uint32 id1 = 0; + uint32 id2 = 0; + uint32 id3 = 0; + if (CreatureData const* cData = target->GetCreatureData()) + { + id1 = cData->id1; + id2 = cData->id2; + id3 = cData->id3; + } + + handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetSpawnId(), target->GetGUID().GetCounter(), entry, id1, id2, id3, displayid, nativeid, faction, npcflags); + + return true; + } static bool HandleNpcNearCommand(ChatHandler* handler, Optional dist) { diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp index 77877043f..0b8af4541 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp @@ -122,7 +122,7 @@ public: events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE); events.ScheduleEvent(EVENT_SUMMON_PROWLERS, 6000, 0, PHASE_ALL); events.ScheduleEvent(EVENT_MARK_OF_ARLOKK, urand(9000, 11000), 0, PHASE_ALL); - events.ScheduleEvent(EVENT_TRANSFORM, urand(15000, 20000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_TRANSFORM, 30000, 0, PHASE_ONE); Talk(SAY_AGGRO); // Sets up list of Panther spawners to cast on @@ -249,7 +249,7 @@ public: case EVENT_VANISH_2: DoCastSelf(SPELL_VANISH); DoCastSelf(SPELL_SUPER_INVIS); - events.ScheduleEvent(EVENT_VISIBLE, urand(7000, 10000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_VISIBLE, urand(41000, 47000), 0, PHASE_ONE); break; case EVENT_VISIBLE: me->SetReactState(REACT_AGGRESSIVE); @@ -259,7 +259,7 @@ public: me->RemoveAura(SPELL_SUPER_INVIS); me->RemoveAura(SPELL_VANISH); events.ScheduleEvent(EVENT_RAVAGE, urand(10000, 14000), 0, PHASE_TWO); - events.ScheduleEvent(EVENT_TRANSFORM_BACK, urand(15000, 18000), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSFORM_BACK, urand(30000, 40000), 0, PHASE_TWO); events.SetPhase(PHASE_TWO); me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack break; @@ -276,7 +276,7 @@ public: me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(4000, 7000), 0, PHASE_ONE); events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE); - events.ScheduleEvent(EVENT_TRANSFORM, urand(16000, 20000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_TRANSFORM, 30000, 0, PHASE_ONE); events.SetPhase(PHASE_ONE); break; } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp index d4aa84a18..6d85c47d8 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp @@ -68,6 +68,9 @@ struct boss_jindo : public BossAI events.ScheduleEvent(EVENT_TELEPORT, 5000); Talk(SAY_AGGRO); + + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + _scheduler.CancelAll(); } void JustSummoned(Creature* summon) override @@ -76,14 +79,15 @@ struct boss_jindo : public BossAI switch (summon->GetEntry()) { - case NPC_BRAIN_WASH_TOTEM: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1)) - { - summon->CastSpell(target, summon->m_spells[0], true); - } - break; - default: - break; + case NPC_BRAIN_WASH_TOTEM: + summon->SetReactState(REACT_PASSIVE); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, me->GetThreatMgr().getThreatList().size() > 1 ? 1 : 0)) + { + summon->CastSpell(target, summon->m_spells[0], true); + } + break; + default: + break; } } @@ -91,20 +95,22 @@ struct boss_jindo : public BossAI { if (_EnterEvadeMode(evadeReason)) { - me->AddUnitState(UNIT_STATE_EVADE); Reset(); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCE); - me->m_Events.AddEventAtOffset([&]() + _scheduler.Schedule(4s, [this](TaskContext /*context*/) { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + me->AddUnitState(UNIT_STATE_EVADE); me->GetMotionMaster()->MoveTargetedHome(); - }, 4s); + }); } } void UpdateAI(uint32 diff) override { + _scheduler.Update(diff); + if (!UpdateVictim()) return; @@ -153,6 +159,9 @@ struct boss_jindo : public BossAI return true; } + +private: + TaskScheduler _scheduler; }; //Healing Ward @@ -282,11 +291,23 @@ class spell_delusions_of_jindo : public SpellScript } }; +struct npc_brain_wash_totem : public ScriptedAI +{ + npc_brain_wash_totem(Creature* creature) : ScriptedAI(creature) + { + } + + void EnterEvadeMode(EvadeReason /*evadeReason*/) override + { + } +}; + void AddSC_boss_jindo() { RegisterZulGurubCreatureAI(boss_jindo); RegisterZulGurubCreatureAI(npc_healing_ward); RegisterZulGurubCreatureAI(npc_shade_of_jindo); + RegisterZulGurubCreatureAI(npc_brain_wash_totem); RegisterSpellScript(spell_random_aggro); RegisterSpellScript(spell_delusions_of_jindo); } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index 018b64b64..cf9d16c47 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -286,7 +286,7 @@ public: if (_chargeTarget.first == hatedUnit->GetGUID()) { // Do not count DOTs/HOTs - if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT)) + if (!(threatSpell && (threatSpell->HasAura(SPELL_AURA_DAMAGE_SHIELD) || threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT)))) { _chargeTarget.second += threat; } @@ -313,6 +313,12 @@ public: } } + bool OnTeleportUnreacheablePlayer(Player* player) override + { + DoCast(player, SPELL_SUMMON_PLAYER, true); + return true; + } + void DoMeleeAttackIfReady(bool ignoreCasting) { if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING)) diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp index a99c4ad5f..2e1af2680 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp @@ -91,8 +91,6 @@ public: default: break; } - - InstanceScript::OnCreatureCreate(creature); } void OnGameObjectCreate(GameObject* go) override diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp index 977f2fbb4..d1198e820 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp @@ -25,7 +25,6 @@ enum Spells SPELL_STINGER_SPRAY = 25749, SPELL_POISON_STINGER = 25748, SPELL_PARALYZE = 25725, - SPELL_TRASH = 3391, SPELL_FRENZY = 8269, SPELL_LASH = 25852, SPELL_FEED = 25721 @@ -38,8 +37,7 @@ enum Events EVENT_SUMMON_SWARMER = 3, EVENT_SWARMER_ATTACK = 4, EVENT_PARALYZE = 5, - EVENT_LASH = 6, - EVENT_TRASH = 7 + EVENT_LASH = 6 }; enum Emotes @@ -77,9 +75,7 @@ public: struct boss_ayamissAI : public BossAI { - boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) - { - } + boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) {} void Reset() override { @@ -101,7 +97,9 @@ public: break; case NPC_HORNET: if (Unit* target = SelectTarget(SelectTargetMethod::Random)) + { who->AI()->AttackStart(target); + } break; } } @@ -116,7 +114,7 @@ public: me->AddUnitState(UNIT_STATE_ROOT); break; case POINT_GROUND: - me->ClearUnitState(UNIT_STATE_ROOT); + me->GetMotionMaster()->MoveChase(me->GetVictim()); break; } } @@ -131,55 +129,51 @@ public: void EnterCombat(Unit* attacker) override { BossAI::EnterCombat(attacker); - events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(20000, 30000)); events.ScheduleEvent(EVENT_POISON_STINGER, 5000); events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000); events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000); events.ScheduleEvent(EVENT_PARALYZE, 15000); - me->SetCanFly(true); me->SetDisableGravity(true); me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos); } + void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + { + if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f) + { + _phase = PHASE_GROUND; + SetCombatMovement(true); + me->ClearUnitState(UNIT_STATE_ROOT); + me->SetCanFly(false); + me->SetDisableGravity(false); + Position VictimPos = me->GetVictim()->GetPosition(); + me->GetMotionMaster()->MovePoint(POINT_GROUND, VictimPos); + events.ScheduleEvent(EVENT_LASH, urand(5000, 8000)); + events.CancelEvent(EVENT_POISON_STINGER); + DoResetThreat(); + } + if (!_enraged && me->GetHealthPct() < 20.0f) + { + DoCastSelf(SPELL_FRENZY); + Talk(EMOTE_FRENZY); + _enraged = true; + } + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; events.Update(diff); - - if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f) - { - _phase = PHASE_GROUND; - SetCombatMovement(true); - me->SetCanFly(false); - Position VictimPos = me->GetVictim()->GetPosition(); - me->GetMotionMaster()->MovePoint(POINT_GROUND, VictimPos); - DoResetThreat(); - events.ScheduleEvent(EVENT_LASH, urand(5000, 8000)); - events.ScheduleEvent(EVENT_TRASH, urand(3000, 6000)); - events.CancelEvent(EVENT_POISON_STINGER); - } - else - { - DoMeleeAttackIfReady(); - } - - if (!_enraged && me->GetHealthPct() < 20.0f) - { - DoCast(me, SPELL_FRENZY); - Talk(EMOTE_FRENZY); - _enraged = true; - } - while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { case EVENT_STINGER_SPRAY: - DoCast(me, SPELL_STINGER_SPRAY); + DoCastSelf(SPELL_STINGER_SPRAY); events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(15000, 20000)); break; case EVENT_POISON_STINGER: @@ -198,30 +192,32 @@ public: break; case EVENT_SWARMER_ATTACK: for (ObjectGuid const& guid : _swarmers) + { if (Creature* swarmer = me->GetMap()->GetCreature(guid)) + { if (Unit* target = SelectTarget(SelectTargetMethod::Random)) + { swarmer->AI()->AttackStart(target); - + } + } + } _swarmers.clear(); events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000); break; case EVENT_SUMMON_SWARMER: { Position Pos = me->GetRandomPoint(SwarmerPos, 80.0f); - me->SummonCreature(NPC_SWARMER, Pos); + me->SummonCreature(NPC_SWARMER, Pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000); break; } - case EVENT_TRASH: - DoCastVictim(SPELL_TRASH); - events.ScheduleEvent(EVENT_TRASH, urand(5000, 7000)); - break; case EVENT_LASH: DoCastVictim(SPELL_LASH); events.ScheduleEvent(EVENT_LASH, urand(8000, 15000)); break; } } + DoMeleeAttackIfReady(); } private: GuidList _swarmers; @@ -250,9 +246,15 @@ public: void MovementInform(uint32 type, uint32 id) override { if (type == POINT_MOTION_TYPE) + { if (id == POINT_PARALYZE) + { if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED))) - DoCast(target, SPELL_FEED); // Omnomnom + { + DoCast(target, SPELL_FEED); + } + } + } } void MoveInLineOfSight(Unit* who) override diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp index 58a8d28b6..97a419af7 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" +#include "TaskScheduler.h" #include "ruins_of_ahnqiraj.h" enum Emotes @@ -36,7 +37,8 @@ enum Spells SPELL_SUMMON_HATCHLING = 1881, SPELL_EXPLODE = 19593, SPELL_EXPLODE_2 = 5255, - SPELL_BURU_EGG_TRIGGER = 26646 + SPELL_BURU_EGG_TRIGGER = 26646, + SPELL_CREATURE_SPECIAL = 7155, // from sniffs }; enum Events @@ -45,7 +47,7 @@ enum Events EVENT_GATHERING_SPEED = 2, EVENT_FULL_SPEED = 3, EVENT_CREEPING_PLAGUE = 4, - EVENT_RESPAWN_EGG = 5 + EVENT_RESPAWN_EGG = 5, }; enum Phases @@ -54,228 +56,229 @@ enum Phases PHASE_TRANSFORM = 1 }; -enum Actions +struct boss_buru : public BossAI { - ACTION_EXPLODE = 0 -}; + boss_buru(Creature* creature) : BossAI(creature, DATA_BURU) {} -class boss_buru : public CreatureScript -{ -public: - boss_buru() : CreatureScript("boss_buru") { } - - struct boss_buruAI : public BossAI + void EnterEvadeMode(EvadeReason why) override { - boss_buruAI(Creature* creature) : BossAI(creature, DATA_BURU) + BossAI::EnterEvadeMode(why); + + DoCastSelf(SPELL_FULL_SPEED, true); + + ManipulateEggs(true); + _eggs.clear(); + } + + void ManipulateEggs(bool respawn) + { + std::list eggs; + me->GetCreaturesWithEntryInRange(eggs, 150.0f, NPC_BURU_EGG); + for (Creature* egg : eggs) + respawn ? egg->Respawn() : Unit::Kill(me, egg); + } + + void EnterCombat(Unit* who) override + { + _EnterCombat(); + Talk(EMOTE_TARGET, who); + DoCastSelf(SPELL_THORNS); + ManipulateEggs(true); + me->RemoveAurasDueToSpell(SPELL_FULL_SPEED); + events.ScheduleEvent(EVENT_DISMEMBER, 5s); + events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s); + events.ScheduleEvent(EVENT_FULL_SPEED, 60s); + _phase = PHASE_EGG; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_CREATURE_SPECIAL) + ChaseNewVictim(); + } + + void JustDied(Unit* /*killer*/) override + { + if (InstanceScript* pInstance = me->GetInstanceScript()) { + pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_CREEPING_PLAGUE); + } + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + ChaseNewVictim(); + } + + void ChaseNewVictim() + { + if (_phase != PHASE_EGG) + return; + + me->RemoveAurasDueToSpell(SPELL_FULL_SPEED); + me->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); + events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s); + events.ScheduleEvent(EVENT_FULL_SPEED, 60s); + if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 0.f, true)) + { + DoResetThreat(); + AttackStart(victim); + me->AddThreat(victim, 1000000.f); + Talk(EMOTE_TARGET, victim); + } + } + + void SetGUID(ObjectGuid const guid, int32 /*type*/) override + { + _eggs.push_back(guid); + events.ScheduleEvent(EVENT_RESPAWN_EGG, 120s); + } + + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (attacker->GetEntry() != NPC_BURU_EGG && _phase == PHASE_EGG) + { + damage = damage * 0.01f; // 99% dmg resist } - void EnterEvadeMode(EvadeReason why) override + if (me->HealthBelowPctDamaged(20, damage) && _phase == PHASE_EGG) { - BossAI::EnterEvadeMode(why); - - for (ObjectGuid const& guid : Eggs) - if (Creature* egg = me->GetMap()->GetCreature(guid)) - egg->Respawn(); - - Eggs.clear(); + DoCastSelf(SPELL_FULL_SPEED, true); + ManipulateEggs(false); + me->RemoveAurasDueToSpell(SPELL_THORNS); + events.Reset(); + _phase = PHASE_TRANSFORM; + DoResetThreat(); + events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 2s); + DoCastSelf(SPELL_BURU_TRANSFORM); } + } - void EnterCombat(Unit* who) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - _EnterCombat(); - Talk(EMOTE_TARGET, who); - DoCast(me, SPELL_THORNS); - - events.ScheduleEvent(EVENT_DISMEMBER, 5000); - events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000); - events.ScheduleEvent(EVENT_FULL_SPEED, 60000); - - _phase = PHASE_EGG; - } - - void DoAction(int32 action) override - { - if (action == ACTION_EXPLODE) - if (_phase == PHASE_EGG) - Unit::DealDamage(me, me, 45000); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - ChaseNewVictim(); - } - - void ChaseNewVictim() - { - if (_phase != PHASE_EGG) - return; - - me->RemoveAurasDueToSpell(SPELL_FULL_SPEED); - me->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); - events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000); - events.ScheduleEvent(EVENT_FULL_SPEED, 60000); - - if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + switch (eventId) { - DoResetThreat(); - AttackStart(victim); - Talk(EMOTE_TARGET, victim); + case EVENT_DISMEMBER: + DoCastVictim(SPELL_DISMEMBER); + events.ScheduleEvent(EVENT_DISMEMBER, 5s); + break; + case EVENT_GATHERING_SPEED: + DoCastSelf(SPELL_GATHERING_SPEED); + events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s); + break; + case EVENT_FULL_SPEED: + DoCastSelf(SPELL_FULL_SPEED); + break; + case EVENT_CREEPING_PLAGUE: + DoCastAOE(SPELL_CREEPING_PLAGUE); + events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 6s); + break; + case EVENT_RESPAWN_EGG: + if (Creature* egg = me->GetMap()->GetCreature(*_eggs.begin())) + egg->Respawn(); + + _eggs.pop_front(); + break; + default: + break; } } - void ManageRespawn(ObjectGuid EggGUID) + DoMeleeAttackIfReady(); + } +private: + uint8 _phase; + GuidList _eggs; +}; + +struct npc_buru_egg : public ScriptedAI +{ + npc_buru_egg(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + SetCombatMovement(false); + me->SetReactState(REACT_PASSIVE); + } + + void EnterCombat(Unit* attacker) override + { + if (Creature* buru = _instance->GetCreature(DATA_BURU)) { - ChaseNewVictim(); - Eggs.push_back(EggGUID); - events.ScheduleEvent(EVENT_RESPAWN_EGG, 100000); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) + if (!buru->IsInCombat()) { - switch (eventId) + buru->AI()->AttackStart(attacker); + } + } + } + + void JustSummoned(Creature* who) override + { + if (who->GetEntry() == NPC_HATCHLING) + { + if (Creature* buru = _instance->GetCreature(DATA_BURU)) + { + if (Unit* target = buru->AI()->SelectTarget(SelectTargetMethod::Random)) { - case EVENT_DISMEMBER: - DoCastVictim(SPELL_DISMEMBER); - events.ScheduleEvent(EVENT_DISMEMBER, 5000); - break; - case EVENT_GATHERING_SPEED: - DoCast(me, SPELL_GATHERING_SPEED); - events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000); - break; - case EVENT_FULL_SPEED: - DoCast(me, SPELL_FULL_SPEED); - break; - case EVENT_CREEPING_PLAGUE: - DoCast(me, SPELL_CREEPING_PLAGUE); - events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 6000); - break; - case EVENT_RESPAWN_EGG: - if (Creature* egg = me->GetMap()->GetCreature(*Eggs.begin())) - { - egg->Respawn(); - Eggs.pop_front(); - } - break; - default: - break; + who->AI()->AttackStart(target); } } + } + } - if (me->GetHealthPct() < 20.0f && _phase == PHASE_EGG) + void JustDied(Unit* killer) override + { + DoCastSelf(SPELL_SUMMON_HATCHLING, true); + if (killer->GetEntry() != NPC_BURU) + { + if (Creature* buru = _instance->GetCreature(DATA_BURU)) { - DoCast(me, SPELL_BURU_TRANSFORM); // Enrage - DoCast(me, SPELL_FULL_SPEED, true); - me->RemoveAurasDueToSpell(SPELL_THORNS); - _phase = PHASE_TRANSFORM; + DoCastSelf(SPELL_EXPLODE); + DoCastSelf(SPELL_BURU_EGG_TRIGGER, true); + buru->CastSpell(buru, SPELL_CREATURE_SPECIAL, true); + if (buru->GetAI()) + buru->AI()->SetGUID(me->GetGUID()); } - - DoMeleeAttackIfReady(); } - private: - uint8 _phase; - GuidList Eggs; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); } +private: + InstanceScript* _instance; }; -class npc_buru_egg : public CreatureScript +class spell_egg_explosion : public SpellScript { -public: - npc_buru_egg() : CreatureScript("npc_buru_egg") { } + PrepareSpellScript(spell_egg_explosion); - struct npc_buru_eggAI : public ScriptedAI + void HandleDummyHitTarget(SpellEffIndex /*effIndex*/) { - npc_buru_eggAI(Creature* creature) : ScriptedAI(creature) + if (Unit* target = GetHitUnit()) { - _instance = me->GetInstanceScript(); - SetCombatMovement(false); + int32 damage = 0; + if (target->IsPlayer()) + damage = -16 * GetCaster()->GetDistance(target) + 500; + else if (target->GetEntry() == NPC_BURU && target->HasAura(SPELL_THORNS)) + damage = target->GetMaxHealth() * 7.f / 100; + + GetCaster()->CastCustomSpell(target, SPELL_EXPLODE_2, &damage, nullptr, nullptr, true); } - - void EnterCombat(Unit* attacker) override - { - if (Creature* buru = me->GetMap()->GetCreature(_instance->GetGuidData(DATA_BURU))) - if (!buru->IsInCombat()) - buru->AI()->AttackStart(attacker); - } - - void JustSummoned(Creature* who) override - { - if (who->GetEntry() == NPC_HATCHLING) - if (Creature* buru = me->GetMap()->GetCreature(_instance->GetGuidData(DATA_BURU))) - if (Unit* target = buru->AI()->SelectTarget(SelectTargetMethod::Random)) - who->AI()->AttackStart(target); - } - - void JustDied(Unit* /*killer*/) override - { - DoCastAOE(SPELL_EXPLODE, true); - DoCastAOE(SPELL_EXPLODE_2, true); // Unknown purpose - DoCast(me, SPELL_SUMMON_HATCHLING, true); - - if (Creature* buru = me->GetMap()->GetCreature(_instance->GetGuidData(DATA_BURU))) - if (boss_buru::boss_buruAI* buruAI = dynamic_cast(buru->AI())) - buruAI->ManageRespawn(me->GetGUID()); - } - private: - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); } -}; -class spell_egg_explosion : public SpellScriptLoader -{ -public: - spell_egg_explosion() : SpellScriptLoader("spell_egg_explosion") { } - - class spell_egg_explosion_SpellScript : public SpellScript + void Register() override { - PrepareSpellScript(spell_egg_explosion_SpellScript); - - void HandleAfterCast() - { - if (Creature* buru = GetCaster()->FindNearestCreature(NPC_BURU, 5.f)) - buru->AI()->DoAction(ACTION_EXPLODE); - } - - void HandleDummyHitTarget(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - Unit::DealDamage(GetCaster(), target, -16 * GetCaster()->GetDistance(target) + 500); - } - - void Register() override - { - AfterCast += SpellCastFn(spell_egg_explosion_SpellScript::HandleAfterCast); - OnEffectHitTarget += SpellEffectFn(spell_egg_explosion_SpellScript::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_egg_explosion_SpellScript(); + OnEffectHitTarget += SpellEffectFn(spell_egg_explosion::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY); } }; void AddSC_boss_buru() { - new boss_buru(); - new npc_buru_egg(); - new spell_egg_explosion(); + RegisterRuinsOfAhnQirajCreatureAI(boss_buru); + RegisterRuinsOfAhnQirajCreatureAI(npc_buru_egg); + RegisterSpellScript(spell_egg_explosion); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp index 6d4ab62d5..34619337a 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp @@ -16,121 +16,134 @@ */ #include "CreatureTextMgr.h" +#include "GameObjectAI.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "TaskScheduler.h" #include "ruins_of_ahnqiraj.h" enum Spells { - SPELL_MORTALWOUND = 25646, - SPELL_SANDTRAP = 25648, + SPELL_MORTAL_WOUND = 25646, + SPELL_SAND_TRAP = 25648, SPELL_ENRAGE = 26527, SPELL_SUMMON_PLAYER = 26446, - SPELL_TRASH = 3391, // Should perhaps be triggered by an aura? Couldn't find any though SPELL_WIDE_SLASH = 25814 }; enum Events { EVENT_MORTAL_WOUND = 1, - EVENT_SANDTRAP = 2, - EVENT_TRASH = 3, - EVENT_WIDE_SLASH = 4 + EVENT_SAND_TRAP = 2, + EVENT_WIDE_SLASH = 3 }; enum Texts { - SAY_KURINAXX_DEATH = 5, // Yelled by Ossirian the Unscarred + SAY_KURINNAXX_DEATH = 5 // Yell by 'Ossirian the Unscarred' }; -class boss_kurinnaxx : public CreatureScript +struct boss_kurinnaxx : public BossAI { -public: - boss_kurinnaxx() : CreatureScript("boss_kurinnaxx") { } + boss_kurinnaxx(Creature* creature) : BossAI(creature, DATA_KURINNAXX) {} - struct boss_kurinnaxxAI : public BossAI + void Reset() override { - boss_kurinnaxxAI(Creature* creature) : BossAI(creature, DATA_KURINNAXX) - { - } - - void Reset() override - { - _Reset(); - _enraged = false; - events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000); - events.ScheduleEvent(EVENT_SANDTRAP, urand(5000, 15000)); - events.ScheduleEvent(EVENT_TRASH, 1000); - events.ScheduleEvent(EVENT_WIDE_SLASH, 11000); - } - - void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override - { - if (!_enraged && HealthBelowPct(30)) - { - DoCast(me, SPELL_ENRAGE); - _enraged = true; - } - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - if (Creature* Ossirian = me->GetMap()->GetCreature(instance->GetGuidData(DATA_OSSIRIAN))) - sCreatureTextMgr->SendChat(Ossirian, SAY_KURINAXX_DEATH, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_MORTAL_WOUND: - DoCastVictim(SPELL_MORTALWOUND); - events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000); - break; - case EVENT_SANDTRAP: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - target->CastSpell(target, SPELL_SANDTRAP, true); - else if (Unit* victim = me->GetVictim()) - victim->CastSpell(victim, SPELL_SANDTRAP, true); - events.ScheduleEvent(EVENT_SANDTRAP, urand(5000, 15000)); - break; - case EVENT_WIDE_SLASH: - DoCast(me, SPELL_WIDE_SLASH); - events.ScheduleEvent(EVENT_WIDE_SLASH, 11000); - break; - case EVENT_TRASH: - DoCast(me, SPELL_TRASH); - events.ScheduleEvent(EVENT_WIDE_SLASH, 16000); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - private: - bool _enraged; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); + BossAI::Reset(); + _enraged = false; + events.ScheduleEvent(EVENT_MORTAL_WOUND, 8s, 10s); + events.ScheduleEvent(EVENT_SAND_TRAP, 5s, 15s); + events.ScheduleEvent(EVENT_WIDE_SLASH, 10s, 15s); } + + void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + { + if (!_enraged && HealthBelowPct(30)) + { + DoCastSelf(SPELL_ENRAGE); + _enraged = true; + } + } + + void JustDied(Unit* killer) override + { + if (killer) + killer->GetMap()->LoadGrid(-9502.80f, 2042.65f); // Ossirian grid + + if (Creature* ossirian = instance->GetCreature(DATA_OSSIRIAN)) + { + ossirian->setActive(true); + if (ossirian->GetAI()) + ossirian->AI()->Talk(SAY_KURINNAXX_DEATH); + } + BossAI::JustDied(killer); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MORTAL_WOUND: + DoCastVictim(SPELL_MORTAL_WOUND); + events.ScheduleEvent(EVENT_MORTAL_WOUND, 8s, 10s); + break; + case EVENT_SAND_TRAP: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.f, true)) + { + target->CastSpell(target, SPELL_SAND_TRAP, true, nullptr, nullptr, me->GetGUID()); + } + events.ScheduleEvent(EVENT_SAND_TRAP, 5s, 15s); + break; + case EVENT_WIDE_SLASH: + DoCastSelf(SPELL_WIDE_SLASH); + events.ScheduleEvent(EVENT_WIDE_SLASH, 12s, 15s); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } +private: + bool _enraged; +}; + +struct go_sand_trap : public GameObjectAI +{ + go_sand_trap(GameObject* go) : GameObjectAI(go) { } + + void Reset() override + { + _scheduler.Schedule(5s, [this](TaskContext /*context*/) + { + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* kurinnaxx = instance->GetCreature(DATA_KURINNAXX)) + me->Use(kurinnaxx); + }); + } + + void UpdateAI(uint32 const diff) override + { + _scheduler.Update(diff); + } + +protected: + TaskScheduler _scheduler; }; void AddSC_boss_kurinnaxx() { - new boss_kurinnaxx(); + RegisterRuinsOfAhnQirajCreatureAI(boss_kurinnaxx); + RegisterGameObjectAI(go_sand_trap); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp index f38bfd8e0..a4f70a104 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp @@ -15,173 +15,180 @@ * with this program. If not, see . */ +#include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "ruins_of_ahnqiraj.h" enum Texts { - EMOTE_AGGRO = 0, - EMOTE_MANA_FULL = 1 + EMOTE_AGGRO = 0, + EMOTE_MANA_FULL = 1, + EMOTE_STONE_PHASE = 2 }; enum Spells { SPELL_TRAMPLE = 15550, + SPELL_DRAIN_MANA_SERVERSIDE = 25676, SPELL_DRAIN_MANA = 25671, SPELL_ARCANE_ERUPTION = 25672, + SPELL_SUMMON_MANA_FIENDS = 25684, SPELL_SUMMON_MANA_FIEND_1 = 25681, // TARGET_DEST_CASTER_FRONT SPELL_SUMMON_MANA_FIEND_2 = 25682, // TARGET_DEST_CASTER_LEFT SPELL_SUMMON_MANA_FIEND_3 = 25683, // TARGET_DEST_CASTER_RIGHT - SPELL_ENERGIZE = 25685 + SPELL_ENERGIZE = 25685, + + SPELL_LARGE_OBSIDIAN_CHUNK = 27630 // Server-side }; enum Events { - EVENT_TRAMPLE = 1, - EVENT_DRAIN_MANA = 2, - EVENT_STONE_PHASE = 3, - EVENT_STONE_PHASE_END = 4, - EVENT_WIDE_SLASH = 5, + EVENT_SPELL_TRAMPLE = 1, + EVENT_SPELL_DRAIN_MANA = 2, + EVENT_STONE_PHASE = 3, + EVENT_STONE_PHASE_END = 4 }; -enum Actions +struct boss_moam : public BossAI { - ACTION_STONE_PHASE_START = 1, - ACTION_STONE_PHASE_END = 2, -}; + boss_moam(Creature* creature) : BossAI(creature, DATA_MOAM) {} -class boss_moam : public CreatureScript -{ -public: - boss_moam() : CreatureScript("boss_moam") { } - - struct boss_moamAI : public BossAI + void Reset() override { - boss_moamAI(Creature* creature) : BossAI(creature, DATA_MOAM) - { - } + _Reset(); + me->SetPower(POWER_MANA, 0); + me->SetRegeneratingPower(false); + } - void Reset() override - { - _Reset(); - me->SetPower(POWER_MANA, 0); - _isStonePhase = false; - events.ScheduleEvent(EVENT_STONE_PHASE, 90000); - //events.ScheduleEvent(EVENT_WIDE_SLASH, 11000); - } + void EnterCombat(Unit* who) override + { + BossAI::EnterCombat(who); + Talk(EMOTE_AGGRO); + events.ScheduleEvent(EVENT_STONE_PHASE, 90000); + events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9000); + events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3000); + } - void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + DoCastAOE(SPELL_LARGE_OBSIDIAN_CHUNK, true); + } + + void SummonedCreatureDies(Creature* /*creature*/, Unit* /*killer*/) override + { + if (!summons.IsAnyCreatureAlive() && me->HasAura(SPELL_ENERGIZE)) { - if (!_isStonePhase && HealthBelowPct(45)) + events.RescheduleEvent(EVENT_STONE_PHASE_END, 1s); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA)) + { + if (me->HasAura(SPELL_ENERGIZE)) { - _isStonePhase = true; - DoAction(ACTION_STONE_PHASE_START); + me->RemoveAurasDueToSpell(SPELL_ENERGIZE); + events.RescheduleEvent(EVENT_STONE_PHASE_END, 1s); } + + Talk(EMOTE_MANA_FULL); + DoCastAOE(SPELL_ARCANE_ERUPTION); } - void DoAction(int32 action) override + while (uint32 eventId = events.ExecuteEvent()) { - switch (action) + switch (eventId) { - case ACTION_STONE_PHASE_END: - { - me->RemoveAurasDueToSpell(SPELL_ENERGIZE); - events.ScheduleEvent(EVENT_STONE_PHASE, 90000); - _isStonePhase = false; - break; - } - case ACTION_STONE_PHASE_START: - { - DoCast(me, SPELL_SUMMON_MANA_FIEND_1); - DoCast(me, SPELL_SUMMON_MANA_FIEND_2); - DoCast(me, SPELL_SUMMON_MANA_FIEND_3); - DoCast(me, SPELL_ENERGIZE); - events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000); - break; - } + case EVENT_STONE_PHASE: + Talk(EMOTE_STONE_PHASE); + DoCastAOE(SPELL_SUMMON_MANA_FIENDS); + DoCastSelf(SPELL_ENERGIZE); + events.CancelEvent(EVENT_SPELL_DRAIN_MANA); + events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000); + break; + case EVENT_STONE_PHASE_END: + me->RemoveAurasDueToSpell(SPELL_ENERGIZE); + events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000)); + events.ScheduleEvent(EVENT_STONE_PHASE, 90000); + break; + case EVENT_SPELL_DRAIN_MANA: + DoCastAOE(SPELL_DRAIN_MANA_SERVERSIDE); + events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000)); + break; + case EVENT_SPELL_TRAMPLE: + DoCastAOE(SPELL_TRAMPLE); + events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15000); + break; default: break; } } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + DoMeleeAttackIfReady(); + } +}; - events.Update(diff); +// 25676 - Drain Mana (server-side) +class spell_moam_mana_drain_filter : public SpellScript +{ + PrepareSpellScript(spell_moam_mana_drain_filter); - if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA)) - { - if (_isStonePhase) - DoAction(ACTION_STONE_PHASE_END); - DoCastAOE(SPELL_ARCANE_ERUPTION); - me->SetPower(POWER_MANA, 0); - } - - if (_isStonePhase) - { - if (events.ExecuteEvent() == EVENT_STONE_PHASE_END) - DoAction(ACTION_STONE_PHASE_END); - return; - } - - // Messing up mana-drain channel - //if (me->HasUnitState(UNIT_STATE_CASTING)) - // return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_STONE_PHASE: - DoAction(ACTION_STONE_PHASE_START); - break; - case EVENT_DRAIN_MANA: - { - std::list targetList; - { - const std::list& threatlist = me->GetThreatMgr().getThreatList(); - for (std::list::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) - if ((*itr)->getTarget()->GetTypeId() == TYPEID_PLAYER && (*itr)->getTarget()->getPowerType() == POWER_MANA) - targetList.push_back((*itr)->getTarget()); - } - - Acore::Containers::RandomResize(targetList, 5); - - for (std::list::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) - DoCast(*itr, SPELL_DRAIN_MANA); - - events.ScheduleEvent(EVENT_DRAIN_MANA, urand(5000, 15000)); - break; - }/* - case EVENT_WIDE_SLASH: - DoCast(me, SPELL_WIDE_SLASH); - events.ScheduleEvent(EVENT_WIDE_SLASH, 11000); - break; - case EVENT_TRASH: - DoCast(me, SPELL_TRASH); - events.ScheduleEvent(EVENT_WIDE_SLASH, 16000); - break;*/ - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - private: - bool _isStonePhase; - }; - - CreatureAI* GetAI(Creature* creature) const override + void FilterTargets(std::list& targets) { - return GetRuinsOfAhnQirajAI(creature); + targets.remove_if([&](WorldObject* target) -> bool + { + return !target->IsPlayer() || target->ToPlayer()->getPowerType() != POWER_MANA; + }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + caster->CastSpell(GetHitUnit(), SPELL_DRAIN_MANA, true); + } + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_mana_drain_filter::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_moam_mana_drain_filter::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// 25684 - Summon Mana Fiends (server-side) +class spell_moam_summon_mana_fiends : public SpellScript +{ + PrepareSpellScript(spell_moam_summon_mana_fiends); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + const uint32 spellIds[3] = { SPELL_SUMMON_MANA_FIEND_1, SPELL_SUMMON_MANA_FIEND_2, SPELL_SUMMON_MANA_FIEND_3 }; + + for (uint32 spellId : spellIds) + { + GetCaster()->CastSpell((Unit*)nullptr, spellId, true); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_moam_summon_mana_fiends::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; void AddSC_boss_moam() { - new boss_moam(); + RegisterRuinsOfAhnQirajCreatureAI(boss_moam); + RegisterSpellScript(spell_moam_mana_drain_filter); + RegisterSpellScript(spell_moam_summon_mana_fiends); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp index af994f8b8..bfa85bc52 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp @@ -22,255 +22,248 @@ #include "ScriptedCreature.h" #include "SpellInfo.h" #include "ruins_of_ahnqiraj.h" +#include "TaskScheduler.h" enum Texts { - SAY_SUPREME = 0, - SAY_INTRO = 1, - SAY_AGGRO = 2, - SAY_SLAY = 3, - SAY_DEATH = 4 + SAY_SUPREME = 0, + SAY_INTRO = 1, + SAY_AGGRO = 2, + SAY_SLAY = 3, + SAY_DEATH = 4 }; enum Spells { - SPELL_SILENCE = 25195, - SPELL_CYCLONE = 25189, - SPELL_STOMP = 25188, - SPELL_SUPREME = 25176, - SPELL_SUMMON = 20477, - SPELL_SAND_STORM = 25160, - SPELL_SUMMON_CRYSTAL = 25192 + SPELL_CURSE_OF_TONGUES = 25195, + SPELL_ENVELOPING_WINDS = 25189, + SPELL_WAR_STOMP = 25188, + SPELL_STRENGHT_OF_OSSIRIAN = 25176, + SPELL_SAND_STORM = 25160, + SPELL_SUMMON_CRYSTAL = 25192 }; enum Actions { - ACTION_TRIGGER_WEAKNESS = 1 + ACTION_TRIGGER_WEAKNESS = 1 }; enum Events { - EVENT_SILENCE = 1, - EVENT_CYCLONE = 2, - EVENT_STOMP = 3 + EVENT_SILENCE = 1, + EVENT_CYCLONE = 2, + EVENT_STOMP = 3 }; uint8 const NUM_CRYSTALS = 9; - -// You spin me right round, baby -// right round like a record, baby -// right round round round Position CrystalCoordinates[NUM_CRYSTALS] = { - { -9394.230469f, 1951.808594f, 85.97733f, 0.0f }, + { -9394.230469f, 1951.808594f, 85.97733f, 0.0f }, { -9357.931641f, 1930.596802f, 85.556198f, 0.0f }, { -9383.113281f, 2011.042725f, 85.556389f, 0.0f }, - { -9243.36f, 1979.04f, 85.556f, 0.0f }, - { -9281.68f, 1886.66f, 85.5558f, 0.0f }, - { -9241.8f, 1806.39f, 85.5557f, 0.0f }, - { -9366.78f, 1781.76f, 85.5561f, 0.0f }, - { -9430.37f, 1786.86f, 85.557f, 0.0f }, - { -9406.73f, 1863.13f, 85.5558f, 0.0f } + { -9243.36f, 1979.04f, 85.556f, 0.0f }, + { -9281.68f, 1886.66f, 85.5558f, 0.0f }, + { -9241.8f, 1806.39f, 85.5557f, 0.0f }, + { -9366.78f, 1781.76f, 85.5561f, 0.0f }, + { -9430.37f, 1786.86f, 85.557f, 0.0f }, + { -9406.73f, 1863.13f, 85.5558f, 0.0f } }; -float RoomRadius = 165.0f; -uint8 const NUM_TORNADOS = 5; /// @todo This number is completly random! +float roomRadius = 165.0f; +uint8 const NUM_TORNADOS = 2; uint8 const NUM_WEAKNESS = 5; -uint32 const SpellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 }; +uint32 const spellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 }; Position const RoomCenter = { -9343.041992f, 1923.278198f, 85.555984f, 0.0 }; -class boss_ossirian : public CreatureScript +struct boss_ossirian : public BossAI { -public: - boss_ossirian() : CreatureScript("boss_ossirian") { } - - struct boss_ossirianAI : public BossAI + boss_ossirian(Creature* creature) : BossAI(creature, DATA_OSSIRIAN) { - boss_ossirianAI(Creature* creature) : BossAI(creature, DATA_OSSIRIAN) - { - SaidIntro = false; - } - - ObjectGuid TriggerGUID; - ObjectGuid CrystalGUID; - uint8 CrystalIterator; - bool SaidIntro; - - void Reset() override - { - _Reset(); - CrystalIterator = 0; - TriggerGUID.Clear(); - CrystalGUID.Clear(); - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - for (uint8 i = 0; i < NUM_WEAKNESS; ++i) - { - if (spell->Id == SpellWeakness[i]) - { - me->RemoveAurasDueToSpell(SPELL_SUPREME); - ((TempSummon*)caster)->UnSummon(); - SpawnNextCrystal(); - } - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_TRIGGER_WEAKNESS) - if (Creature* Trigger = me->GetMap()->GetCreature(TriggerGUID)) - if (!Trigger->HasUnitState(UNIT_STATE_CASTING)) - Trigger->CastSpell(Trigger, SpellWeakness[urand(0, 4)], false); - } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - events.Reset(); - events.ScheduleEvent(EVENT_SILENCE, 30000); - events.ScheduleEvent(EVENT_CYCLONE, 20000); - events.ScheduleEvent(EVENT_STOMP, 30000); - - DoCast(me, SPELL_SUPREME); - Talk(SAY_AGGRO); - - Map* map = me->GetMap(); - if (!map->IsDungeon()) - return; - - WorldPackets::Misc::Weather weather(WEATHER_STATE_HEAVY_SANDSTORM, 1.0f); - map->SendToPlayers(weather.Write()); - - for (uint8 i = 0; i < NUM_TORNADOS; ++i) - { - Position Point = me->GetRandomPoint(RoomCenter, RoomRadius); - if (Creature* Tornado = me->GetMap()->SummonCreature(NPC_SAND_VORTEX, Point)) - Tornado->CastSpell(Tornado, SPELL_SAND_STORM, true); - } - - SpawnNextCrystal(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason why) override - { - Cleanup(); - summons.DespawnAll(); - BossAI::EnterEvadeMode(why); - } - - void JustDied(Unit* /*killer*/) override - { - Cleanup(); - _JustDied(); - } - - void Cleanup() - { - if (GameObject* Crystal = me->GetMap()->GetGameObject(CrystalGUID)) - Crystal->Use(me); - } - - void SpawnNextCrystal() - { - if (CrystalIterator == NUM_CRYSTALS) - CrystalIterator = 0; - - if (Creature* Trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[CrystalIterator])) - { - TriggerGUID = Trigger->GetGUID(); - if (GameObject* Crystal = Trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL, - CrystalCoordinates[CrystalIterator].GetPositionX(), - CrystalCoordinates[CrystalIterator].GetPositionY(), - CrystalCoordinates[CrystalIterator].GetPositionZ(), - 0, 0, 0, 0, 0, uint32(-1))) - { - CrystalGUID = Crystal->GetGUID(); - ++CrystalIterator; - Crystal->SetOwnerGUID(ObjectGuid::Empty); - } - } - } - - void MoveInLineOfSight(Unit* who) override - - { - if (!SaidIntro) - { - Talk(SAY_INTRO); - SaidIntro = true; - } - BossAI::MoveInLineOfSight(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - // No kiting! - if (me->GetDistance(me->GetVictim()) > 60.00f && me->GetDistance(me->GetVictim()) < 120.00f) - DoCastVictim(SPELL_SUMMON); - - bool ApplySupreme = true; - - if (me->HasAura(SPELL_SUPREME)) - ApplySupreme = false; - else - { - for (uint8 i = 0; i < NUM_WEAKNESS; ++i) - { - if (me->HasAura(SpellWeakness[i])) - { - ApplySupreme = false; - break; - } - } - } - - if (ApplySupreme) - { - DoCast(me, SPELL_SUPREME); - Talk(SAY_SUPREME); - } - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SILENCE: - DoCast(me, SPELL_SILENCE); - events.ScheduleEvent(EVENT_SILENCE, urand(20000, 30000)); - break; - case EVENT_CYCLONE: - DoCastVictim(SPELL_CYCLONE); - events.ScheduleEvent(EVENT_CYCLONE, 20000); - break; - case EVENT_STOMP: - DoCast(me, SPELL_STOMP); - events.ScheduleEvent(EVENT_STOMP, 30000); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); + _saidIntro = false; } + + void Reset() override + { + BossAI::Reset(); + _crystalIterator = 0; + _triggerGUID.Clear(); + _crystalGUID.Clear(); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + for (uint8 weakness : spellWeakness) + { + if (spell->Id == weakness) + { + me->RemoveAurasDueToSpell(SPELL_STRENGHT_OF_OSSIRIAN); + ((TempSummon*)caster)->UnSummon(); + SpawnNextCrystal(); + } + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_TRIGGER_WEAKNESS) + { + if (Creature* trigger = me->GetMap()->GetCreature(_triggerGUID)) + { + if (!trigger->HasUnitState(UNIT_STATE_CASTING)) + { + trigger->CastSpell(trigger, spellWeakness[urand(0, 4)], false); + } + } + } + } + + void EnterCombat(Unit* who) override + { + BossAI::EnterCombat(who); + events.Reset(); + events.ScheduleEvent(EVENT_SILENCE, 30s); + events.ScheduleEvent(EVENT_CYCLONE, 20s); + events.ScheduleEvent(EVENT_STOMP, 30s); + DoCastSelf(SPELL_STRENGHT_OF_OSSIRIAN); + Talk(SAY_AGGRO); + + Map* map = me->GetMap(); + if (!map->IsDungeon()) + return; + + WorldPackets::Misc::Weather weather(WEATHER_STATE_HEAVY_SANDSTORM, 1.0f); + map->SendToPlayers(weather.Write()); + for (uint8 i = 0; i < NUM_TORNADOS; ++i) + { + Position Point = me->GetRandomPoint(RoomCenter, roomRadius); + if (Creature* Tornado = me->GetMap()->SummonCreature(NPC_SAND_VORTEX, Point)) + { + Tornado->CastSpell(Tornado, SPELL_SAND_STORM, true); + } + } + SpawnNextCrystal(); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } + + void EnterEvadeMode(EvadeReason why) override + { + Cleanup(); + summons.DespawnAll(); + BossAI::EnterEvadeMode(why); + } + + void JustDied(Unit* killer) override + { + Cleanup(); + BossAI::JustDied(killer); + } + + void Cleanup() + { + if (GameObject* crystal = me->GetMap()->GetGameObject(_crystalGUID)) + { + crystal->Use(me); + } + + std::list vortexes; + me->GetCreaturesWithEntryInRange(vortexes, 200.f, NPC_SAND_VORTEX); + for (Creature* vortex : vortexes) + vortex->DespawnOrUnsummon(); + } + + void SpawnNextCrystal() + { + if (_crystalIterator == NUM_CRYSTALS) + _crystalIterator = 0; + + if (Creature* trigger = me->GetMap()->SummonCreature(NPC_OSSIRIAN_TRIGGER, CrystalCoordinates[_crystalIterator])) + { + _triggerGUID = trigger->GetGUID(); + if (GameObject* crystal = trigger->SummonGameObject(GO_OSSIRIAN_CRYSTAL, + CrystalCoordinates[_crystalIterator].GetPositionX(), + CrystalCoordinates[_crystalIterator].GetPositionY(), + CrystalCoordinates[_crystalIterator].GetPositionZ(), + 0, 0, 0, 0, 0, uint32(-1))) + { + _crystalGUID = crystal->GetGUID(); + ++_crystalIterator; + crystal->SetOwnerGUID(ObjectGuid::Empty); + } + } + } + + void MoveInLineOfSight(Unit* who) override + + { + if (!_saidIntro) + { + Talk(SAY_INTRO); + _saidIntro = true; + } + BossAI::MoveInLineOfSight(who); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + bool applySupreme = true; + if (me->HasAura(SPELL_STRENGHT_OF_OSSIRIAN)) + { + applySupreme = false; + } + else + { + for (uint8 weakness : spellWeakness) + { + if (me->HasAura(weakness)) + { + applySupreme = false; + break; + } + } + } + + if (applySupreme) + { + DoCastSelf(SPELL_STRENGHT_OF_OSSIRIAN); + Talk(SAY_SUPREME); + } + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SILENCE: + DoCastAOE(SPELL_CURSE_OF_TONGUES); + events.ScheduleEvent(EVENT_SILENCE, 20s, 30s); + break; + case EVENT_CYCLONE: + DoCastVictim(SPELL_ENVELOPING_WINDS); + events.ScheduleEvent(EVENT_CYCLONE, 20s); + break; + case EVENT_STOMP: + DoCastAOE(SPELL_WAR_STOMP); + events.ScheduleEvent(EVENT_STOMP, 30s); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + +protected: + ObjectGuid _triggerGUID; + ObjectGuid _crystalGUID; + uint8 _crystalIterator; + bool _saidIntro; }; class go_ossirian_crystal : public GameObjectScript @@ -280,21 +273,99 @@ public: bool OnGossipHello(Player* player, GameObject* /*go*/) override { - InstanceScript* Instance = player->GetInstanceScript(); - if (!Instance) + InstanceScript* instance = player->GetInstanceScript(); + if (!instance) return false; - Creature* Ossirian = player->FindNearestCreature(NPC_OSSIRIAN, 30.0f); - if (!Ossirian || Instance->GetBossState(DATA_OSSIRIAN) != IN_PROGRESS) + Creature* ossirian = instance->GetCreature(DATA_OSSIRIAN); + if (!ossirian || instance->GetBossState(DATA_OSSIRIAN) != IN_PROGRESS) return false; - Ossirian->AI()->DoAction(ACTION_TRIGGER_WEAKNESS); + ossirian->AI()->DoAction(ACTION_TRIGGER_WEAKNESS); return true; } }; +enum AnubisathGuardian +{ + SPELL_METEOR = 24340, + SPELL_PLAGUE = 22997, + SPELL_SHADOW_STORM = 2148, + SPELL_THUNDER_CLAP = 2834, + SPELL_REFLECT_ARCANE_FIRE = 13022, + SPELL_REFLECT_FROST_SHADOW = 19595, + SPELL_ENRAGE = 8599, + SPELL_EXPLODE = 25698, + + SPELL_SUMMON_ANUB_SWARMGUARD = 17430, + SPELL_SUMMON_ANUB_WARRIOR = 17431, +}; + +struct npc_anubisath_guardian : public ScriptedAI +{ + npc_anubisath_guardian(Creature* creature) : ScriptedAI(creature) + { + _spells[0] = RAND(SPELL_SHADOW_STORM, SPELL_THUNDER_CLAP); + _spells[1] = RAND(SPELL_REFLECT_ARCANE_FIRE, SPELL_REFLECT_FROST_SHADOW); + } + + void Reset() override + { + _enraged = false; + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + void EnterCombat(Unit* /*who*/) override + { + DoCastSelf(_spells[0]); + DoCastSelf(_spells[1]); + + _scheduler.CancelAll(); + + uint32 spell = RAND(SPELL_METEOR, SPELL_PLAGUE); + _scheduler.Schedule(10s, [this, spell](TaskContext context) { + DoCastRandomTarget(spell); + context.Repeat(10s, 15s); + }); + + spell = RAND(SPELL_SUMMON_ANUB_SWARMGUARD, SPELL_SUMMON_ANUB_WARRIOR); + _scheduler.Schedule(10s, [this, spell](TaskContext context) { + DoCastAOE(spell); + context.Repeat(10s, 15s); + }); + } + + void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /* damagetype */, SpellSchoolMask /*damageSchoolMask*/) override + { + if (!_enraged && me->HealthBelowPctDamaged(10, damage)) + { + _enraged = true; + DoCastSelf(RAND(SPELL_ENRAGE, SPELL_EXPLODE), true); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); + } + +private: + bool _enraged; + uint32 _spells[2]; + TaskScheduler _scheduler; +}; + void AddSC_boss_ossirian() { - new boss_ossirian(); + RegisterRuinsOfAhnQirajCreatureAI(boss_ossirian); new go_ossirian_crystal(); + RegisterCreatureAI(npc_anubisath_guardian); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp index d9587d28e..2c648dfb0 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp @@ -22,16 +22,6 @@ enum Yells { - // The time of our retribution is at hand! Let darkness reign in the hearts of our enemies! Sound: 8645 Emote: 35 - SAY_ANDOROV_INTRO = 0, // Before for the first wave - SAY_ANDOROV_ATTACK = 1, // Beginning the event - - SAY_WAVE3 = 0, - SAY_WAVE4 = 1, - SAY_WAVE5 = 2, - SAY_WAVE6 = 3, - SAY_WAVE7 = 4, - SAY_INTRO = 5, SAY_UNK1 = 6, SAY_UNK2 = 7, SAY_UNK3 = 8, @@ -63,27 +53,25 @@ public: struct boss_rajaxxAI : public BossAI { - boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX) - { - } + boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX) { } void Reset() override { _Reset(); enraged = false; - events.ScheduleEvent(EVENT_DISARM, 10000); - events.ScheduleEvent(EVENT_THUNDERCRASH, 12000); } void JustDied(Unit* /*killer*/) override { - //SAY_DEATH + Talk(SAY_DEATH); _JustDied(); } void EnterCombat(Unit* /*victim*/) override { _EnterCombat(); + events.ScheduleEvent(EVENT_DISARM, 10000); + events.ScheduleEvent(EVENT_THUNDERCRASH, 12000); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp index 5cb1e8373..aa088d091 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp @@ -15,10 +15,49 @@ * with this program. If not, see . */ +#include "CreatureGroups.h" #include "InstanceScript.h" #include "ScriptMgr.h" +#include "TaskScheduler.h" #include "ruins_of_ahnqiraj.h" +ObjectData const creatureData[] = +{ + { NPC_BURU, DATA_BURU }, + { NPC_KURINNAXX, DATA_KURINNAXX }, + { NPC_RAJAXX, DATA_RAJAXX }, + { NPC_OSSIRIAN, DATA_OSSIRIAN }, + { NPC_QUUEZ, DATA_QUUEZ }, + { NPC_TUUBID, DATA_TUUBID }, + { NPC_DRENN, DATA_DRENN }, + { NPC_XURREM, DATA_XURREM }, + { NPC_YEGGETH, DATA_YEGGETH }, + { NPC_PAKKON, DATA_PAKKON }, + { NPC_ZERRAN, DATA_ZERRAN }, +}; + +enum RajaxxText +{ + SAY_WAVE3 = 0, + SAY_WAVE4 = 1, + SAY_WAVE5 = 2, + SAY_WAVE6 = 3, + SAY_WAVE7 = 4, + SAY_ENGAGE = 5 +}; + +std::array RajaxxWavesData[] = +{ + { DATA_QUUEZ, 0 }, + { DATA_TUUBID, 0 }, + { DATA_DRENN, SAY_WAVE3 }, + { DATA_XURREM, SAY_WAVE4 }, + { DATA_YEGGETH, SAY_WAVE5 }, + { DATA_PAKKON, SAY_WAVE6 }, + { DATA_ZERRAN, SAY_WAVE7 }, + { DATA_RAJAXX, SAY_ENGAGE } +}; + class instance_ruins_of_ahnqiraj : public InstanceMapScript { public: @@ -29,14 +68,18 @@ public: instance_ruins_of_ahnqiraj_InstanceMapScript(Map* map) : InstanceScript(map) { SetBossNumber(NUM_ENCOUNTER); + LoadObjectData(creatureData, nullptr); + _rajaxWaveCounter = 0; } void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + switch (creature->GetEntry()) { - case NPC_KURINAXX: - _kurinaxxGUID = creature->GetGUID(); + case NPC_KURINNAXX: + _kurinnaxxGUID = creature->GetGUID(); break; case NPC_RAJAXX: _rajaxxGUID = creature->GetGUID(); @@ -56,12 +99,73 @@ public: } } - bool SetBossState(uint32 bossId, EncounterState state) override + void OnCreatureEvade(Creature* creature) override { - if (!InstanceScript::SetBossState(bossId, state)) - return false; + if (CreatureGroup* formation = creature->GetFormation()) + { + if (Creature* leader = formation->GetLeader()) + { + switch (leader->GetEntry()) + { + case NPC_QUUEZ: + case NPC_TUUBID: + case NPC_DRENN: + case NPC_XURREM: + case NPC_YEGGETH: + case NPC_PAKKON: + case NPC_ZERRAN: + if (!formation->IsFormationInCombat()) + { + ResetRajaxxWaves(); + } + break; + default: + break; + } + } + } + else if (creature->GetEntry() == NPC_RAJAXX) + { + ResetRajaxxWaves(); + } + } - return true; + void OnUnitDeath(Unit* unit) override + { + if (Creature* creature = unit->ToCreature()) + { + if (CreatureGroup* formation = creature->GetFormation()) + { + if (Creature* leader = formation->GetLeader()) + { + switch (leader->GetEntry()) + { + case NPC_QUUEZ: + case NPC_TUUBID: + case NPC_DRENN: + case NPC_XURREM: + case NPC_YEGGETH: + case NPC_PAKKON: + case NPC_ZERRAN: + _scheduler.CancelAll(); + _scheduler.Schedule(1s, [this, formation](TaskContext /*context*/) { + if (!formation->IsAnyMemberAlive()) + { + CallNextRajaxxLeader(); + } + }); + break; + default: + break; + } + } + } + } + } + + void Update(uint32 diff) override + { + _scheduler.Update(diff); } void SetGuidData(uint32 type, ObjectGuid data) override @@ -75,7 +179,7 @@ public: switch (type) { case DATA_KURINNAXX: - return _kurinaxxGUID; + return _kurinnaxxGUID; case DATA_RAJAXX: return _rajaxxGUID; case DATA_MOAM: @@ -136,14 +240,56 @@ public: OUT_LOAD_INST_DATA_COMPLETE; } + void CallNextRajaxxLeader() + { + ++_rajaxWaveCounter; + + if (Creature* nextLeader = GetCreature(RajaxxWavesData[_rajaxWaveCounter].at(0))) + { + if (_rajaxWaveCounter >= 2) + { + if (Creature* rajaxx = GetCreature(DATA_RAJAXX)) + { + rajaxx->AI()->Talk(RajaxxWavesData[_rajaxWaveCounter].at(1)); + } + } + + if (nextLeader->IsAlive()) + { + nextLeader->SetInCombatWithZone(); + } + else + { + CallNextRajaxxLeader(); + } + } + } + + void ResetRajaxxWaves() + { + _rajaxWaveCounter = 0; + for (auto const& data : RajaxxWavesData) + { + if (Creature* creature = GetCreature(data.at(0))) + { + if (CreatureGroup* group = creature->GetFormation()) + { + group->RespawnFormation(true); + } + } + } + } + private: - ObjectGuid _kurinaxxGUID; + ObjectGuid _kurinnaxxGUID; ObjectGuid _rajaxxGUID; ObjectGuid _moamGUID; ObjectGuid _buruGUID; ObjectGuid _ayamissGUID; ObjectGuid _ossirianGUID; ObjectGuid _paralyzedGUID; + uint32 _rajaxWaveCounter; + TaskScheduler _scheduler; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h index b735b1e9b..522b70c78 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h @@ -32,12 +32,22 @@ enum DataTypes DATA_OSSIRIAN = 5, NUM_ENCOUNTER = 6, - DATA_PARALYZED = 7 + DATA_PARALYZED = 7, + + DATA_QUUEZ = 8, + DATA_TUUBID = 9, + DATA_DRENN = 10, + DATA_XURREM = 11, + DATA_YEGGETH = 12, + DATA_PAKKON = 13, + DATA_ZERRAN = 14, + + DATA_ENGAGED_FORMATION = 1 }; enum Creatures { - NPC_KURINAXX = 15348, + NPC_KURINNAXX = 15348, NPC_RAJAXX = 15341, NPC_MOAM = 15340, NPC_BURU = 15370, @@ -49,9 +59,19 @@ enum Creatures NPC_SAND_VORTEX = 15428, NPC_OSSIRIAN_TRIGGER = 15590, NPC_HATCHLING = 15521, + NPC_BURU_EGG = 15514, NPC_LARVA = 15555, NPC_SWARMER = 15546, - NPC_HORNET = 15934 + NPC_HORNET = 15934, + + // Rajaxx + NPC_QUUEZ = 15391, + NPC_TUUBID = 15392, + NPC_DRENN = 15389, + NPC_XURREM = 15390, + NPC_YEGGETH = 15386, + NPC_PAKKON = 15388, + NPC_ZERRAN = 15385 }; enum GameObjects @@ -65,4 +85,6 @@ inline AI* GetRuinsOfAhnQirajAI(T* obj) return GetInstanceAI(obj, RuinsOfAhnQirajScriptName); } +#define RegisterRuinsOfAhnQirajCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetRuinsOfAhnQirajAI) + #endif diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index cffb86012..66211a1b0 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -195,6 +195,18 @@ public: instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM); } + void MoveInLineOfSight(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER && !me->IsInCombat()) + { + // Z checks are necessary here because AQ maps do funky stuff. + if (me->IsWithinLOSInMap(who) && me->IsWithinDist2d(who, 50.0f) && who->GetPositionZ() > 100.0f) + { + AttackStart(who); + } + } + } + void DoAction(int32 action) override { if (action == ACTION_SPAWN_EYE_TENTACLES) @@ -367,6 +379,7 @@ public: me->InterruptNonMeleeSpells(true); me->RemoveAllAuras(); + _scheduler.CancelAll(); break; case PHASE_CTHUN_DONE: @@ -819,13 +832,11 @@ public: } } - void DoAction(int32 param) override + void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override { - switch (param) + if (creature->GetEntry() == NPC_FLESH_TENTACLE) { - case ACTION_FLESH_TENTACLE_KILLED: - ++FleshTentaclesKilled; - break; + ++FleshTentaclesKilled; } } }; @@ -1178,33 +1189,6 @@ public: }; }; -class npc_giant_flesh_tentacle : public CreatureScript -{ -public: - npc_giant_flesh_tentacle() : CreatureScript("npc_giant_flesh_tentacle") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new flesh_tentacleAI(creature); - } - - struct flesh_tentacleAI : public ScriptedAI - { - flesh_tentacleAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); - } - - void JustDied(Unit* /*killer*/) override - { - if (TempSummon* summon = me->ToTempSummon()) - if (Unit* summoner = summon->GetSummonerUnit()) - if (summoner->IsAIEnabled) - summoner->GetAI()->DoAction(ACTION_FLESH_TENTACLE_KILLED); - } - }; -}; - //GetAIs void AddSC_boss_cthun() @@ -1215,5 +1199,4 @@ void AddSC_boss_cthun() new npc_claw_tentacle(); new npc_giant_claw_tentacle(); new npc_giant_eye_tentacle(); - new npc_giant_flesh_tentacle(); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp index e7fd78ea6..fdd08243b 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp @@ -24,6 +24,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "TaskScheduler.h" #include "temple_of_ahnqiraj.h" #define SOUND_SENTENCE_YOU 8588 @@ -34,7 +35,7 @@ EndScriptData */ enum Spells { - SPELL_MORTAL_WOUND = 28467, + SPELL_MORTAL_WOUND = 25646, SPELL_ROOT = 28858, // Enrage for his spawns @@ -55,28 +56,8 @@ public: { boss_fankrissAI(Creature* creature) : ScriptedAI(creature) { } - uint32 MortalWound_Timer; - uint32 SpawnHatchlings_Timer; - uint32 SpawnSpawns_Timer; - int Rand; - float RandX; - float RandY; - - Creature* Hatchling; - Creature* Spawn; - - void Reset() override + void SummonSpawn() { - MortalWound_Timer = urand(10000, 15000); - SpawnHatchlings_Timer = urand(6000, 12000); - SpawnSpawns_Timer = urand(15000, 45000); - } - - void SummonSpawn(Unit* victim) - { - if (!victim) - return; - Rand = 10 + (rand() % 10); switch (rand() % 2) { @@ -99,13 +80,68 @@ public: break; } Rand = 0; - Spawn = DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - if (Spawn) - Spawn->AI()->AttackStart(victim); + DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); } void EnterCombat(Unit* /*who*/) override { + _scheduler.CancelAll(); + + _scheduler.Schedule(4s, 8s, [this](TaskContext context) { + DoCastVictim(SPELL_MORTAL_WOUND); + context.Repeat(); + }).Schedule(15s, 45s, [this](TaskContext context) { + switch (urand(0, 2)) + { + case 0: + SummonSpawn(); + break; + case 1: + SummonSpawn(); + SummonSpawn(); + break; + case 2: + SummonSpawn(); + SummonSpawn(); + SummonSpawn(); + break; + } + context.Repeat(30s, 60s); + }).Schedule(15s, 45s, [this](TaskContext context) { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + { + DoCast(target, SPELL_ROOT); + + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -100); + + switch (urand(0, 2)) + { + case 0: + DoTeleportPlayer(target, -8106.0142f, 1289.2900f, -74.419533f, 5.112f); + me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + break; + case 1: + DoTeleportPlayer(target, -7990.135354f, 1155.1907f, -78.849319f, 2.608f); + me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + break; + case 2: + DoTeleportPlayer(target, -8159.7753f, 1127.9064f, -76.868660f, 0.675f); + me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + break; + } + } + context.Repeat(45s, 60s); + }); } void UpdateAI(uint32 diff) override @@ -114,105 +150,15 @@ public: if (!UpdateVictim()) return; - //MortalWound_Timer - if (MortalWound_Timer <= diff) - { - DoCastVictim(SPELL_MORTAL_WOUND); - MortalWound_Timer = urand(10000, 20000); - } - else MortalWound_Timer -= diff; - - //Summon 1-3 Spawns of Fankriss at random time. - if (SpawnSpawns_Timer <= diff) - { - switch (urand(0, 2)) - { - case 0: - SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0)); - break; - case 1: - SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0)); - SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0)); - break; - case 2: - SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0)); - SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0)); - SummonSpawn(SelectTarget(SelectTargetMethod::Random, 0)); - break; - } - SpawnSpawns_Timer = urand(30000, 60000); - } - else SpawnSpawns_Timer -= diff; - - // Teleporting Random Target to one of the three tunnels and spawn 4 hatchlings near the gamer. - //We will only telport if fankriss has more than 3% of hp so teleported gamers can always loot. - if (HealthAbovePct(3)) - { - if (SpawnHatchlings_Timer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - DoCast(target, SPELL_ROOT); - - if (DoGetThreat(target)) - DoModifyThreatPercent(target, -100); - - switch (urand(0, 2)) - { - case 0: - DoTeleportPlayer(target, -8106.0142f, 1289.2900f, -74.419533f, 5.112f); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - break; - case 1: - DoTeleportPlayer(target, -7990.135354f, 1155.1907f, -78.849319f, 2.608f); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - break; - case 2: - DoTeleportPlayer(target, -8159.7753f, 1127.9064f, -76.868660f, 0.675f); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() - 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 3, target->GetPositionY() + 3, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() - 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - Hatchling = me->SummonCreature(15962, target->GetPositionX() - 5, target->GetPositionY() + 5, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Hatchling) - Hatchling->AI()->AttackStart(target); - break; - } - } - SpawnHatchlings_Timer = urand(45000, 60000); - } - else SpawnHatchlings_Timer -= diff; - } - - DoMeleeAttackIfReady(); + _scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); } + + private: + TaskScheduler _scheduler; + int Rand; + float RandX; + float RandY; }; }; diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp index 3b5be7146..bdd58744e 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp @@ -24,6 +24,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "temple_of_ahnqiraj.h" enum Huhuran @@ -36,7 +37,8 @@ enum Huhuran SPELL_POISONBOLT = 26052, SPELL_NOXIOUSPOISON = 26053, SPELL_WYVERNSTING = 26180, - SPELL_ACIDSPIT = 26050 + SPELL_ACIDSPIT = 26050, + SPELL_WYVERN_STING_DAMAGE = 26233 }; class boss_huhuran : public CreatureScript @@ -76,10 +78,6 @@ public: Berserk = false; } - void EnterCombat(Unit* /*who*/) override - { - } - void UpdateAI(uint32 diff) override { //Return since we have no target @@ -100,8 +98,7 @@ public: // Wyvern Timer if (Wyvern_Timer <= diff) { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - DoCast(target, SPELL_WYVERNSTING); + DoCastAOE(SPELL_WYVERNSTING); Wyvern_Timer = urand(15000, 32000); } else Wyvern_Timer -= diff; @@ -155,7 +152,27 @@ public: }; }; +// 26180 - Wyvern Sting +class spell_huhuran_wyvern_sting : public AuraScript +{ + PrepareAuraScript(spell_huhuran_wyvern_sting); + + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + { + caster->CastCustomSpell(SPELL_WYVERN_STING_DAMAGE, SPELLVALUE_BASE_POINT0, 3000, GetUnitOwner(), true); + } + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_huhuran_wyvern_sting::HandleRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } +}; + void AddSC_boss_huhuran() { new boss_huhuran(); + RegisterSpellScript(spell_huhuran_wyvern_sting); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp index f0ffe9d79..5944c9e95 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp @@ -58,6 +58,7 @@ public: void Reset() override { + _Reset(); _flag = 0; _hpct = 75.0f; me->SetVisible(true); @@ -96,9 +97,6 @@ public: if (_flag & (1 << 7)) _flag = 0; - if (Unit* Target = SelectTarget(SelectTargetMethod::Random)) - creature->AI()->AttackStart(Target); - float ImageHealthPct; if (me->GetHealthPct() < 25.0f) @@ -110,12 +108,16 @@ public: creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct); creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f)); + BossAI::JustSummoned(creature); } void JustDied(Unit* /*killer*/) override { if (!me->IsSummon()) + { + _JustDied(); Talk(SAY_DEATH); + } else me->RemoveCorpse(); } @@ -169,7 +171,7 @@ public: if (!me->IsSummon() && me->GetHealthPct() < _hpct) { - DoCast(me, SPELL_SUMMON_IMAGES); + DoCast(me, SPELL_SUMMON_IMAGES, true); Talk(SAY_SPLIT); _hpct -= 25.0f; me->SetVisible(false); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 51d16c953..8204f55b4 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4472,6 +4472,104 @@ class spell_gen_remove_impairing_auras : public SpellScript } }; +enum AQSpells +{ + SPELL_CONSUME_LEECH_AQ20 = 25373, + SPELL_CONSUME_LEECH_HEAL_AQ20 = 25378, + SPELL_CONSUME_SPIT_OUT = 25383, + + SPELL_HIVEZARA_CATALYST = 25187 +}; + +class spell_gen_consume : public AuraScript +{ + PrepareAuraScript(spell_gen_consume); + +public: + spell_gen_consume(uint32 spellId1, uint32 spellId2) : AuraScript(), _spellId1(spellId1), _spellId2(spellId2) { } + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ _spellId1, _spellId2 }); + } + + void HandleProc(AuraEffect* /*aurEff*/) + { + if (Unit* caster = GetCaster()) + { + if (!caster->IsAlive()) + { + GetUnitOwner()->RemoveAurasDueToSpell(GetSpellInfo()->Id); + return; + } + + caster->CastSpell(GetUnitOwner(), _spellId1, true); + } + } + + void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()) + { + if (Unit* caster = GetCaster()) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH) + { + caster->CastSpell(caster, _spellId2, true); + } + else if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + { + caster->CastSpell(GetTarget(), SPELL_CONSUME_SPIT_OUT, true); + } + } + } + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_gen_consume::AfterRemove, EFFECT_1, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_gen_consume::HandleProc, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + +private: + uint32 _spellId1; + uint32 _spellId2; +}; + +class spell_gen_apply_aura_after_expiration : public AuraScript +{ + PrepareAuraScript(spell_gen_apply_aura_after_expiration); + +public: + spell_gen_apply_aura_after_expiration(uint32 spellId, uint32 effect, uint32 aura) : AuraScript(), _spellId(spellId), _effect(effect), _aura(aura) { } + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ _spellId }); + } + + void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication() && GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + { + if (Unit* caster = GetCaster()) + { + caster->CastSpell(GetTarget(), _spellId, true); + } + } + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_gen_apply_aura_after_expiration::AfterRemove, _effect, _aura, AURA_EFFECT_HANDLE_REAL); + } + +private: + uint32 _spellId; + uint32 _effect; + uint32 _aura; +}; + void AddSC_generic_spell_scripts() { RegisterSpellScript(spell_silithyst); @@ -4569,6 +4667,7 @@ void AddSC_generic_spell_scripts() RegisterSpellScript(spell_gen_teleporting); RegisterSpellScript(spell_gen_ds_flush_knockback); RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_default_count_pct_from_max_hp"); + RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_10pct_count_pct_from_max_hp", 10); RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_50pct_count_pct_from_max_hp", 50); RegisterSpellScriptWithArgs(spell_gen_count_pct_from_max_hp, "spell_gen_100pct_count_pct_from_max_hp", 100); RegisterSpellScript(spell_gen_despawn_self); @@ -4605,4 +4704,6 @@ void AddSC_generic_spell_scripts() RegisterSpellScript(spell_gen_holiday_buff_food); RegisterSpellScript(spell_gen_arcane_charge); RegisterSpellScript(spell_gen_remove_impairing_auras); + RegisterSpellScriptWithArgs(spell_gen_consume, "spell_consume_aq20", SPELL_CONSUME_LEECH_AQ20, SPELL_CONSUME_LEECH_HEAL_AQ20); + RegisterSpellScriptWithArgs(spell_gen_apply_aura_after_expiration, "spell_itch_aq20", SPELL_HIVEZARA_CATALYST, EFFECT_0, SPELL_AURA_DUMMY); } diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 7c92f7ec7..384bee7da 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -842,22 +842,17 @@ class spell_pri_vampiric_touch : public AuraScript bool CheckProc(ProcEventInfo& eventInfo) { if (!eventInfo.GetActionTarget() || GetOwner()->GetGUID() != eventInfo.GetActionTarget()->GetGUID()) - return false; - - if (eventInfo.GetTypeMask() & PROC_FLAG_KILLED) { - if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) - { - if (spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (spellInfo->SpellFamilyFlags[0] & 0x00002000)) - { - return true; - } - } - return false; } - return eventInfo.GetActionTarget()->IsAlive(); + SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); + if (!spellInfo || spellInfo->SpellFamilyName != SPELLFAMILY_PRIEST || !(spellInfo->SpellFamilyFlags[0] & 0x00002000)) + { + return false; + } + + return true; } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index cfa787420..82a3e5e99 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -21,6 +21,7 @@ * Scriptnames of files in this file should be prefixed with "spell_warl_". */ +#include "Pet.h" #include "Player.h" #include "ScriptMgr.h" #include "SpellAuraEffects.h" @@ -1229,6 +1230,45 @@ class spell_warl_shadowburn : public AuraScript } }; +class spell_warl_glyph_of_felguard : public AuraScript +{ + PrepareAuraScript(spell_warl_glyph_of_felguard); + + void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetCaster()->ToPlayer()) + { + if (Pet* pet = player->GetPet()) + { + if (pet->GetEntry() == NPC_FELGUARD) + { + pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true); + } + } + } + } + + void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetCaster()->ToPlayer()) + { + if (Pet* pet = player->GetPet()) + { + if (pet->GetEntry() == NPC_FELGUARD) + { + pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), false); + } + } + } + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_felguard::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_felguard::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + void AddSC_warlock_spell_scripts() { RegisterSpellScript(spell_warl_eye_of_kilrogg); @@ -1260,4 +1300,5 @@ void AddSC_warlock_spell_scripts() RegisterSpellScript(spell_warl_unstable_affliction); RegisterSpellScript(spell_warl_drain_soul); RegisterSpellScript(spell_warl_shadowburn); + RegisterSpellScript(spell_warl_glyph_of_felguard); } diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 3ca17f2ed..c2e846396 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -16,10 +16,14 @@ */ #include "MapBuilder.h" +#include "IntermediateValues.h" #include "MapDefines.h" #include "MapTree.h" #include "ModelInstance.h" #include "PathCommon.h" +#include "StringFormat.h" +#include "VMapFactory.h" +#include "VMapMgr2.h" #include #include #include