mirror of
https://github.com/azerothcore/azerothcore-wotlk.git
synced 2025-11-10 20:44:17 +08:00
Compare commits
40 Commits
25e6bf68d9
...
ed3e16896e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed3e16896e | ||
|
|
5bef92d5ea | ||
|
|
723aae9039 | ||
|
|
283f03bdcd | ||
|
|
57daeed03a | ||
|
|
36d739ee42 | ||
|
|
3ad79541f6 | ||
|
|
be58898d06 | ||
|
|
bab53774d2 | ||
|
|
8f89a77592 | ||
|
|
4e6ccb828b | ||
|
|
a5549c7fa2 | ||
|
|
49ebc55bda | ||
|
|
19f31152f3 | ||
|
|
e07481c099 | ||
|
|
a31b747bfb | ||
|
|
ad8cd929fd | ||
|
|
3b98fbeb94 | ||
|
|
18ca9b9dd7 | ||
|
|
f5ce362876 | ||
|
|
fdd27f12c6 | ||
|
|
7c58590b02 | ||
|
|
74391d0d96 | ||
|
|
f4b436f67e | ||
|
|
48f966df04 | ||
|
|
2a77ab785c | ||
|
|
7b3546753c | ||
|
|
c817ba903c | ||
|
|
9f86676a2c | ||
|
|
0b9b84389c | ||
|
|
c4afc5534e | ||
|
|
5684cd63d4 | ||
|
|
66c87d231a | ||
|
|
4f1fcb10fd | ||
|
|
795570ba8f | ||
|
|
f3bd5adf8e | ||
|
|
f0e28838dc | ||
|
|
bb18ac07df | ||
|
|
8cf85f6b8d | ||
|
|
918b0b46b1 |
67
data/sql/updates/db_world/2025_11_09_03.sql
Normal file
67
data/sql/updates/db_world/2025_11_09_03.sql
Normal file
@ -0,0 +1,67 @@
|
||||
-- DB update 2025_11_09_02 -> 2025_11_09_03
|
||||
--
|
||||
-- Fixes "Bluff", Set `allowOverride` of action list
|
||||
UPDATE `smart_scripts` SET `action_param3` = 1 WHERE (`entryorguid` IN (23672, 23673, 23675, 24271)) AND (`source_type` = 0) AND (`event_type` = 8) AND (`event_param1` = 44609);
|
||||
|
||||
-- Removes double spawns
|
||||
DELETE FROM `gameobject` WHERE `id` = 186959 AND `guid` IN (264459, 264460, 264461, 264462, 264463, 264464, 264465);
|
||||
|
||||
-- Add missing aura. Usage is unknown
|
||||
DELETE FROM `creature_template_addon` WHERE (`entry` = 24825);
|
||||
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
|
||||
(24825, 0, 0, 0, 0, 0, 0, '44652');
|
||||
|
||||
-- Disable flying vehicle, but causes camera stuttering on rocket jump
|
||||
UPDATE `creature_template_movement` SET `Flight` = 0 WHERE (`CreatureId` = 24825);
|
||||
|
||||
DELETE FROM `creature_text` WHERE (`CreatureID` = 24825) AND (`GroupID` = 1);
|
||||
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(24825, 1, 0, 'Launching.', 12, 0, 100, 0, 0, 0, 23860, 0, 'Iron Rune Construct');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 24825) AND (`source_type` = 0) AND (`id` IN (15, 16));
|
||||
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`, `event_param6`, `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
|
||||
(24825, 0, 15, 0, 31, 0, 100, 512, 44609, 0, 3000, 3000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Spellhit \'Bluff\' - Say Line 0'),
|
||||
(24825, 0, 16, 0, 8, 0, 100, 512, 44626, 0, 5000, 5000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Spellhit \'Rocket Jump\' - Say Line 1');
|
||||
-- Remove unused 'Say Line 0' in actionscripts
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` IN (2367201, 2367301, 2367501, 2427101)) AND `source_type` = 9 AND `id` = 1 AND `target_type` = 19 AND `target_param1` = 24825 AND `action_type` = 1 AND `target_param2` = 20;
|
||||
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` IN (2, 4)) AND (`SourceEntry` = 44608) AND (`SourceId` = 0) AND (`ConditionTypeOrReference` = 31);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(13, 4, 44608, 0, 0, 31, 0, 3, 24826, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 4, 44608, 0, 1, 31, 0, 3, 24827, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 4, 44608, 0, 2, 31, 0, 3, 24828, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 4, 44608, 0, 3, 31, 0, 3, 24829, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 4, 44608, 0, 4, 31, 0, 3, 24831, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 4, 44608, 0, 5, 31, 0, 3, 24832, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 2, 44608, 0, 0, 31, 0, 5, 186953, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 2, 44608, 0, 1, 31, 0, 5, 186960, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 2, 44608, 0, 2, 31, 0, 5, 186961, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 2, 44608, 0, 3, 31, 0, 5, 186963, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 2, 44608, 0, 4, 31, 0, 5, 186962, 0, 0, 0, 0, '', 'Rocket Jump'),
|
||||
(13, 2, 44608, 0, 5, 31, 0, 5, 186964, 0, 0, 0, 0, '', 'Rocket Jump');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24825);
|
||||
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`, `event_param6`, `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
|
||||
(24825, 0, 0, 0, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 75, 44643, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Just Summoned - Add Aura \'Reputation and Language\''),
|
||||
(24825, 0, 1, 0, 28, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 44643, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Passenger Removed - Remove Aura \'Reputation and Language\''),
|
||||
(24825, 0, 2, 0, 38, 0, 100, 512, 0, 1, 0, 0, 0, 0, 53, 2, 24826, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 1 - Start Waypoint Path 24826'),
|
||||
(24825, 0, 3, 0, 38, 0, 100, 512, 0, 2, 0, 0, 0, 0, 53, 2, 24827, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 2 - Start Waypoint Path 24827'),
|
||||
(24825, 0, 4, 0, 38, 0, 100, 512, 0, 3, 0, 0, 0, 0, 53, 2, 24828, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 3 - Start Waypoint Path 24828'),
|
||||
(24825, 0, 5, 0, 38, 0, 100, 512, 0, 4, 0, 0, 0, 0, 53, 2, 24831, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 4 - Start Waypoint Path 24831'),
|
||||
(24825, 0, 6, 0, 38, 0, 100, 512, 0, 5, 0, 0, 0, 0, 53, 2, 24829, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 5 - Start Waypoint Path 24829'),
|
||||
(24825, 0, 7, 0, 38, 0, 100, 512, 0, 6, 0, 0, 0, 0, 53, 2, 24832, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 6 - Start Waypoint Path 24832'),
|
||||
(24825, 0, 8, 0, 58, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 44626, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Path 0 Finished - Remove Aura \'Rocket Jump\''),
|
||||
(24825, 0, 9, 0, 31, 0, 100, 512, 44609, 0, 3000, 3000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Target Spellhit \'Bluff\' - Say Line 0'),
|
||||
(24825, 0, 10, 0, 8, 0, 100, 512, 44626, 0, 5000, 5000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Spellhit \'Rocket Jump\' - Say Line 1');
|
||||
--
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (24826, 24827, 24828, 24829, 24831, 24832));
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (24826, 24827, 24828, 24829, 24831, 24832));
|
||||
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`, `event_param6`, `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
|
||||
(24826, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 1'),
|
||||
(24827, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 2'),
|
||||
(24828, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 3, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 3'),
|
||||
(24831, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 4, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 4'),
|
||||
(24829, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 5'),
|
||||
(24832, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 6, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 6');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE `source_type` = 9 AND `entryorguid` IN (2482600, 2482700, 2482800, 2482900, 2483100, 2483200);
|
||||
6
data/sql/updates/db_world/2025_11_09_04.sql
Normal file
6
data/sql/updates/db_world/2025_11_09_04.sql
Normal file
@ -0,0 +1,6 @@
|
||||
-- DB update 2025_11_09_03 -> 2025_11_09_04
|
||||
--
|
||||
DELETE FROM `spell_custom_attr` WHERE `spell_id` IN (52671, 59834);
|
||||
INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES
|
||||
(52671, 0x00400000),
|
||||
(59834, 0x00400000);
|
||||
79
data/sql/updates/db_world/2025_11_09_05.sql
Normal file
79
data/sql/updates/db_world/2025_11_09_05.sql
Normal file
@ -0,0 +1,79 @@
|
||||
-- DB update 2025_11_09_04 -> 2025_11_09_05
|
||||
--
|
||||
-- v11_2_5_63906
|
||||
SET @VBUILD := 63906;
|
||||
|
||||
DELETE FROM `creature_template_addon` WHERE (`entry` = 28503);
|
||||
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
|
||||
(28503, 0, 0, 0, 0, 0, 0, '58837');
|
||||
|
||||
DELETE FROM `creature_template_addon` WHERE (`entry` = 28998);
|
||||
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
|
||||
(28998, 0, 0, 0, 0, 0, 0, '58837');
|
||||
|
||||
DELETE FROM `creature` WHERE (`id1` = 28998) AND (`guid` IN (1974609));
|
||||
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`, `Comment`, `VerifiedBuild`) VALUES
|
||||
(1974609, 28998, 0, 0, 571, 0, 0, 1, 1, 0, 6175.2456, -2017.6545, 590.9613, 3.0019662, 300, 0, 0, 550001, 0, 0, 0, 0, 0, '', NULL, @VBUILD);
|
||||
|
||||
DELETE FROM `creature_template_addon` WHERE (`entry` = 28998);
|
||||
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
|
||||
(28998, 0, 0, 0, 1, 0, 0, '');
|
||||
|
||||
UPDATE `spell_target_position` SET `PositionX`=6161.15, `PositionY`=-2015.36, `PositionZ`=590.878, `Orientation`=6.283189773559570312, `VerifiedBuild`=@VBUILD WHERE `ID`=52863 AND `EffectIndex`=0;
|
||||
|
||||
UPDATE `creature_template_addon` SET `bytes2` = 1 WHERE (`entry` = 28717);
|
||||
|
||||
-- Update comments
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28498) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 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`, `event_param6`, `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
|
||||
(28498, 0, 0, 0, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 1, 28498, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'The Lich King - On Just Summoned - Start Waypoint Path 28498'),
|
||||
(28498, 0, 1, 2, 40, 0, 100, 512, 2, 0, 0, 0, 0, 0, 54, 83000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'The Lich King - On Point 2 of Path Any Reached - Pause Waypoint'),
|
||||
(28498, 0, 2, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2849800, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'The Lich King - On Point 2 of Path Any Reached - Run Script'),
|
||||
(28498, 0, 3, 4, 40, 0, 100, 512, 3, 0, 0, 0, 0, 0, 45, 0, 2, 0, 0, 0, 0, 10, 127495, 0, 0, 0, 0, 0, 0, 0, 'The Lich King - On Point 3 of Path Any Reached - Set Data 0 2'),
|
||||
(28498, 0, 4, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'The Lich King - On Point 3 of Path Any Reached - Despawn Instant');
|
||||
|
||||
-- Disable gravity
|
||||
DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 29100);
|
||||
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
|
||||
(29100, 0, 0, 1, 0, 0, 0, 0);
|
||||
|
||||
-- Idle
|
||||
UPDATE `creature` SET `MovementType` = 0, `wander_distance` = 0 WHERE `id1` = 29100 AND `guid` IN (112307, 112308, 112309, 112310);
|
||||
|
||||
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 202357;
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 202357) AND (`source_type` = 1) 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`, `event_param6`, `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
|
||||
(202357, 1, 0, 0, 62, 0, 100, 0, 11091, 0, 0, 0, 0, 0, 11, 57553, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Drakuru\'s Last Wish - On Gossip Option 0 Selected - Cast \'Escape Voltarus\'');
|
||||
|
||||
-- Drakuru's Last Wish
|
||||
UPDATE `gameobject_template_addon` SET `flags` = 32 WHERE (`entry` = 202357);
|
||||
|
||||
-- Skull and Portal spells target 'Totally Generic Bunny (JSB)'
|
||||
DELETE FROM `creature` WHERE (`id1` = 28960) and `guid` IN (98914, 98920);
|
||||
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`, `Comment`, `VerifiedBuild`) VALUES
|
||||
(98914, 28960, 0, 0, 571, 0, 0, 1, 1, 0, 6144.01, -2011.8, 590.963, 6.16101, 300, 0, 0, 4979, 0, 0, 0, 0, 0, '', '\'Throw Portal Crystal\' guid target', @VBUILD),
|
||||
(98920, 28960, 0, 0, 571, 0, 0, 1, 1, 0, 6181.5137, -2032.4258, 590.96124, 1.01229, 300, 0, 0, 4979, 0, 0, 0, 0, 0, '', '\'Drakuru\'s Skull Missile\' guid target', @VBUILD);
|
||||
|
||||
UPDATE `conditions` SET `ConditionValue3` = 98914, `Comment` = 'target Totally Generic Bunny (JSB)' WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 54209) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 28960) AND (`ConditionValue3` = 0);
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 54250) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 28960);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(13, 1, 54250, 0, 0, 31, 0, 3, 28960, 98920, 0, 0, 0, '', 'target Totally Generic Bunny (JSB)');
|
||||
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 54089) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 1) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 51966) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(13, 1, 54089, 0, 0, 1, 0, 51966, 0, 0, 0, 0, 0, '', 'Has Aura \'Scourge Disguise\'');
|
||||
|
||||
-- 54104 Blight Fog
|
||||
UPDATE `creature_template_addon` SET `auras` = '54104' WHERE (`entry` = 28998);
|
||||
|
||||
DELETE FROM `creature_summon_groups` WHERE `summonerId` = 28998 and `summonerType` = 0 AND `groupId` = 1;
|
||||
INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`, `Comment`) VALUES
|
||||
(28998, 0, 1, 28931, 6184.1455, -1970.1699, 586.84186, 4.5902, 8, 0, 'Overlord Drakuru - Group 1 - Blightblood Troll'),
|
||||
(28998, 0, 1, 28931, 6222.855, -2026.6315, 586.84186, 3.00197, 8, 0, 'Overlord Drakuru - Group 1 - Blightblood Troll'),
|
||||
(28998, 0, 1, 28931, 6166.278, -2065.3123, 586.84186, 1.44862, 8, 0, 'Overlord Drakuru - Group 1 - Blightblood Troll'),
|
||||
(28998, 0, 1, 28931, 6127.5117, -2008.6506, 586.84186, 6.16101, 8, 0, 'Overlord Drakuru - Group 1 - Blightblood Troll');
|
||||
|
||||
-- 54105 Blight Fog
|
||||
DELETE FROM `spell_script_names` WHERE (`spell_id` = 54105);
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(54105, 'spell_blight_fog');
|
||||
@ -308,6 +308,76 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist,
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool _finiteF(float v) { return std::isfinite(v); }
|
||||
namespace { constexpr float INV_SQRT2 = 0.70710678118654752440f; }
|
||||
|
||||
float DynamicMapTree::getHeightAccurate(float x, float y, float z, float maxSearchDist, uint32 phasemask,
|
||||
float radius, float yaw, float blend, float clamp, float sampleDelta) const
|
||||
{
|
||||
auto sample = [&](float sx, float sy) -> float
|
||||
{
|
||||
G3D::Vector3 v(sx, sy, z);
|
||||
G3D::Ray r(v, G3D::Vector3(0, 0, -1));
|
||||
float dist = maxSearchDist;
|
||||
DynamicTreeIntersectionCallback cb(phasemask, VMAP::ModelIgnoreFlags::Nothing);
|
||||
impl->intersectZAllignedRay(r, cb, dist);
|
||||
if (cb.didHit())
|
||||
return z - dist;
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
};
|
||||
|
||||
const float h0 = sample(x, y);
|
||||
if (!_finiteF(h0))
|
||||
return -G3D::finf();
|
||||
|
||||
if (radius <= 0.0f)
|
||||
return h0;
|
||||
|
||||
const float d = (sampleDelta > 0.0f) ? sampleDelta
|
||||
: std::max(0.05f, std::min(0.5f, radius * 0.5f));
|
||||
|
||||
const float hx1 = sample(x + d, y);
|
||||
const float hx2 = sample(x - d, y);
|
||||
const float hy1 = sample(x, y + d);
|
||||
const float hy2 = sample(x, y - d);
|
||||
|
||||
auto diff = [&](float p, float m) -> float
|
||||
{
|
||||
if (_finiteF(p) && _finiteF(m)) return (p - m) / (2.0f * d);
|
||||
if (_finiteF(p)) return (p - h0) / d;
|
||||
if (_finiteF(m)) return (h0 - m) / d;
|
||||
return 0.0f;
|
||||
};
|
||||
|
||||
float gx = diff(hx1, hx2); // dz/dx
|
||||
float gy = diff(hy1, hy2); // dz/dy
|
||||
|
||||
if (clamp > 0.0f)
|
||||
{
|
||||
const float g2 = gx*gx + gy*gy;
|
||||
const float c2 = clamp*clamp;
|
||||
if (g2 > c2)
|
||||
{
|
||||
const float s = clamp / std::sqrt(g2);
|
||||
gx *= s; gy *= s;
|
||||
}
|
||||
}
|
||||
|
||||
const float slopeL2 = std::sqrt(std::max(0.0f, gx*gx + gy*gy));
|
||||
float totalSlope = slopeL2;
|
||||
|
||||
if (blend < 1.0f)
|
||||
{
|
||||
float c = std::cos(yaw), s = std::sin(yaw);
|
||||
float rx = gx * c + gy * s;
|
||||
float ry = -gx * s + gy * c;
|
||||
float slopeL1 = std::abs(rx) + std::abs(ry);
|
||||
totalSlope = blend * slopeL2 + (1.0f - blend) * (INV_SQRT2 * slopeL1);
|
||||
}
|
||||
|
||||
return h0 + radius * totalSlope;
|
||||
}
|
||||
|
||||
bool DynamicMapTree::GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||
{
|
||||
G3D::Vector3 v(x, y, z + 0.5f);
|
||||
|
||||
@ -55,6 +55,8 @@ public:
|
||||
float pModifyDist) const;
|
||||
|
||||
[[nodiscard]] float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const;
|
||||
[[nodiscard]] float getHeightAccurate(float x, float y, float z, float maxSearchDist, uint32 phasemask,
|
||||
float radius, float yaw, float blend, float clamp, float sampleDelta) const;
|
||||
|
||||
void insert(const GameObjectModel&);
|
||||
void remove(const GameObjectModel&);
|
||||
|
||||
@ -1397,6 +1397,79 @@ vmap.BlizzlikeLOSInOpenWorld = 1
|
||||
|
||||
vmap.enableIndoorCheck = 1
|
||||
|
||||
#
|
||||
# Accurate ground settlement (cylinder–plane) settings
|
||||
# 0 = cylinder-circle footprint (recommended),
|
||||
# 1 = square footprint (upside-down-pyramid)
|
||||
#
|
||||
|
||||
Height.Accurate.Shape = 0
|
||||
|
||||
#
|
||||
# Scale factor applied to the probe radius (safety margin, do not abuse)
|
||||
#
|
||||
|
||||
Height.Accurate.RadiusScale = 1.0
|
||||
|
||||
#
|
||||
# Square and cylinder mix [0..1]
|
||||
# 0.00 = pure square
|
||||
# 1.00 = cylinder (circle) (equal to Shape=0)
|
||||
# Recommended for QA: 0.15–0.25
|
||||
#
|
||||
|
||||
Height.Accurate.SquareBlend = 0.2
|
||||
|
||||
#
|
||||
# Optional slope clamp (rise/run). 0.0 disables clamping.
|
||||
# This limits the gradient magnitude used by both circle and square footprints,
|
||||
# preventing extreme lifts on near-vertical faces. Safe upper bound: ~5.0 (≈78.7°).
|
||||
#
|
||||
|
||||
Height.Accurate.SlopeClamp = 0.0
|
||||
|
||||
#
|
||||
# Gradient mode
|
||||
# 0 = Plane (exact face-plane gradient; maximizes geometric accuracy)
|
||||
# 1 = LS (least-squares gradient; smoother, slightly less exact)
|
||||
#
|
||||
|
||||
Height.Accurate.GradientMode = 0
|
||||
|
||||
#
|
||||
# Normal epsilon used to detect degenerate faces (|nz| < eps)
|
||||
# Recommended: 1e-6 .. 1e-5
|
||||
#
|
||||
|
||||
Height.Accurate.NormalEps = 0.000001
|
||||
|
||||
#
|
||||
# Accurate VMAP height (apply same footprint & slope logic on VMAP)
|
||||
# 1 = enable (recommended), 0 = legacy point-ray height
|
||||
#
|
||||
|
||||
Height.Accurate.VMap.Enable = 1
|
||||
|
||||
#
|
||||
# Lateral sample delta (meters) to estimate VMAP gradient with 4 extra rays:
|
||||
# (x±delta,y) and (x,y±delta). Typical 0.15..0.35. Affects precision & cost.
|
||||
#
|
||||
|
||||
Height.Accurate.VMap.Delta = 0.25
|
||||
|
||||
#
|
||||
# -- Accurate DYNAMIC (MMAP) planar offset (gradient sampling) --
|
||||
# 1 = enable (recommended), 0 = legacy point ray
|
||||
#
|
||||
|
||||
Height.Accurate.Dynamic.Enable = 1
|
||||
|
||||
#
|
||||
# Gradient sampling delta for Dynamic (meters). Typical 0.15..0.35
|
||||
#
|
||||
|
||||
Height.Accurate.Dynamic.Delta = 0.25
|
||||
|
||||
#
|
||||
# DetectPosCollision
|
||||
# Description: Check final move position, summon position, etc for visible collision with
|
||||
|
||||
@ -3042,6 +3042,36 @@ float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/,
|
||||
return GetMap()->GetHeight(GetPhaseMask(), x, y, z, vmap, distanceToSearch);
|
||||
}
|
||||
|
||||
float WorldObject::GetGroundProbeRadius() const
|
||||
{
|
||||
if (Unit const* u = ToUnit())
|
||||
return std::max(0.25f, u->GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS));
|
||||
return 0.3f;
|
||||
}
|
||||
|
||||
float WorldObject::GetMapHeightAccurate(float x, float y, float z, bool vmap/* = true*/,
|
||||
float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/, float radius/* = 0.3f*/) const
|
||||
{
|
||||
if (radius <= 0.0f)
|
||||
{
|
||||
if (Unit const* u = ToUnit())
|
||||
{
|
||||
radius = std::max(0.25f, u->GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS));
|
||||
}
|
||||
else
|
||||
radius = 0.3f;
|
||||
}
|
||||
|
||||
float rScale = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE);
|
||||
radius *= rScale;
|
||||
|
||||
float yaw = GetOrientation();
|
||||
if (z != MAX_HEIGHT)
|
||||
z += std::max(GetCollisionHeight(), radius + 0.2f);
|
||||
|
||||
return GetMap()->GetHeightAccurate(GetPhaseMask(), x, y, z, radius, yaw, vmap, distanceToSearch);
|
||||
}
|
||||
|
||||
float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const
|
||||
{
|
||||
return GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), x, y, z, ground,
|
||||
|
||||
@ -703,6 +703,8 @@ public:
|
||||
};
|
||||
[[nodiscard]] float GetMapWaterOrGroundLevel(float x, float y, float z, float* ground = nullptr) const;
|
||||
[[nodiscard]] float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f) const; // DEFAULT_HEIGHT_SEARCH in map.h
|
||||
[[nodiscard]] float GetGroundProbeRadius() const;
|
||||
[[nodiscard]] float GetMapHeightAccurate(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f, float radius = 0.3f) const;
|
||||
|
||||
[[nodiscard]] float GetFloorZ() const;
|
||||
[[nodiscard]] float GetMinHeightInWater() const;
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "GridTerrainData.h"
|
||||
#include "Log.h"
|
||||
#include "MapDefines.h"
|
||||
#include "World.h"
|
||||
#include <filesystem>
|
||||
#include <G3D/Ray.h>
|
||||
|
||||
@ -615,3 +616,212 @@ LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float
|
||||
|
||||
return liquidData;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr float INV_SQRT2 = 0.70710678118654752440f; // 1/sqrt(2)
|
||||
}
|
||||
|
||||
static inline float CELL_SIZE() { return SIZE_OF_GRIDS / float(MAP_RESOLUTION); } // ≈ 4.1666667f
|
||||
|
||||
bool GridTerrainData::SampleHeights(uint32 xInt, uint32 yInt, float& h1, float& h2, float& h3, float& h4, float& h5) const
|
||||
{
|
||||
if (!_loadedHeightData)
|
||||
return false;
|
||||
|
||||
// FLOAT
|
||||
if (_loadedHeightData->floatHeightData)
|
||||
{
|
||||
auto const& v9 = _loadedHeightData->floatHeightData->v9;
|
||||
auto const& v8 = _loadedHeightData->floatHeightData->v8;
|
||||
|
||||
h1 = v9[xInt * 129 + yInt];
|
||||
h2 = v9[(xInt + 1) * 129 + yInt];
|
||||
h3 = v9[xInt * 129 + yInt + 1];
|
||||
h4 = v9[(xInt + 1) * 129 + yInt + 1];
|
||||
h5 = v8[xInt * 128 + yInt];
|
||||
return true;
|
||||
}
|
||||
|
||||
// UINT8
|
||||
if (_loadedHeightData->uint8HeightData)
|
||||
{
|
||||
auto const& d = *_loadedHeightData->uint8HeightData;
|
||||
float k = d.gridIntHeightMultiplier;
|
||||
float base = _loadedHeightData->gridHeight;
|
||||
|
||||
auto v9ptr = &d.v9[xInt * 128 + xInt + yInt]; // == xInt*129 + yInt
|
||||
h1 = float(v9ptr[0]) * k + base;
|
||||
h2 = float(v9ptr[129]) * k + base;
|
||||
h3 = float(v9ptr[1]) * k + base;
|
||||
h4 = float(v9ptr[130]) * k + base;
|
||||
|
||||
uint8 v8val = d.v8[xInt * 128 + yInt];
|
||||
h5 = float(v8val) * k + base;
|
||||
return true;
|
||||
}
|
||||
|
||||
// UINT16
|
||||
if (_loadedHeightData->uint16HeightData)
|
||||
{
|
||||
auto const& d = *_loadedHeightData->uint16HeightData;
|
||||
float k = d.gridIntHeightMultiplier;
|
||||
float base = _loadedHeightData->gridHeight;
|
||||
|
||||
auto v9ptr = &d.v9[xInt * 128 + xInt + yInt]; // == xInt*129 + yInt
|
||||
h1 = float(v9ptr[0]) * k + base;
|
||||
h2 = float(v9ptr[129]) * k + base;
|
||||
h3 = float(v9ptr[1]) * k + base;
|
||||
h4 = float(v9ptr[130]) * k + base;
|
||||
|
||||
uint16 v8val = d.v8[xInt * 128 + yInt];
|
||||
h5 = float(v8val) * k + base;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float GridTerrainData::GetHeightAccurate(float x, float y, float radius) const
|
||||
{
|
||||
return GetHeightAccurate(x, y, radius, GroundFootprintShape::Circle, 0.0f, 1.0f, 0.0f, 0u, 1.0e-6f);
|
||||
}
|
||||
|
||||
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape) const
|
||||
{
|
||||
return GetHeightAccurate(x, y, radius, shape, 0.0f, (shape == GroundFootprintShape::Square ? 0.0f : 1.0f), 0.0f, 0u, 1.0e-6f);
|
||||
}
|
||||
|
||||
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw) const
|
||||
{
|
||||
// Wrapper with default blend = 1 for circle, 0 for square.
|
||||
return GetHeightAccurate(x, y, radius, shape, yaw, (shape == GroundFootprintShape::Square ? 0.0f : 1.0f), 0.0f, 0u, 1.0e-6f);
|
||||
}
|
||||
|
||||
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw,
|
||||
float squareBlend, float slopeClamp, uint32 gradientMode, float normalEps) const
|
||||
{
|
||||
if (!_loadedHeightData)
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
float xf = MAP_RESOLUTION * (32.0f - x / SIZE_OF_GRIDS);
|
||||
float yf = MAP_RESOLUTION * (32.0f - y / SIZE_OF_GRIDS);
|
||||
|
||||
int xInt = static_cast<int>(std::floor(xf));
|
||||
int yInt = static_cast<int>(std::floor(yf));
|
||||
float fx = xf - static_cast<float>(xInt);
|
||||
float fy = yf - static_cast<float>(yInt);
|
||||
|
||||
if (fx < 0.0f) { fx += 1.0f; --xInt; }
|
||||
if (fy < 0.0f) { fy += 1.0f; --yInt; }
|
||||
if (fx >= 1.0f) { fx -= 1.0f; ++xInt; }
|
||||
if (fy >= 1.0f) { fy -= 1.0f; ++yInt; }
|
||||
xInt &= (MAP_RESOLUTION - 1);
|
||||
yInt &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(xInt, yInt))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
float h1, h2, h3, h4, h5;
|
||||
if (!SampleHeights(xInt, yInt, h1, h2, h3, h4, h5))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
// h1 -> (0,0)
|
||||
// h2 -> (S,0)
|
||||
// h3 -> (0,S)
|
||||
// h4 -> (S,S)
|
||||
// h5 -> (S/2, S/2)
|
||||
const float S = CELL_SIZE();
|
||||
const float S2 = S * 0.5f;
|
||||
|
||||
G3D::Vector3 P(fx * S, fy * S, 0.0f);
|
||||
|
||||
G3D::Vector3 A(S2, S2, h5);
|
||||
|
||||
const float eps = 1e-6f;
|
||||
const float blend = std::max(0.0f, std::min(1.0f, squareBlend));
|
||||
|
||||
const bool right = (P.x >= A.x);
|
||||
const bool top = (P.y >= A.y);
|
||||
G3D::Vector3 B, C;
|
||||
if (right && !top)
|
||||
{
|
||||
B = G3D::Vector3(S, 0.0f, h2);
|
||||
C = G3D::Vector3(0.0f, 0.0f, h1);
|
||||
} // BR
|
||||
else if (right && top)
|
||||
{
|
||||
B = G3D::Vector3(S, S, h4);
|
||||
C = G3D::Vector3(S, 0.0f, h2);
|
||||
} // TR
|
||||
else if (!right && top)
|
||||
{
|
||||
B = G3D::Vector3(0.0f, S, h3);
|
||||
C = G3D::Vector3(S, S, h4);
|
||||
} // TL
|
||||
else /* !right && !top */
|
||||
{
|
||||
B = G3D::Vector3(0.0f, 0.0f, h1);
|
||||
C = G3D::Vector3(0.0f, S, h3);
|
||||
} // BL
|
||||
|
||||
const G3D::Vector3 U = B - A;
|
||||
const G3D::Vector3 V = C - A;
|
||||
const G3D::Vector3 n = U.cross(V);
|
||||
const float nzAbs = std::abs(n.z);
|
||||
if (nzAbs < std::max(eps, normalEps))
|
||||
return getHeight(x, y);
|
||||
|
||||
const float zPlane = A.z - (n.x * (P.x - A.x) + n.y * (P.y - A.y)) / n.z;
|
||||
const float inv2S = 1.0f / (2.0f * S);
|
||||
float gx, gy;
|
||||
|
||||
if (gradientMode == 0u)
|
||||
{
|
||||
// Plane-exact gradient: z = (-n.x*x - n.y*y - d)/n.z => ∇z = (-n.x/n.z, -n.y/n.z)
|
||||
gx = -n.x / n.z;
|
||||
gy = -n.y / n.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
// LS gradient (smoother)
|
||||
gx = ((h2 + h4) - (h1 + h3)) * inv2S;
|
||||
gy = ((h3 + h4) - (h1 + h2)) * inv2S;
|
||||
}
|
||||
|
||||
// Optional clamp
|
||||
if (slopeClamp > 0.0f)
|
||||
{
|
||||
const float g2 = gx*gx + gy*gy;
|
||||
const float c2 = slopeClamp * slopeClamp;
|
||||
if (g2 > c2)
|
||||
{
|
||||
const float s = slopeClamp / std::sqrt(g2);
|
||||
gx *= s; gy *= s;
|
||||
}
|
||||
}
|
||||
|
||||
const float slopeL2 = std::sqrt(std::max(0.0f, gx*gx + gy*gy));
|
||||
|
||||
// Fast‑path radius 0
|
||||
if (radius <= 0.0f)
|
||||
return zPlane;
|
||||
|
||||
float totalSlope = slopeL2; // por defecto: círculo (o blend==1)
|
||||
if (shape == GroundFootprintShape::Square && blend < 1.0f)
|
||||
{
|
||||
float slopeL1 = 0.0f;
|
||||
if (!(gx == 0.0f && gy == 0.0f))
|
||||
{
|
||||
const float c = std::cos(yaw);
|
||||
const float s = std::sin(yaw);
|
||||
const float rx = gx * c + gy * s;
|
||||
const float ry = -gx * s + gy * c;
|
||||
slopeL1 = std::abs(rx) + std::abs(ry);
|
||||
}
|
||||
totalSlope = blend * slopeL2 + (1.0f - blend) * (INV_SQRT2 * slopeL1);
|
||||
}
|
||||
|
||||
// Final height (Minkowski): base + radius * slope
|
||||
return zPlane + radius * totalSlope;
|
||||
}
|
||||
|
||||
@ -245,11 +245,37 @@ public:
|
||||
~GridTerrainData() { };
|
||||
TerrainMapDataReadResult Load(std::string const& mapFileName);
|
||||
|
||||
enum class GroundFootprintShape : uint8
|
||||
{
|
||||
Circle = 0, // cylinder-plane
|
||||
Square = 1 // upside-down pyramid
|
||||
};
|
||||
|
||||
static inline const char* ToString(GroundFootprintShape s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case GroundFootprintShape::Circle: return "circle";
|
||||
case GroundFootprintShape::Square: return "square";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
// Accurate height with footprint & yaw. squareBlend in [0..1]. slopeClamp in [0..10] (0 disables).
|
||||
float GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw,
|
||||
float squareBlend, float slopeClamp, uint32 gradientMode, float normalEps) const;
|
||||
// Convenience wrappers (kept for compatibility).
|
||||
float GetHeightAccurate(float x, float y, float radius) const;
|
||||
float GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape) const;
|
||||
float GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw /*rads*/) const;
|
||||
inline std::string to_string(GridTerrainData::GroundFootprintShape s) { return GridTerrainData::ToString(s); }
|
||||
uint16 getArea(float x, float y) const;
|
||||
inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); }
|
||||
float getMinHeight(float x, float y) const;
|
||||
float getLiquidLevel(float x, float y) const;
|
||||
LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const;
|
||||
private:
|
||||
bool SampleHeights(uint32 xInt, uint32 yInt, float& h1, float& h2, float& h3, float& h4, float& h5) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1175,6 +1175,123 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
|
||||
return mapHeight; // explicitly use map data
|
||||
}
|
||||
|
||||
namespace { constexpr float INV_SQRT2 = 0.70710678118654752440f; }
|
||||
|
||||
float Map::GetVMapHeightAccurate(float x, float y, float z, float radius, float yaw,
|
||||
GridTerrainData::GroundFootprintShape shape, float blend, float clamp, float sampleDelta) const
|
||||
{
|
||||
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
|
||||
auto sample = [&](float sx, float sy) -> float
|
||||
{
|
||||
float h = vmgr->getHeight(GetId(), sx, sy, z, DEFAULT_HEIGHT_SEARCH);
|
||||
return (h > INVALID_HEIGHT) ? h : std::numeric_limits<float>::quiet_NaN();
|
||||
};
|
||||
|
||||
float h0 = sample(x, y);
|
||||
if (!std::isfinite(h0))
|
||||
return VMAP_INVALID_HEIGHT_VALUE;
|
||||
|
||||
if (radius <= 0.0f)
|
||||
return h0;
|
||||
|
||||
const float d = (sampleDelta > 0.0f) ? sampleDelta
|
||||
: std::max(0.05f, std::min(0.5f, radius * 0.5f));
|
||||
|
||||
float hx1 = sample(x + d, y), hx2 = sample(x - d, y);
|
||||
float hy1 = sample(x, y + d), hy2 = sample(x, y - d);
|
||||
|
||||
auto diff = [&](float p, float m) -> float
|
||||
{
|
||||
if (std::isfinite(p) && std::isfinite(m)) return (p - m) / (2.0f * d);
|
||||
if (std::isfinite(p)) return (p - h0) / d;
|
||||
if (std::isfinite(m)) return (h0 - m) / d;
|
||||
return 0.0f;
|
||||
};
|
||||
|
||||
float gx = diff(hx1, hx2); // dz/dx
|
||||
float gy = diff(hy1, hy2); // dz/dy
|
||||
|
||||
if (clamp > 0.0f)
|
||||
{
|
||||
float g2 = gx*gx + gy*gy, c2 = clamp*clamp;
|
||||
if (g2 > c2)
|
||||
{
|
||||
float s = clamp / std::sqrt(g2);
|
||||
gx *= s; gy *= s;
|
||||
}
|
||||
}
|
||||
|
||||
float slopeL2 = std::sqrt(std::max(0.0f, gx*gx + gy*gy));
|
||||
float totalSlope = slopeL2;
|
||||
|
||||
if (shape == GridTerrainData::GroundFootprintShape::Square && blend < 1.0f)
|
||||
{
|
||||
float c = std::cos(yaw), s = std::sin(yaw);
|
||||
float rx = gx * c + gy * s, ry = -gx * s + gy * c;
|
||||
float slopeL1 = std::abs(rx) + std::abs(ry);
|
||||
totalSlope = blend * slopeL2 + (1.0f - blend) * (INV_SQRT2 * slopeL1);
|
||||
}
|
||||
return h0 + radius * totalSlope;
|
||||
}
|
||||
|
||||
float Map::GetHeightAccurate(float x, float y, float z, float radius, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||
{
|
||||
return GetHeightAccurate(x, y, z, radius, 0.0f, checkVMap, maxSearchDist);
|
||||
}
|
||||
|
||||
float Map::GetHeightAccurate(float x, float y, float z, float radius, float yaw, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||
{
|
||||
// find raw .map surface under Z coordinates
|
||||
float mapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
||||
float gridHeight = GetGridHeightAccurate(x, y, radius, yaw);
|
||||
if (gridHeight > INVALID_HEIGHT)
|
||||
{
|
||||
const float tol = std::max(0.1f, 0.5f * radius); // dynamic tolerance based on the size of the collider
|
||||
if (G3D::fuzzyGe(z, gridHeight - tol))
|
||||
mapHeight = gridHeight;
|
||||
}
|
||||
|
||||
float vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
||||
if (checkVMap)
|
||||
{
|
||||
const bool useAccurateVMap = (sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE) != 0);
|
||||
if (useAccurateVMap)
|
||||
{
|
||||
auto shape = static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE));
|
||||
float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||
float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||
float delta = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_VMAP_DELTA);
|
||||
vmapHeight = GetVMapHeightAccurate(x, y, z, radius, yaw, shape, blend, clamp, delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
|
||||
vmapHeight = vmgr->getHeight(GetId(), x, y, z, maxSearchDist);
|
||||
}
|
||||
}
|
||||
|
||||
// mapHeight set for any above raw ground Z or <= INVALID_HEIGHT
|
||||
// vmapheight set for any under Z value or <= INVALID_HEIGHT
|
||||
if (vmapHeight > INVALID_HEIGHT)
|
||||
{
|
||||
if (mapHeight > INVALID_HEIGHT)
|
||||
{
|
||||
// we have mapheight and vmapheight and must select more appropriate
|
||||
|
||||
// we are already under the surface or vmap height above map heigt
|
||||
// or if the distance of the vmap height is less the land height distance
|
||||
if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
|
||||
return vmapHeight;
|
||||
else
|
||||
return mapHeight; // better use .map surface height
|
||||
}
|
||||
else
|
||||
return vmapHeight; // we have only vmapHeight (if have)
|
||||
}
|
||||
|
||||
return mapHeight; // explicitly use map data
|
||||
}
|
||||
|
||||
float Map::GetGridHeight(float x, float y) const
|
||||
{
|
||||
if (GridTerrainData* gmap = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
||||
@ -1183,6 +1300,26 @@ float Map::GetGridHeight(float x, float y) const
|
||||
return INVALID_HEIGHT;
|
||||
}
|
||||
|
||||
float Map::GetGridHeightAccurate(float x, float y, float radius, float yaw) const
|
||||
{
|
||||
if (GridTerrainData* gmap = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
||||
{
|
||||
const auto shape = static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE));
|
||||
const float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||
const float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||
const uint32 mode = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE);
|
||||
const float eps = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_NORMAL_EPS);
|
||||
return gmap->GetHeightAccurate(x, y, radius, shape, yaw, blend, clamp, mode, eps);
|
||||
}
|
||||
|
||||
return INVALID_HEIGHT;
|
||||
}
|
||||
|
||||
float Map::GetGridHeightAccurate(float x, float y, float radius) const
|
||||
{
|
||||
return GetGridHeightAccurate(x, y, radius, 0.0f);
|
||||
}
|
||||
|
||||
float Map::GetMinHeight(float x, float y) const
|
||||
{
|
||||
if (GridTerrainData const* grid = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
||||
@ -1598,6 +1735,35 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
|
||||
return std::max<float>(h1, h2);
|
||||
}
|
||||
|
||||
float Map::GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius,
|
||||
bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||
{
|
||||
return GetHeightAccurate(phasemask, x, y, z, radius, 0.0f, vmap, maxSearchDist);
|
||||
}
|
||||
|
||||
float Map::GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, float yaw,
|
||||
bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||
{
|
||||
const float hMapMix = GetHeightAccurate(x, y, z, radius, yaw, vmap, maxSearchDist);
|
||||
|
||||
float hDyn;
|
||||
const bool dynAcc = (sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE) != 0);
|
||||
if (dynAcc)
|
||||
{
|
||||
const auto shape = static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE));
|
||||
const float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||
const float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||
const float dlt = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA);
|
||||
const float effBlend = (shape == GridTerrainData::GroundFootprintShape::Square) ? blend : 1.0f;
|
||||
hDyn = _dynamicTree.getHeightAccurate(x, y, z, maxSearchDist, phasemask, radius, yaw, effBlend, clamp, dlt);
|
||||
}
|
||||
else
|
||||
{
|
||||
hDyn = _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask);
|
||||
}
|
||||
return std::max<float>(hMapMix, hDyn);
|
||||
}
|
||||
|
||||
bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, float collisionHeight) const
|
||||
{
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, MAP_ALL_LIQUIDS);
|
||||
|
||||
@ -238,8 +238,12 @@ public:
|
||||
|
||||
// some calls like isInWater should not use vmaps due to processor power
|
||||
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
||||
[[nodiscard]] float GetHeightAccurate(float x, float y, float z, float radius, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; // wrapper yaw=0
|
||||
[[nodiscard]] float GetHeightAccurate(float x, float y, float z, float radius, float yaw, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||
[[nodiscard]] float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||
[[nodiscard]] float GetGridHeight(float x, float y) const;
|
||||
[[nodiscard]] float GetGridHeightAccurate(float x, float y, float radius) const; // wrapper yaw=0
|
||||
[[nodiscard]] float GetGridHeightAccurate(float x, float y, float radius, float yaw) const;
|
||||
[[nodiscard]] float GetMinHeight(float x, float y) const;
|
||||
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr);
|
||||
|
||||
@ -382,6 +386,8 @@ public:
|
||||
|
||||
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = DEFAULT_COLLISION_HEIGHT) const;
|
||||
[[nodiscard]] float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||
[[nodiscard]] float GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; // wrapper yaw=0
|
||||
[[nodiscard]] float GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, float yaw, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const;
|
||||
bool CanReachPositionAndGetValidCoords(WorldObject const* source, PathGenerator *path, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
|
||||
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
|
||||
@ -539,6 +545,9 @@ private:
|
||||
bool EnsureGridLoaded(Cell const& cell);
|
||||
MapGridType* GetMapGrid(uint16 const x, uint16 const y);
|
||||
|
||||
[[nodiscard]] float GetVMapHeightAccurate(float x, float y, float z, float radius, float yaw,
|
||||
GridTerrainData::GroundFootprintShape shape, float blend, float clamp, float sampleDelta) const;
|
||||
|
||||
void ScriptsProcess();
|
||||
|
||||
void SendObjectUpdates();
|
||||
|
||||
@ -2187,12 +2187,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(1);
|
||||
});
|
||||
|
||||
// Halls of Lightning, Arcing Burn
|
||||
ApplySpellFix({ 52671, 59834 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
|
||||
});
|
||||
|
||||
// Trial of the Champion, Death's Respite
|
||||
ApplySpellFix({ 68306 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
@ -285,6 +285,17 @@ void WorldConfig::BuildConfigCache()
|
||||
SetConfigValue<bool>(CONFIG_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
|
||||
SetConfigValue<float>(CONFIG_CHANCE_OF_GM_SURVEY, "GM.TicketSystem.ChanceOfGMSurvey", 50.0f);
|
||||
|
||||
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_SHAPE, "Height.Accurate.Shape", 0, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE, "Height.Accurate.RadiusScale", 1.0f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.1f && value <= 4.0f; }, ">= 0.1 and <= 4.0");
|
||||
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND, "Height.Accurate.SquareBlend", 0.20f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f && value <= 1.0f; }, ">= 0.0 and <= 1.0");
|
||||
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP, "Height.Accurate.SlopeClamp", 0.0f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f && value <= 10.0f; }, ">= 0.0 and <= 10.0");
|
||||
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE, "Height.Accurate.GradientMode", 0, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_NORMAL_EPS, "Height.Accurate.NormalEps", 1.0e-6f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 1e-8f && value <= 1e-3f; }, ">= 1e-8f and <= 1e-3f");
|
||||
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE, "Height.Accurate.VMap.Enable", 1, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_VMAP_DELTA, "Height.Accurate.VMap.Delta", 0.25f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.01f && value <= 1.0f; }, ">= 0.01f and <= 1.0f");
|
||||
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE, "Height.Accurate.Dynamic.Enable", 1, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA, "Height.Accurate.Dynamic.Delta", 0.25f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.01f && value <= 1.0f; }, ">= 0.01f and <= 1.0f");
|
||||
|
||||
SetConfigValue<uint32>(CONFIG_GROUP_VISIBILITY, "Visibility.GroupMode", 1);
|
||||
|
||||
SetConfigValue<bool>(CONFIG_OBJECT_SPARKLES, "Visibility.ObjectSparkles", true);
|
||||
|
||||
@ -484,7 +484,16 @@ enum ServerConfigs
|
||||
RATE_MISS_CHANCE_MULTIPLIER_TARGET_PLAYER,
|
||||
CONFIG_NEW_CHAR_STRING,
|
||||
CONFIG_VALIDATE_SKILL_LEARNED_BY_SPELLS,
|
||||
|
||||
CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE,
|
||||
CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND,
|
||||
CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP,
|
||||
CONFIG_HEIGHT_ACCURATE_SHAPE,
|
||||
CONFIG_HEIGHT_ACCURATE_NORMAL_EPS,
|
||||
CONFIG_HEIGHT_ACCURATE_VMAP_DELTA,
|
||||
CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA,
|
||||
CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE,
|
||||
CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE,
|
||||
CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE,
|
||||
MAX_NUM_SERVER_CONFIGS
|
||||
};
|
||||
|
||||
|
||||
@ -619,6 +619,7 @@ public:
|
||||
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||
|
||||
Map* map = object->GetMap();
|
||||
float zoneX = object->GetPositionX();
|
||||
float zoneY = object->GetPositionY();
|
||||
|
||||
@ -626,6 +627,22 @@ public:
|
||||
|
||||
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
|
||||
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
||||
const float probeR = object->GetGroundProbeRadius(); // pre-scale
|
||||
const float rScale = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE);
|
||||
const float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||
const float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||
const uint32 gmode = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE);
|
||||
const float neps = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_NORMAL_EPS);
|
||||
const uint32 vmapAcc = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE);
|
||||
const float vdelta = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_VMAP_DELTA);
|
||||
const uint32 dynAcc = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE);
|
||||
const float dyndelta = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA);
|
||||
const float yaw = object->GetOrientation();
|
||||
const float probeRScaled = probeR * rScale;
|
||||
|
||||
const float GridZAccurate = map->GetGridHeightAccurate(object->GetPositionX(), object->GetPositionY(), probeRScaled, yaw);
|
||||
const float MapZAccurate = object->GetMapHeightAccurate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), true, DEFAULT_HEIGHT_SEARCH, probeR);
|
||||
const char* shapeStr = GridTerrainData::ToString(static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE)));
|
||||
|
||||
uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
|
||||
uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
|
||||
@ -656,6 +673,12 @@ public:
|
||||
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
|
||||
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMAP);
|
||||
|
||||
handler->PSendSysMessage("Accurate Height Shape: {} (SquareBlend: {:0.2f}, RadiusScale: {:0.2f}, SlopeClamp: {:0.2f}, GradMode: {}, NormalEps: {:0.6f}, VMapAccurate: {}, VMapDelta: {:0.2f}, DynAccurate: {}, DynDelta: {:0.2f})",
|
||||
shapeStr, blend, rScale, clamp, gmode, neps, vmapAcc, vdelta, dynAcc, dyndelta);
|
||||
handler->PSendSysMessage("Accurate Height Grid: {}", GridZAccurate);
|
||||
handler->PSendSysMessage("Accurate Height Map: {}", MapZAccurate);
|
||||
handler->PSendSysMessage("Probe radius (pre-scale): {:0.3f}", probeR);
|
||||
|
||||
LiquidData const& liquidData = object->GetLiquidData();
|
||||
|
||||
if (liquidData.Status)
|
||||
|
||||
@ -41,6 +41,7 @@ enum VolkhanOther
|
||||
NPC_VOLKHAN_ANVIL = 28823,
|
||||
NPC_MOLTEN_GOLEM = 28695,
|
||||
NPC_BRITTLE_GOLEM = 28681,
|
||||
NPC_SLAG = 28585,
|
||||
|
||||
// Misc
|
||||
ACTION_SHATTER = 1,
|
||||
@ -77,7 +78,7 @@ enum Yells
|
||||
|
||||
struct boss_volkhan : public BossAI
|
||||
{
|
||||
boss_volkhan(Creature* creature) : BossAI(creature, DATA_VOLKHAN), summons(creature) { }
|
||||
boss_volkhan(Creature* creature) : BossAI(creature, DATA_VOLKHAN) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@ -104,6 +105,18 @@ struct boss_volkhan : public BossAI
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
std::list<Creature*> slags;
|
||||
GetCreatureListWithEntryInGrid(slags, me, NPC_SLAG, 100.0f);
|
||||
|
||||
if (!slags.empty())
|
||||
{
|
||||
for (Creature* slag : slags)
|
||||
{
|
||||
if (slag)
|
||||
slag->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetNextPos()
|
||||
@ -286,8 +299,6 @@ struct boss_volkhan : public BossAI
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
float x, y, z;
|
||||
uint8 PointID;
|
||||
uint8 ShatteredCount;
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
#include "CreatureScript.h"
|
||||
#include "GameObjectScript.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "Vehicle.h"
|
||||
#include <algorithm>
|
||||
|
||||
enum AlchemistItemRequirements
|
||||
{
|
||||
@ -234,297 +236,376 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum overlordDrakuru
|
||||
enum OverlordDrakuru
|
||||
{
|
||||
SPELL_SHADOW_BOLT = 54113,
|
||||
SPELL_SCOURGE_DISGUISE_EXPIRING = 52010,
|
||||
SPELL_THROW_BRIGHT_CRYSTAL = 54087,
|
||||
SPELL_TELEPORT_EFFECT = 52096,
|
||||
SPELL_SCOURGE_DISGUISE = 51966,
|
||||
SPELL_SCOURGE_DISGUISE_INSTANT_CAST = 52192,
|
||||
SPELL_BLIGHT_FOG = 54104,
|
||||
SPELL_THROW_PORTAL_CRYSTAL = 54209,
|
||||
SPELL_ARTHAS_PORTAL = 51807,
|
||||
SPELL_TOUCH_OF_DEATH = 54236,
|
||||
SPELL_DRAKURU_DEATH = 54248,
|
||||
SPELL_SUMMON_SKULL = 54253,
|
||||
SPELL_SHADOW_BOLT = 54113,
|
||||
SPELL_SCOURGE_DISGUISE_EXPIRING = 52010,
|
||||
SPELL_DROP_DISGUISE = 54089,
|
||||
SPELL_THROW_BRIGHT_CRYSTAL = 54087,
|
||||
SPELL_TELEPORT_EFFECT = 52096,
|
||||
SPELL_SCOURGE_SPOTLIGHT = 53104,
|
||||
SPELL_SCOURGE_DISGUISE = 51966,
|
||||
SPELL_SCOURGE_DISGUISE_INSTANT_CAST = 52192,
|
||||
SPELL_BLIGHT_FOG = 54104,
|
||||
SPELL_THROW_PORTAL_CRYSTAL = 54209,
|
||||
SPELL_ARTHAS_PORTAL = 51807,
|
||||
SPELL_TOUCH_OF_DEATH = 54236,
|
||||
SPELL_DRAKURU_DEATH = 54248,
|
||||
SPELL_SUMMON_SKULL = 54253,
|
||||
SPELL_BLOATED_ABOMINATION_FEIGN_DEATH = 52593,
|
||||
SPELL_EXPLODE_ABOMINATION_BLOODY_MEAT = 52523,
|
||||
SPELL_EXPLODE_ABOMINATION_MEAT = 52520,
|
||||
SPELL_DRAKURUS_SKULL_MISSILE = 54250,
|
||||
SPELL_BURST_AT_THE_SEAMS_BONE = 52516,
|
||||
|
||||
QUEST_BETRAYAL = 12713,
|
||||
QUEST_BETRAYAL = 12713,
|
||||
|
||||
NPC_BLIGHTBLOOD_TROLL = 28931,
|
||||
NPC_LICH_KING = 28498,
|
||||
NPC_BLIGHTBLOOD_TROLL = 28931,
|
||||
NPC_LICH_KING = 28498,
|
||||
NPC_TOTALLY_GENERIC_BUNNY = 29100,
|
||||
NPC_TOTALLY_GENERIC_BUNNY_JSB = 28960,
|
||||
GO_DRAKURUS_LAST_WISH = 202357,
|
||||
|
||||
EVENT_BETRAYAL_1 = 1,
|
||||
EVENT_BETRAYAL_2 = 2,
|
||||
EVENT_BETRAYAL_3 = 3,
|
||||
EVENT_BETRAYAL_4 = 4,
|
||||
EVENT_BETRAYAL_5 = 5,
|
||||
EVENT_BETRAYAL_6 = 6,
|
||||
EVENT_BETRAYAL_7 = 7,
|
||||
EVENT_BETRAYAL_8 = 8,
|
||||
EVENT_BETRAYAL_9 = 9,
|
||||
EVENT_BETRAYAL_10 = 10,
|
||||
EVENT_BETRAYAL_11 = 11,
|
||||
EVENT_BETRAYAL_12 = 12,
|
||||
EVENT_BETRAYAL_13 = 13,
|
||||
EVENT_BETRAYAL_14 = 14,
|
||||
EVENT_BETRAYAL_SHADOW_BOLT = 20,
|
||||
EVENT_BETRAYAL_CRYSTAL = 21,
|
||||
EVENT_BETRAYAL_COMBAT_TALK = 22,
|
||||
ACTION_SUMMON_DRAKURU_LAST_WISH = 1,
|
||||
ACTION_DESTROY_DRAKURU_LAST_WISH = 2,
|
||||
ACTION_REMOVE_SPOTLIGHTS = 3,
|
||||
|
||||
SAY_DRAKURU_0 = 0,
|
||||
SAY_DRAKURU_1 = 1,
|
||||
SAY_DRAKURU_2 = 2,
|
||||
SAY_DRAKURU_3 = 3,
|
||||
SAY_DRAKURU_4 = 4,
|
||||
SAY_DRAKURU_5 = 5,
|
||||
SAY_DRAKURU_6 = 6,
|
||||
SAY_DRAKURU_7 = 7,
|
||||
SAY_LICH_7 = 7,
|
||||
SAY_LICH_8 = 8,
|
||||
SAY_LICH_9 = 9,
|
||||
SAY_LICH_10 = 10,
|
||||
SAY_LICH_11 = 11,
|
||||
SAY_LICH_12 = 12,
|
||||
SUMMON_GROUP_BLIGHTBLOOD_TROLL = 1,
|
||||
|
||||
EVENT_BETRAYAL_INTRO_1 = 1,
|
||||
EVENT_BETRAYAL_INTRO_2 = 2,
|
||||
EVENT_BETRAYAL_INTRO_3 = 3,
|
||||
EVENT_BETRAYAL_INTRO_4 = 4,
|
||||
EVENT_BETRAYAL_EVADE_CHECK = 5,
|
||||
EVENT_BETRAYAL_EPILOGUE_1 = 6,
|
||||
EVENT_BETRAYAL_EPILOGUE_2 = 7,
|
||||
EVENT_BETRAYAL_EPILOGUE_3 = 8,
|
||||
EVENT_BETRAYAL_EPILOGUE_4 = 9,
|
||||
EVENT_BETRAYAL_EPILOGUE_5 = 10,
|
||||
EVENT_BETRAYAL_EPILOGUE_6 = 11,
|
||||
EVENT_BETRAYAL_EPILOGUE_7 = 12,
|
||||
EVENT_BETRAYAL_EPILOGUE_8 = 13,
|
||||
EVENT_BETRAYAL_EPILOGUE_9 = 14,
|
||||
EVENT_BETRAYAL_EPILOGUE_10 = 15,
|
||||
|
||||
SAY_DRAKURU_0 = 0,
|
||||
SAY_DRAKURU_1 = 1,
|
||||
SAY_DRAKURU_2 = 2,
|
||||
SAY_DRAKURU_3 = 3,
|
||||
SAY_DRAKURU_4 = 4,
|
||||
SAY_DRAKURU_5 = 5,
|
||||
SAY_DRAKURU_6 = 6,
|
||||
SAY_DRAKURU_7 = 7,
|
||||
SAY_LICH_7 = 7,
|
||||
SAY_LICH_8 = 8,
|
||||
SAY_LICH_9 = 9,
|
||||
SAY_LICH_10 = 10,
|
||||
SAY_LICH_11 = 11,
|
||||
SAY_LICH_12 = 12,
|
||||
};
|
||||
|
||||
class npc_overlord_drakuru_betrayal : public CreatureScript
|
||||
enum BetrayalState
|
||||
{
|
||||
public:
|
||||
npc_overlord_drakuru_betrayal() : CreatureScript("npc_overlord_drakuru_betrayal") { }
|
||||
BETRAYAL_NOT_STARTED,
|
||||
BETRAYAL_IN_PROGRESS,
|
||||
BETRAYAL_EPILOGUE,
|
||||
BETRAYAL_EVADE,
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct npc_overlord_drakuru_betrayal : public ScriptedAI
|
||||
{
|
||||
npc_overlord_drakuru_betrayal(Creature* creature) : ScriptedAI(creature), _summons(me), _state(BETRAYAL_NOT_STARTED)
|
||||
{
|
||||
return new npc_overlord_drakuru_betrayalAI(creature);
|
||||
me->SetCombatMovement(false);
|
||||
}
|
||||
|
||||
struct npc_overlord_drakuru_betrayalAI : public ScriptedAI
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
npc_overlord_drakuru_betrayalAI(Creature* creature) : ScriptedAI(creature), summons(me)
|
||||
{
|
||||
}
|
||||
if (_state != BETRAYAL_EVADE)
|
||||
return;
|
||||
me->SetFaction(FACTION_UNDEAD_SCOURGE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
ObjectGuid playerGUID;
|
||||
ObjectGuid lichGUID;
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
scheduler.CancelAll();
|
||||
_summons.DespawnAll();
|
||||
_playerGUID.Clear();
|
||||
_lichGUID.Clear();
|
||||
me->SetFaction(FACTION_UNDEAD_SCOURGE);
|
||||
me->SetVisible(false);
|
||||
DoAction(ACTION_SUMMON_DRAKURU_LAST_WISH);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetImmuneToPC(true);
|
||||
_state = BETRAYAL_NOT_STARTED;
|
||||
DoAction(ACTION_REMOVE_SPOTLIGHTS);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
if (playerGUID)
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
|
||||
if (player->IsWithinDistInMap(me, 80))
|
||||
return;
|
||||
me->SetFaction(FACTION_UNDEAD_SCOURGE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
ScriptedAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
playerGUID.Clear();
|
||||
lichGUID.Clear();
|
||||
me->SetFaction(FACTION_UNDEAD_SCOURGE);
|
||||
me->SetVisible(false);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (who->IsPlayer())
|
||||
case ACTION_SUMMON_DRAKURU_LAST_WISH:
|
||||
if (!me->FindNearestGameObject(GO_DRAKURUS_LAST_WISH, 80.0f))
|
||||
me->SummonGameObject(GO_DRAKURUS_LAST_WISH, 6185.989, -2029.6979, 590.87787, 0, 0, 0, 0, 0, 0, true, GO_SUMMON_TIMED_DESPAWN);
|
||||
break;
|
||||
case ACTION_DESTROY_DRAKURU_LAST_WISH:
|
||||
if (GameObject* go = me->FindNearestGameObject(GO_DRAKURUS_LAST_WISH, 80.0f))
|
||||
go->Delete();
|
||||
break;
|
||||
case ACTION_REMOVE_SPOTLIGHTS:
|
||||
{
|
||||
if (playerGUID)
|
||||
std::list<Creature*> creatures;
|
||||
me->GetCreatureListWithEntryInGrid(creatures, NPC_TOTALLY_GENERIC_BUNNY, 55.0f);
|
||||
for (Creature* creature : creatures)
|
||||
creature->RemoveAurasDueToSpell(SPELL_SCOURGE_SPOTLIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPlayerOnQuest(Player* player)
|
||||
{
|
||||
return player->GetQuestStatus(QUEST_BETRAYAL) == QUEST_STATUS_INCOMPLETE;
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (Player* player = who->ToPlayer())
|
||||
{
|
||||
bool shouldStartEvent = (_state == BETRAYAL_NOT_STARTED) && IsPlayerOnQuest(player) && player->HasAura(SPELL_SCOURGE_DISGUISE) && player->IsWithinDistInMap(me, 80.0f);
|
||||
if (shouldStartEvent)
|
||||
{
|
||||
me->SetVisible(true);
|
||||
_state = BETRAYAL_IN_PROGRESS;
|
||||
DoAction(ACTION_DESTROY_DRAKURU_LAST_WISH);
|
||||
_playerGUID = who->GetGUID();
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_INTRO_1, 6s);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EVADE_CHECK, 10s);
|
||||
}
|
||||
}
|
||||
else
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
_summons.Summon(summon);
|
||||
switch (summon->GetEntry())
|
||||
{
|
||||
case NPC_BLIGHTBLOOD_TROLL:
|
||||
if (Creature* target = summon->FindNearestCreature(NPC_TOTALLY_GENERIC_BUNNY, 10.0f, true))
|
||||
target->CastSpell(target, SPELL_TELEPORT_EFFECT, true);
|
||||
break;
|
||||
case NPC_LICH_KING:
|
||||
me->SetFacingToObject(summon);
|
||||
_lichGUID = summon->GetGUID();
|
||||
summon->GetMotionMaster()->MovePoint(0, 6164.2695, -2016.8978, 590.8636);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
scheduler.Schedule(0s, [this](TaskContext context)
|
||||
{
|
||||
if (!me->IsWithinMeleeRange(me->GetVictim()))
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
context.Repeat(2s);
|
||||
}).Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
|
||||
DoCast(target, SPELL_THROW_BRIGHT_CRYSTAL);
|
||||
context.Repeat(6s, 15s);
|
||||
}).Schedule(20s, [this](TaskContext context)
|
||||
{
|
||||
Talk(SAY_DRAKURU_4);
|
||||
context.Repeat(10s, 20s);
|
||||
});
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && !me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
{
|
||||
damage = 0;
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(2082);
|
||||
me->SetImmuneToPC(true);
|
||||
events.Reset();
|
||||
scheduler.CancelAll();
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_1, 4200ms);
|
||||
_state = BETRAYAL_EPILOGUE;
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||
{
|
||||
switch (spellInfo->Id)
|
||||
{
|
||||
case SPELL_THROW_PORTAL_CRYSTAL:
|
||||
if (Aura* aura = target->AddAura(SPELL_ARTHAS_PORTAL, target))
|
||||
aura->SetDuration(77'000);
|
||||
break;
|
||||
case SPELL_DRAKURUS_SKULL_MISSILE:
|
||||
target->CastSpell(target, SPELL_SUMMON_SKULL, true);
|
||||
break;
|
||||
case SPELL_DROP_DISGUISE:
|
||||
target->CastSpell(target, SPELL_SCOURGE_DISGUISE_EXPIRING, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_TOUCH_OF_DEATH)
|
||||
{
|
||||
DoCastAOE(SPELL_DRAKURUS_SKULL_MISSILE, true);
|
||||
DoCastSelf(SPELL_BLOATED_ABOMINATION_FEIGN_DEATH, true);
|
||||
DoCastSelf(SPELL_BURST_AT_THE_SEAMS_BONE, true);
|
||||
DoCastSelf(SPELL_BURST_AT_THE_SEAMS_BONE, true);
|
||||
DoCastSelf(SPELL_BURST_AT_THE_SEAMS_BONE, true);
|
||||
DoCastSelf(SPELL_EXPLODE_ABOMINATION_MEAT, true);
|
||||
DoCastSelf(SPELL_EXPLODE_ABOMINATION_BLOODY_MEAT, true);
|
||||
DoCastSelf(SPELL_EXPLODE_ABOMINATION_BLOODY_MEAT, true);
|
||||
DoCastSelf(SPELL_EXPLODE_ABOMINATION_BLOODY_MEAT, true);
|
||||
DoCastSelf(SPELL_DRAKURU_DEATH, true);
|
||||
DoAction(ACTION_SUMMON_DRAKURU_LAST_WISH);
|
||||
me->SetImmuneToPC(true);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_BETRAYAL_EVADE_CHECK:
|
||||
{
|
||||
if (_state == BETRAYAL_IN_PROGRESS)
|
||||
{
|
||||
if (who->GetGUID() != playerGUID)
|
||||
float radius = 80.0f;
|
||||
std::list<Player*> players;
|
||||
Acore::AnyPlayerInObjectRangeCheck checker(me, radius, true, true);
|
||||
Acore::PlayerListSearcher<Acore::AnyPlayerInObjectRangeCheck> searcher(me, players, checker);
|
||||
Cell::VisitObjects(me, searcher, radius);
|
||||
if (std::ranges::any_of(players, [this](Player* player)
|
||||
{
|
||||
Player* player = ObjectAccessor::GetPlayer(*me, playerGUID);
|
||||
if (player && player->IsWithinDistInMap(me, 80))
|
||||
who->ToPlayer()->NearTeleportTo(6143.76f, -1969.7f, 417.57f, 2.08f);
|
||||
else
|
||||
{
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
return;
|
||||
}
|
||||
return IsPlayerOnQuest(player);
|
||||
}))
|
||||
{
|
||||
events.Repeat(10s);
|
||||
}
|
||||
else
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
{
|
||||
_state = BETRAYAL_EVADE;
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
}
|
||||
}
|
||||
else if (who->ToPlayer()->GetQuestStatus(QUEST_BETRAYAL) == QUEST_STATUS_INCOMPLETE && who->HasAura(SPELL_SCOURGE_DISGUISE))
|
||||
break;
|
||||
}
|
||||
case EVENT_BETRAYAL_INTRO_1:
|
||||
Talk(SAY_DRAKURU_0);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_INTRO_2, 4s);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_INTRO_3, 6600ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_INTRO_2:
|
||||
me->SummonCreatureGroup(SUMMON_GROUP_BLIGHTBLOOD_TROLL);
|
||||
break;
|
||||
case EVENT_BETRAYAL_INTRO_3:
|
||||
Talk(SAY_DRAKURU_1);
|
||||
DoCastAOE(SPELL_DROP_DISGUISE);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_INTRO_4, 9600ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_INTRO_4:
|
||||
{
|
||||
Talk(SAY_DRAKURU_2);
|
||||
Talk(SAY_DRAKURU_3);
|
||||
me->SetImmuneToPC(false);
|
||||
std::list<Creature*> creatures;
|
||||
me->GetCreatureListWithEntryInGrid(creatures, NPC_TOTALLY_GENERIC_BUNNY, 55.0f);
|
||||
for (Creature* creature : creatures)
|
||||
creature->CastSpell(creature, SPELL_SCOURGE_SPOTLIGHT, true);
|
||||
break;
|
||||
}
|
||||
case EVENT_BETRAYAL_EPILOGUE_1:
|
||||
{
|
||||
Talk(SAY_DRAKURU_5);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_2, 4800ms);
|
||||
DoAction(ACTION_REMOVE_SPOTLIGHTS);
|
||||
break;
|
||||
}
|
||||
case EVENT_BETRAYAL_EPILOGUE_2:
|
||||
Talk(SAY_DRAKURU_6);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_3, 1800ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_3:
|
||||
DoCastSelf(SPELL_THROW_PORTAL_CRYSTAL, true);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_4, 3600ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_4:
|
||||
me->SummonCreature(NPC_LICH_KING, 6140.4233, -2010.9938, 589.1911, 6.126106, TEMPSUMMON_TIMED_DESPAWN, 77'000);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_5, 8400ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_5:
|
||||
Talk(SAY_DRAKURU_7);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_6, 9600ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_6:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, _lichGUID))
|
||||
{
|
||||
me->SetVisible(true);
|
||||
playerGUID = who->GetGUID();
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_1, 5s);
|
||||
lich->AI()->Talk(SAY_LICH_7);
|
||||
lich->AI()->Talk(SAY_LICH_8, 5400ms);
|
||||
}
|
||||
}
|
||||
else
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_7, 7800ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_7:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, _lichGUID))
|
||||
lich->CastSpell(me, SPELL_TOUCH_OF_DEATH, false);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_8, 4200ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_8:
|
||||
me->SetVisible(false);
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, _lichGUID))
|
||||
{
|
||||
lich->AI()->Talk(SAY_LICH_9, 3600ms);
|
||||
lich->AI()->Talk(SAY_LICH_10, 8400ms);
|
||||
lich->AI()->Talk(SAY_LICH_11, 22800ms);
|
||||
lich->AI()->Talk(SAY_LICH_12, 27600ms);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_9, 32600ms);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_EPILOGUE_10, 37200ms);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_9:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, _lichGUID))
|
||||
lich->GetMotionMaster()->MovePoint(0, 6141.2393, -2011.2728, 589.8653);
|
||||
break;
|
||||
case EVENT_BETRAYAL_EPILOGUE_10:
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
break;
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* cr) override
|
||||
{
|
||||
summons.Summon(cr);
|
||||
if (cr->GetEntry() == NPC_BLIGHTBLOOD_TROLL)
|
||||
cr->CastSpell(cr, SPELL_TELEPORT_EFFECT, true);
|
||||
else
|
||||
{
|
||||
me->SetFacingToObject(cr);
|
||||
lichGUID = cr->GetGUID();
|
||||
float o = me->GetAngle(cr);
|
||||
cr->GetMotionMaster()->MovePoint(0, me->GetPositionX() + cos(o) * 6.0f, me->GetPositionY() + std::sin(o) * 6.0f, me->GetPositionZ());
|
||||
}
|
||||
}
|
||||
if (me->GetFaction() == 2082 || me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_STUNNED))
|
||||
return;
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
Talk(SAY_DRAKURU_3);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_SHADOW_BOLT, 2s);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_CRYSTAL, 5s);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_COMBAT_TALK, 20s);
|
||||
}
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && !me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
{
|
||||
damage = 0;
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop();
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_4, 1s);
|
||||
}
|
||||
}
|
||||
scheduler.Update(diff);
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_THROW_PORTAL_CRYSTAL)
|
||||
if (Aura* aura = target->AddAura(SPELL_ARTHAS_PORTAL, target))
|
||||
aura->SetDuration(48000);
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
|
||||
{
|
||||
if (spellInfo->Id == SPELL_TOUCH_OF_DEATH)
|
||||
{
|
||||
me->CastSpell(me, SPELL_DRAKURU_DEATH, true);
|
||||
me->CastSpell(me, SPELL_SUMMON_SKULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_BETRAYAL_1:
|
||||
Talk(SAY_DRAKURU_0);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_2, 5s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_2:
|
||||
me->SummonCreature(NPC_BLIGHTBLOOD_TROLL, 6184.1f, -1969.9f, 586.76f, 4.5f);
|
||||
me->SummonCreature(NPC_BLIGHTBLOOD_TROLL, 6222.9f, -2026.5f, 586.76f, 2.9f);
|
||||
me->SummonCreature(NPC_BLIGHTBLOOD_TROLL, 6166.2f, -2065.4f, 586.76f, 1.4f);
|
||||
me->SummonCreature(NPC_BLIGHTBLOOD_TROLL, 6127.5f, -2008.7f, 586.76f, 0.0f);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_3, 5s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_3:
|
||||
Talk(SAY_DRAKURU_1);
|
||||
Talk(SAY_DRAKURU_2);
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
|
||||
player->CastSpell(player, SPELL_SCOURGE_DISGUISE_EXPIRING, true);
|
||||
if (Aura* aur = me->AddAura(SPELL_BLIGHT_FOG, me))
|
||||
aur->SetDuration(22000);
|
||||
break;
|
||||
case EVENT_BETRAYAL_4:
|
||||
Talk(SAY_DRAKURU_5);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_5, 6s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_5:
|
||||
Talk(SAY_DRAKURU_6);
|
||||
me->CastSpell(me, SPELL_THROW_PORTAL_CRYSTAL, true);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_6, 8s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_6:
|
||||
me->SummonCreature(NPC_LICH_KING, 6142.9f, -2011.6f, 590.86f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 41000);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_7, 8s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_7:
|
||||
Talk(SAY_DRAKURU_7);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_8, 5s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_8:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, lichGUID))
|
||||
lich->AI()->Talk(SAY_LICH_7);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_9, 6s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_9:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, lichGUID))
|
||||
{
|
||||
lich->AI()->Talk(SAY_LICH_8);
|
||||
lich->CastSpell(me, SPELL_TOUCH_OF_DEATH, false);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_10, 4s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_10:
|
||||
me->SetVisible(false);
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, lichGUID))
|
||||
lich->AI()->Talk(SAY_LICH_9);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_11, 4s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_11:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, lichGUID))
|
||||
lich->AI()->Talk(SAY_LICH_10);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_12, 6s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_12:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, lichGUID))
|
||||
lich->AI()->Talk(SAY_LICH_11);
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_13, 3s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_13:
|
||||
if (Creature* lich = ObjectAccessor::GetCreature(*me, lichGUID))
|
||||
{
|
||||
lich->AI()->Talk(SAY_LICH_12);
|
||||
lich->GetMotionMaster()->MovePoint(0, 6143.8f, -2011.5f, 590.9f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_BETRAYAL_14, 7s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_14:
|
||||
playerGUID.Clear();
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->GetFaction() == FACTION_FRIENDLY || me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_STUNNED))
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_BETRAYAL_SHADOW_BOLT:
|
||||
if (!me->IsWithinMeleeRange(me->GetVictim()))
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||
events.Repeat(2s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_CRYSTAL:
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, playerGUID))
|
||||
me->CastSpell(player, SPELL_THROW_BRIGHT_CRYSTAL, true);
|
||||
events.Repeat(6s, 15s);
|
||||
break;
|
||||
case EVENT_BETRAYAL_COMBAT_TALK:
|
||||
Talk(SAY_DRAKURU_4);
|
||||
events.Repeat(20s);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
private:
|
||||
SummonList _summons;
|
||||
ObjectGuid _playerGUID;
|
||||
ObjectGuid _lichGUID;
|
||||
BetrayalState _state;
|
||||
};
|
||||
|
||||
/*####
|
||||
@ -864,11 +945,32 @@ class spell_scourge_disguise_instability : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 54105 - Blight Fog
|
||||
class spell_blight_fog : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_blight_fog);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
targets.remove_if([](WorldObject* target) -> bool
|
||||
{
|
||||
float z = target->GetPositionZ();
|
||||
bool isInBlightFog = (582.0f <= z && z <= 583.0f) || (586.0f <= z && z <= 587.0f);
|
||||
return !isInBlightFog;
|
||||
});
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_blight_fog::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_zuldrak()
|
||||
{
|
||||
new npc_finklestein();
|
||||
new go_finklestein_cauldron();
|
||||
new npc_overlord_drakuru_betrayal();
|
||||
RegisterCreatureAI(npc_overlord_drakuru_betrayal);
|
||||
new npc_drakuru_shackles();
|
||||
new npc_captured_rageclaw();
|
||||
new npc_released_offspring_harkoa();
|
||||
@ -876,4 +978,5 @@ void AddSC_zuldrak()
|
||||
new go_scourge_enclosure();
|
||||
|
||||
RegisterSpellScript(spell_scourge_disguise_instability);
|
||||
RegisterSpellScript(spell_blight_fog);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user