Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
bash
2025-09-24 01:59:18 +02:00
committed by GitHub
25 changed files with 544 additions and 266 deletions
+8 -4
View File
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
# Set SUDO variable - one liner
SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "")
if [[ "$OSTYPE" == "msys"* ]]; then
SUDO=""
else
SUDO=$([ "$EUID" -ne 0 ] && echo "sudo" || echo "")
fi
function inst_configureOS() {
echo "Platform: $OSTYPE"
@@ -67,7 +71,7 @@ function inst_dbCreate() {
# In CI environments or when no password is set, try without password first
if [[ "$CONTINUOUS_INTEGRATION" == "true" ]]; then
echo "CI environment detected, attempting connection without password..."
if $SUDO mysql -u root < "$AC_PATH_ROOT/data/sql/create/create_mysql.sql" 2>/dev/null; then
echo "Database created successfully."
return 0
@@ -75,7 +79,7 @@ function inst_dbCreate() {
echo "Failed to connect without password, falling back to interactive mode..."
fi
fi
# Try with password (interactive mode)
echo "Please enter your sudo and your MySQL root password if prompted."
$SUDO mysql -u root -p < "$AC_PATH_ROOT/data/sql/create/create_mysql.sql"
@@ -178,4 +182,4 @@ function inst_download_client_data {
&& echo "unzip downloaded file in $path..." && unzip -q -o "$zipPath" -d "$path/" \
&& echo "Remove downloaded file" && rm "$zipPath" \
&& echo "INSTALLED_VERSION=$VERSION" > "$dataVersionFile"
}
}
+35 -31
View File
@@ -1,16 +1,16 @@
#!/usr/bin/env bash
# AzerothCore Dashboard Script
#
#
# This script provides an interactive menu system for AzerothCore management
# using the unified menu system library.
#
#
# Usage:
# ./acore.sh - Interactive mode with numeric and text selection
# ./acore.sh <command> [args] - Direct command execution (only text commands, no numbers)
#
# Interactive Mode:
# - Select options by number (1, 2, 3...), command name (init, compiler, etc.),
# - Select options by number (1, 2, 3...), command name (init, compiler, etc.),
# or short alias (i, c, etc.)
# - All selection methods work in interactive mode
#
@@ -35,6 +35,7 @@ menu_items=(
"install-deps|d|Configure OS dep"
"pull|u|Update Repository"
"reset|r|Reset & Clean Repository"
"setup-db|r|Install db only"
"compiler|c|Run compiler tool"
"module|m|Module manager (search/install/update/remove)"
"client-data|gd|download client data from github repository (beta)"
@@ -51,52 +52,55 @@ menu_items=(
function handle_menu_command() {
local key="$1"
shift
case "$key" in
"init")
inst_allInOne
"init")
inst_allInOne
;;
"install-deps")
inst_configureOS
"install-deps")
inst_configureOS
;;
"pull")
inst_updateRepo
"pull")
inst_updateRepo
;;
"reset")
inst_resetRepo
"reset")
inst_resetRepo
;;
"compiler")
bash "$AC_PATH_APPS/compiler/compiler.sh" "$@"
"setup-db")
inst_dbCreate
;;
"module")
bash "$AC_PATH_APPS/installer/includes/modules-manager/module-main.sh" "$@"
"compiler")
bash "$AC_PATH_APPS/compiler/compiler.sh" "$@"
;;
"client-data")
inst_download_client_data
"module")
bash "$AC_PATH_APPS/installer/includes/modules-manager/module-main.sh" "$@"
;;
"run-worldserver")
inst_simple_restarter worldserver
"client-data")
inst_download_client_data
;;
"run-authserver")
inst_simple_restarter authserver
"run-worldserver")
inst_simple_restarter worldserver
;;
"docker")
"run-authserver")
inst_simple_restarter authserver
;;
"docker")
DOCKER=1 bash "$AC_PATH_ROOT/apps/docker/docker-cmd.sh" "$@"
exit
exit
;;
"version")
"version")
printf "AzerothCore Rev. %s\n" "$ACORE_VERSION"
exit
exit
;;
"service-manager")
"service-manager")
bash "$AC_PATH_APPS/startup-scripts/src/service-manager.sh" "$@"
exit
exit
;;
"quit")
"quit")
echo "Goodbye!"
exit
exit
;;
*)
*)
echo "Invalid option. Use --help to see available commands."
return 1
;;
@@ -0,0 +1,7 @@
-- DB update 2025_09_23_01 -> 2025_09_23_02
--
DELETE FROM `spell_script_names` WHERE `spell_id` IN (66050, 62062, 66052) AND `ScriptName` = 'spell_item_brewfest_hops';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(66050, 'spell_item_brewfest_hops'),
(62062, 'spell_item_brewfest_hops'),
(66052, 'spell_item_brewfest_hops');
@@ -0,0 +1,99 @@
-- DB update 2025_09_23_02 -> 2025_09_23_03
--
UPDATE `spell_dbc` SET
`Attributes`=384,
`CastingTimeIndex`=1,
`DurationIndex`=3,
`RangeIndex`=7,
`EquippedItemClass`=-1,
`SchoolMask`=1,
`Effect_1`=76,
`ImplicitTargetA_1`=18,
`EffectMiscValue_1`=185541
WHERE `Id`=39797;
DELETE FROM `gameobject` WHERE `id`=185541;
UPDATE `creature_template` SET `AIName`='SmartAI', `unit_flags`=768 WHERE `entry`=22972;
DELETE FROM `smart_scripts` WHERE `entryorguid`=22972 AND `source_type`=0;
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (2297200,2297201,2297202) 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_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(22972, 0, 0, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 80, 2297200, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - On Just Summoned - Action list'),
(22972, 0, 1, 0, 54, 0, 100, 0, 0, 0, 0, 0, 0, 80, 2297201, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - On Just Summoned - Action list'),
(2297200, 9, 0, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Say text'),
(2297200, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 89, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Random Move'),
(2297200, 9, 2, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Say text'),
(2297200, 9, 3, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Say text'),
(2297200, 9, 4, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 30, 30, 90, 0, 'Cenarion Sparrowhawk - Action list - Move Offset'),
(2297200, 9, 5, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Despawn'),
(2297201, 9, 0, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Say text'),
(2297201, 9, 1, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 69, 1, 0, 0, 0, 0, 0, 19, 22986, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Random Move'),
(2297201, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Say text'),
(22972, 0, 2, 0, 34, 0, 100, 0, 8, 1, 0, 0, 0, 80, 2297202, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - On Movement Inform - Action list'),
(2297202, 9, 0, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Say text'),
(2297202, 9, 1, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 11, 39797, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Cast Summon Raven Stone'),
(2297202, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 19, 22986, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Despawn'),
(2297202, 9, 3, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 30, 30, 90, 0, 'Cenarion Sparrowhawk - Action list - Move Offset'),
(2297202, 9, 4, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Cenarion Sparrowhawk - Action list - Despawn');
DELETE FROM `creature_text` WHERE `CreatureID`=22972;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(22972, 0, 0, "%s looks at you for a moment, then motions for you to follow.", 16, 0, 100, 0, 0, 0, 20689, 0, 'Cenarion Sparrowhawk'),
(22972, 1, 0, '%s surveys the ground for buried raven stones.', 16, 0, 100, 0, 0, 0, 20675, 0, 'Cenarion Sparrowhawk'),
(22972, 2, 0, '%s locates a buried raven stone.', 16, 0, 100, 0, 0, 0, 20676, 0, 'Cenarion Sparrowhawk'),
(22972, 3, 0, "%s doesn't seem to have had any luck finding raven stones nearby.", 16, 0, 100, 0, 0, 0, 21065, 0, 'Cenarion Sparrowhawk');
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry`=22972 AND `SourceId`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(22, 1, 22972, 0, 0, 29, 1, 22986, 40, 0, 1, 0, 0, '', 'Only run SAI if No Invis Rune Stone within 40 yards'),
(22, 2, 22972, 0, 0, 29, 1, 22986, 40, 0, 0, 0, 0, '', 'Only run SAI if Invis Rune Stone within 40 yards');
SET @CGUID := 132442;
-- Replace ALL with sniffed spawns
DELETE FROM `creature` WHERE `id1`=22986;
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
(@CGUID+0 , 22986, 0, 0, 530, 3519, 3978, 1, 1, 0, -4180.95, 3124.89, 321.461, 6.14356, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+1 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4116.41, 3212.79, 299.878, 5.55015, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+2 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4088.1, 3247.53, 298.661, 0.191986, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+3 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4189.13, 3257.78, 292.119, 4.34587, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+4 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4056.92, 3349.51, 285.699, 3.80482, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+5 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4085.99, 3318.13, 288.276, 6.21337, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+6 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4135.11, 3297.11, 291.408, 5.34071, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+7 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4195.95, 3307.84, 284.269, 1.65806, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+8 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4145.48, 3366.98, 286.727, 2.46091, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+9 , 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4114.75, 3445.96, 291.581, 2.32129, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+10, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4045.76, 3442.87, 277.701, 0.872665, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+11, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4059.89, 3511.65, 284.039, 2.25147, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+12, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4108.45, 3544.02, 296.909, 2.56563, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+13, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4035.31, 3604.09, 289.025, 2.35619, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+14, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4047.76, 3670.26, 306.392, 2.87979, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+15, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3944.93, 3664.09, 287.99, 1.78024, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+16, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -4015.38, 3703.51, 296.596, 2.3911, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+17, 22986, 0, 0, 530, 3519, 3974, 1, 1, 0, -3904.37, 3726.72, 295.336, 2.37365, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+18, 22986, 0, 0, 530, 3519, 3974, 1, 1, 0, -3928.23, 3804, 296.871, 4.31096, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+19, 22986, 0, 0, 530, 3519, 3974, 1, 1, 0, -3868.97, 3813.03, 293.218, 2.60054, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+20, 22986, 0, 0, 530, 3519, 3974, 1, 1, 0, -3833.35, 3733.27, 285.779, 4.57276, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+21, 22986, 0, 0, 530, 3519, 3974, 1, 1, 0, -3758.84, 3732.39, 276.927, 0.575959, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+22, 22986, 0, 0, 530, 3519, 3974, 1, 1, 0, -3709.53, 3744.04, 277.156, 5.09636, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+23, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3687.76, 3677.07, 276.01, 4.31096, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+24, 22986, 0, 0, 530, 3519, 3680, 1, 1, 0, -3591.33, 3724.59, 286.079, 6.26573, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+25, 22986, 0, 0, 530, 3519, 3680, 1, 1, 0, -3585.6, 3606.65, 283.146, 4.7473, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+26, 22986, 0, 0, 530, 3519, 3680, 1, 1, 0, -3466.94, 3487.49, 286.668, 3.24631, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+27, 22986, 0, 0, 530, 3519, 3973, 1, 1, 0, -3518.43, 3586.55, 278.603, 0.488692, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+28, 22986, 0, 0, 530, 3519, 3978, 1, 1, 0, -4066.59, 3066.77, 318.167, 5.46288, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+29, 22986, 0, 0, 530, 3519, 3978, 1, 1, 0, -4002.09, 3002.9, 361.925, 2.21657, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+30, 22986, 0, 0, 530, 3519, 3977, 1, 1, 0, -3919.28, 3054.06, 359.032, 3.14159, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+31, 22986, 0, 0, 530, 3519, 3977, 1, 1, 0, -3868.7, 3107.64, 333.52, 4.39823, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+32, 22986, 0, 0, 530, 3519, 3977, 1, 1, 0, -3897.7, 3145.86, 326.602, 1.36136, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+33, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3889.21, 3200.03, 313.549, 4.85202, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+34, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3862.66, 3234.81, 307.935, 4.32842, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+35, 22986, 0, 0, 530, 3519, 3976, 1, 1, 0, -3777.56, 3341.35, 276.612, 2.56563, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+36, 22986, 0, 0, 530, 3519, 3975, 1, 1, 0, -3651.93, 3446.62, 279.142, 3.42085, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+37, 22986, 0, 0, 530, 3519, 3975, 1, 1, 0, -3690.24, 3390.89, 282.282, 1.23918, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+38, 22986, 0, 0, 530, 3519, 3975, 1, 1, 0, -3621.2, 3498.29, 277.993, 4.50295, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+39, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3623.24, 3372.64, 294.953, 2.33874, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+40, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3651.9, 3308.47, 285.5, 4.24115, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+41, 22986, 0, 0, 530, 3519, 3679, 1, 1, 0, -3716.68, 3343.7, 287.338, 3.89208, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+42, 22986, 0, 0, 530, 3519, 3680, 1, 1, 0, -3642.5, 3189.22, 314.679, 5.07891, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+43, 22986, 0, 0, 530, 3519, 3976, 1, 1, 0, -4015.76, 3328.22, 285.747, 3.82227, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745),
(@CGUID+44, 22986, 0, 0, 530, 3519, 3978, 1, 1, 0, -4259.69, 2987.85, 312.869, 2.05949, 120, 0, 0, 1604, 852, 0, 0, 0, 0, '', 45745);
+3
View File
@@ -231,6 +231,9 @@ public:
// Called when an aura is removed or expires.
virtual void OnAuraRemove(AuraApplication* /*aurApp*/, AuraRemoveMode /*mode*/) { }
virtual void DistancingStarted() {}
virtual void DistancingEnded() {}
protected:
virtual void MoveInLineOfSight(Unit* /*who*/);
+44 -50
View File
@@ -49,7 +49,6 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
mEvadeDisabled = false;
mCanAutoAttack = true;
mCanCombatMove = true;
mForcedPaused = false;
@@ -80,6 +79,9 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
m_ConditionsTimer = 0;
if (me->GetVehicleKit())
conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry());
_currentRangeMode = false;
_attackDistance = 0.f;
}
bool SmartAI::IsAIControlled() const
@@ -846,7 +848,7 @@ void SmartAI::AttackStart(Unit* who)
if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
{
if (mCanCombatMove)
if (!me->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT))
{
SetRun(mRun);
MovementGeneratorType type = me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE);
@@ -1047,37 +1049,49 @@ void SmartAI::sQuestReward(Player* player, Quest const* quest, uint32 opt)
GetScript()->ProcessEventsFor(SMART_EVENT_REWARD_QUEST, player, quest->GetQuestId(), opt);
}
void SmartAI::SetCombatMove(bool on, float chaseRange)
void SmartAI::SetCombatMovement(bool on, bool stopOrStartMovement)
{
if (mCanCombatMove == on)
if (on)
me->ClearUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT);
else
me->AddUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT);
if (!IsAIControlled() || HasEscortState(SMART_ESCORT_ESCORTING))
return;
mCanCombatMove = on;
if (!IsAIControlled())
return;
if (!HasEscortState(SMART_ESCORT_ESCORTING))
if (stopOrStartMovement && me->GetVictim()) // Only change current movement while in combat
{
if (on && me->GetVictim())
if (!me->IsCrowdControlled())
{
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE)
{
SetRun(mRun);
me->GetMotionMaster()->MoveChase(me->GetVictim(), chaseRange);
me->CastStop();
}
}
else
{
me->StopMoving();
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
if (on)
me->GetMotionMaster()->MoveChase(me->GetVictim());
else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->StopMoving();
}
}
}
void SmartAI::SetCurrentRangeMode(bool on, float range)
{
_currentRangeMode = on;
_attackDistance = range;
if (Unit* victim = me->GetVictim())
me->GetMotionMaster()->MoveChase(victim, _attackDistance);
}
void SmartAI::DistanceYourself(float range)
{
Unit* victim = me->GetVictim();
if (!victim || !victim->IsWithinMeleeRange(me))
return;
float combatReach = me->GetMeleeRange(victim);
float distance = DISTANCING_CONSTANT + std::max(combatReach * 1.5f, combatReach + range);
me->GetMotionMaster()->DistanceYourself(distance);
_pendingDistancing = distance;
}
void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, uint32 end, uint32 creditType, bool aliveState)
{
if (!target)
@@ -1130,32 +1144,6 @@ void SmartAI::StopFollow(bool complete)
GetScript()->ProcessEventsFor(SMART_EVENT_FOLLOW_COMPLETED, player);
}
void SmartAI::MoveAway(float distance)
{
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
return;
mCanCombatMove = false;
if (!IsAIControlled())
return;
if (!HasEscortState(SMART_ESCORT_ESCORTING))
{
if (me->GetVictim())
{
me->StopMoving();
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
me->GetMotionMaster()->Clear(false);
float x, y, z;
me->GetClosePoint(x, y, z, me->GetObjectSize(), distance, M_PI);
if (me->GetVictim()->IsWithinLOS(x, y, z))
me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, x, y, z);
}
}
}
void SmartAI::SetScript9(SmartScriptHolder& e, uint32 entry, WorldObject* invoker)
{
if (invoker)
@@ -1183,6 +1171,12 @@ void SmartAI::PathEndReached(uint32 /*pathId*/)
me->LoadPath(0);
}
void SmartAI::DistancingEnded()
{
SetCurrentRangeMode(true, _pendingDistancing);
_pendingDistancing = 0.f;
}
void SmartGameObjectAI::SummonedCreatureDies(Creature* summon, Unit* /*killer*/)
{
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMONED_UNIT_DIES, summon);
+10 -6
View File
@@ -40,6 +40,8 @@ enum SmartEscortVars
SMART_MAX_AID_DIST = SMART_ESCORT_MAX_PLAYER_DIST / 2,
};
#define DISTANCING_CONSTANT 1.f // buffer for better functionality of distancing
class SmartAI : public CreatureAI
{
public:
@@ -63,11 +65,11 @@ public:
bool IsEscorted() override { return (mEscortState & SMART_ESCORT_ESCORTING); }
void RemoveEscortState(uint32 uiEscortState) { mEscortState &= ~uiEscortState; }
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
void SetCombatMove(bool on, float chaseRange = 0.0f);
bool CanCombatMove() { return mCanCombatMove; }
void SetCombatMovement(bool on, bool stopOrStartMovement);
void SetCurrentRangeMode(bool on, float range = 0.f);
void DistanceYourself(float range);
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0, bool aliveState = true);
void StopFollow(bool complete);
void MoveAway(float distance);
void SetScript9(SmartScriptHolder& e, uint32 entry, WorldObject* invoker);
SmartScript* GetScript() { return &mScript; }
@@ -212,8 +214,7 @@ public:
// Xinef
void SetWPPauseTimer(uint32 time) { mWPPauseTimer = time; }
void SetChaseOnInterrupt(bool apply) { _chaseOnInterrupt = apply; }
[[nodiscard]] bool CanChaseOnInterrupt() const { return _chaseOnInterrupt; }
void DistancingEnded() override;
private:
bool mIsCharmed;
@@ -242,7 +243,6 @@ private:
bool mRun;
bool mEvadeDisabled;
bool mCanAutoAttack;
bool mCanCombatMove;
bool mForcedPaused;
uint32 mInvincibilityHpLevel;
@@ -263,6 +263,10 @@ private:
bool _chaseOnInterrupt;
std::unordered_map<uint32, uint32> aiDataSet;
bool _currentRangeMode;
float _attackDistance;
float _pendingDistancing;
};
class SmartGameObjectAI : public GameObjectAI
+29 -37
View File
@@ -686,7 +686,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
float spellMinRange = me->GetSpellMinRangeForTarget(target->ToUnit(), spellInfo);
float meleeRange = me->GetMeleeRange(target->ToUnit());
bool isWithinLOSInMap = me->IsWithinLOSInMap(target->ToUnit());
bool isWithinLOSInMap = me->IsWithinLOSInMap(target->ToUnit(), VMAP::ModelIgnoreFlags::M2);
bool isWithinMeleeRange = distanceToTarget <= meleeRange;
bool isRangedAttack = spellMaxRange > NOMINAL_MELEE_RANGE;
bool isTargetRooted = target->ToUnit()->HasUnitState(UNIT_STATE_ROOT);
@@ -703,7 +703,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
continue;
float minDistance = std::max(meleeRange, spellMinRange) - distanceToTarget + NOMINAL_MELEE_RANGE;
CAST_AI(SmartAI, me->AI())->MoveAway(std::min(minDistance, spellMaxRange));
CAST_AI(SmartAI, me->AI())->DistanceYourself(std::min(minDistance, spellMaxRange));
continue;
}
@@ -715,7 +715,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (me->IsRooted()) // Rooted inhabit type, never move/reposition
continue;
CAST_AI(SmartAI, me->AI())->SetCombatMove(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
continue;
}
else if (distanceToTarget < spellMinRange || !(isWithinLOSInMap || isSpellIgnoreLOS))
@@ -725,7 +725,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (me->IsRooted()) // Rooted inhabit type, never move/reposition
continue;
CAST_AI(SmartAI, me->AI())->SetCombatMove(true);
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, 0.f);
if (e.action.cast.castFlags & SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS)
CAST_AI(SmartAI, me->AI())->SetCombatMovement(true, true);
continue;
}
@@ -743,18 +745,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE)
{
CAST_AI(SmartAI, me->AI())->SetChaseOnInterrupt(true);
if (!me->isMoving()) // Don't try to reposition while we are moving
{
// 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.
if (result == SPELL_FAILED_OUT_OF_RANGE)
// if we are just out of range, we only chase until we are back in spell range.
CAST_AI(SmartAI, me->AI())->SetCombatMove(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
else
// if spell fail for any other reason, we chase to melee range, or stay where we are if spellcast was successful.
CAST_AI(SmartAI, me->AI())->SetCombatMove(spellCastFailed);
}
// 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.
if (result == SPELL_FAILED_OUT_OF_RANGE || result == SPELL_CAST_OK)
// if we are just out of range, we only chase until we are back in spell range.
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
else // move into melee on any other fail
// if spell fail for any other reason, we chase to melee range, or stay where we are if spellcast was successful.
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(false, 0.f);
}
if (spellCastFailed)
@@ -989,7 +986,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
bool move = e.action.combatMove.move;
CAST_AI(SmartAI, me->AI())->SetCombatMove(move);
CAST_AI(SmartAI, me->AI())->SetCombatMovement(move, true);
LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature {} bool on = {}",
me->GetGUID().ToString(), e.action.combatMove.move);
break;
@@ -2061,7 +2058,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (WorldObject* target : targets)
if (Creature* creature = target->ToCreature())
if (IsSmart(creature) && creature->GetVictim())
if (CAST_AI(SmartAI, creature->AI())->CanCombatMove())
if (!creature->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT))
creature->GetMotionMaster()->MoveChase(creature->GetVictim(), attackDistance, attackAngle);
break;
@@ -2730,26 +2727,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
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(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);
}
if (!(e.action.castCustom.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.castCustom.spell))
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.castCustom.spell);
CustomSpellValues values;
if (e.action.castCustom.bp1)
values.AddSpellMod(SPELLVALUE_BASE_POINT0, e.action.castCustom.bp1);
@@ -2757,7 +2737,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
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);
SpellCastResult result = me->CastCustomSpell(spellInfo, values, target->ToUnit(), (e.action.castCustom.flags & SMARTCAST_TRIGGERED) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
float spellMaxRange = me->GetSpellMaxRangeForTarget(target->ToUnit(), spellInfo);
if (e.action.cast.castFlags & 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.
if (result == SPELL_FAILED_OUT_OF_RANGE || result == SPELL_CAST_OK)
// if we are just out of range, we only chase until we are back in spell range.
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
else // move into melee on any other fail
// if spell fail for any other reason, we chase to melee range, or stay where we are if spellcast was successful.
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(false, 0.f);
}
}
}
}
@@ -1957,7 +1957,8 @@ enum SmartCastFlags
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
SMARTCAST_TARGET_POWER_MANA = 0x100 // Only cast if the target has power type mana (e.g. Mana Drain)
SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200,
};
enum SmartFollowType
+10 -8
View File
@@ -1081,7 +1081,6 @@ void ConditionMgr::LoadConditions(bool isReload)
LOG_INFO("server.loading", "Reloading `gossip_menu_option` Table for Conditions!");
sObjectMgr->LoadGossipMenuItems();
sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
}
QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, "
@@ -1405,7 +1404,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond)
// build new shared mask with found effect
uint32 sharedMask = (1 << i);
ConditionList* cmp = spellInfo->Effects[i].ImplicitTargetConditions;
std::shared_ptr<ConditionList> cmp = spellInfo->Effects[i].ImplicitTargetConditions;
for (uint8 effIndex = i + 1; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
{
if (spellInfo->Effects[effIndex].ImplicitTargetConditions == cmp)
@@ -1428,7 +1427,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond)
return false;
// get shared data
ConditionList* sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions;
std::shared_ptr<ConditionList> sharedList = spellInfo->Effects[firstEffIndex].ImplicitTargetConditions;
// there's already data entry for that sharedMask
if (sharedList)
@@ -1447,22 +1446,25 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond)
else
{
// add new list, create new shared mask
sharedList = new ConditionList();
auto newList = std::make_shared<ConditionList>();
bool assigned = false;
for (uint8 i = firstEffIndex; i < MAX_SPELL_EFFECTS; ++i)
{
if ((1 << i) & commonMask)
{
spellInfo->Effects[i].ImplicitTargetConditions = sharedList;
assigned = true;
spellInfo->Effects[i].ImplicitTargetConditions = newList;
assigned = true;
}
}
if (!assigned)
delete sharedList;
if (assigned)
sharedList = newList;
}
if (sharedList)
sharedList->push_back(cond);
break;
}
}
+5 -9
View File
@@ -1283,6 +1283,11 @@ SpellCastResult Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& v
return SPELL_FAILED_SPELL_UNAVAILABLE;
}
return CastCustomSpell(spellInfo, value, victim, triggerFlags, castItem, triggeredByAura, originalCaster);
}
SpellCastResult Unit::CastCustomSpell(SpellInfo const* spellInfo, CustomSpellValues const& value, Unit* victim, TriggerCastFlags triggerFlags, Item* castItem, AuraEffect const* triggeredByAura, ObjectGuid originalCaster)
{
SpellCastTargets targets;
targets.SetUnitTarget(victim);
@@ -4130,15 +4135,6 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi
spell->SetReferencedFromCurrent(false);
}
// SAI creatures only
// Start chasing victim if they are spell casters (at least one SMC spell) if interrupted/silenced.
if (IsCreature())
{
if (SmartAI* ai = dynamic_cast<SmartAI*>(ToCreature()->AI()))
if (ai->CanChaseOnInterrupt())
ai->SetCombatMove(true);
}
if (IsCreature() && IsAIEnabled)
ToCreature()->AI()->OnSpellCastFinished(spell->GetSpellInfo(), SPELL_FINISHED_CANCELED);
}
+3
View File
@@ -736,6 +736,8 @@ public:
[[nodiscard]] uint16 GetExtraUnitMovementFlags() const { return m_movementInfo.flags2; }
void SetExtraUnitMovementFlags(uint16 f) { m_movementInfo.flags2 = f; }
inline bool IsCrowdControlled() const { return HasFlag(UNIT_FIELD_FLAGS, (UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_STUNNED)); }
/*********************************************************/
/*** UNIT TYPES, CLASSES, RACES... ***/
/*********************************************************/
@@ -1595,6 +1597,7 @@ public:
SpellCastResult CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim, bool triggered, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
SpellCastResult CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
SpellCastResult CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
SpellCastResult CastCustomSpell(SpellInfo const* spellInfo, CustomSpellValues const& value, Unit* victim = nullptr, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = nullptr, AuraEffect const* triggeredByAura = nullptr, ObjectGuid originalCaster = ObjectGuid::Empty);
/*********************************************************/
/*** METHODS RELATED TO GAMEOBJECT & DYNOBEJCTS ***/
@@ -197,6 +197,8 @@ enum UnitState
UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator
UNIT_STATE_NO_ENVIRONMENT_UPD = 0x20000000,
UNIT_STATE_NO_COMBAT_MOVEMENT, // serverside only - should never be changed outside of core and hence shouldnt have a defined static value and be at the end
UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE
| UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED
| UNIT_STATE_DISTRACTED | UNIT_STATE_ISOLATED | UNIT_STATE_ATTACK_PLAYER | UNIT_STATE_CASTING
+36 -1
View File
@@ -310,12 +310,29 @@ void MotionMaster::MoveConfused()
/**
* @brief Force the unit to chase this target. Doesn't work with UNIT_FLAG_DISABLE_MOVE
*/
void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle)
void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle)
{
// ignore movement request if target not exist
if (!target || target == _owner || _owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
return;
if (GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
if (_owner->IsPlayer())
{
ChaseMovementGenerator<Player>* gen = (ChaseMovementGenerator<Player>*)top();
gen->SetOffsetAndAngle(dist, angle);
gen->SetNewTarget(target);
}
else
{
ChaseMovementGenerator<Creature>* gen = (ChaseMovementGenerator<Creature>*)top();
gen->SetOffsetAndAngle(dist, angle);
gen->SetNewTarget(target);
}
return;
}
//_owner->ClearUnitState(UNIT_STATE_FOLLOW);
if (_owner->IsPlayer())
{
@@ -331,6 +348,24 @@ void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std:
}
}
void MotionMaster::DistanceYourself(float dist)
{
if (GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
{
if (_owner->IsPlayer())
{
ChaseMovementGenerator<Player>* gen = (ChaseMovementGenerator<Player>*)top();
gen->DistanceYourself((Player*)_owner, dist);
}
else
{
ChaseMovementGenerator<Creature>* gen = (ChaseMovementGenerator<Creature>*)top();
gen->DistanceYourself((Creature*)_owner, dist);
}
return;
}
}
void MotionMaster::MoveBackwards(Unit* target, float dist)
{
if (!target)
+2
View File
@@ -250,6 +250,8 @@ public:
void ReinitializeMovement();
bool GetDestination(float& x, float& y, float& z);
void DistanceYourself(float range);
private:
void Mutate(MovementGenerator* m, MovementSlot slot); // use Move* functions instead
@@ -62,6 +62,81 @@ bool ChaseMovementGenerator<T>::PositionOkay(T* owner, Unit* target, Optional<fl
return true;
}
template<class T>
void ChaseMovementGenerator<T>::SetOffsetAndAngle(std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle)
{
_range = dist;
_angle = angle;
_lastTargetPosition.reset();
}
template<class T>
void ChaseMovementGenerator<T>::SetNewTarget(Unit* target)
{
i_target.link(target, this);
_lastTargetPosition.reset();
}
template<class T>
void ChaseMovementGenerator<T>::DistanceYourself(T* owner, float distance)
{
// make a new path if we have to...
if (!i_path)
i_path = std::make_unique<PathGenerator>(owner);
float x, y, z;
i_target->GetNearPoint(owner, x, y, z, owner->GetBoundaryRadius(), distance, i_target->GetAngle(owner));
if (DispatchSplineToPosition(owner, x, y, z, false, false, 0.f, false, false))
{
m_currentMode = CHASE_MODE_DISTANCING;
if constexpr (!std::is_same_v<T, Player>)
{
owner->AI()->DistancingStarted();
}
}
}
template<class T>
bool ChaseMovementGenerator<T>::DispatchSplineToPosition(T* owner, float x, float y, float z, bool walk, bool cutPath, float maxTarget, bool forceDest, bool target)
{
Creature* cOwner = owner->ToCreature();
if (owner->IsHovering())
owner->UpdateAllowedPositionZ(x, y, z);
bool success = i_path->CalculatePath(x, y, z, forceDest);
if (!success || i_path->GetPathType() & PATHFIND_NOPATH)
{
if (cOwner)
{
cOwner->SetCannotReachTarget(i_target.getTarget()->GetGUID());
}
owner->StopMoving();
return true;
}
if (cutPath)
i_path->ShortenPathUntilDist(G3D::Vector3(x, y, z), maxTarget);
if (cOwner)
{
cOwner->SetCannotReachTarget();
}
owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
i_recalculateTravel = true;
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
if (target)
init.SetFacing(i_target.getTarget());
init.SetWalk(walk);
init.Launch();
return false;
}
template<class T>
bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
{
@@ -71,6 +146,13 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
if (!owner || !owner->IsAlive())
return false;
if (owner->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT)) // script paused combat movement
{
owner->StopMoving();
_lastTargetPosition.reset();
return true;
}
Creature* cOwner = owner->ToCreature();
bool isStoppedBecauseOfCasting = cOwner && cOwner->IsMovementPreventedByCasting();
@@ -243,53 +325,23 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
shortenPath = false;
}
if (owner->IsHovering())
owner->UpdateAllowedPositionZ(x, y, z);
bool success = i_path->CalculatePath(x, y, z, forceDest);
if (!success || i_path->GetPathType() & PATHFIND_NOPATH)
{
if (cOwner)
{
cOwner->SetCannotReachTarget(target->GetGUID());
}
owner->StopMoving();
return true;
}
if (shortenPath)
i_path->ShortenPathUntilDist(G3D::Vector3(x, y, z), maxTarget);
if (cOwner)
{
cOwner->SetCannotReachTarget();
}
bool walk = false;
if (cOwner && !cOwner->IsPet())
{
switch (cOwner->GetMovementTemplate().GetChase())
{
case CreatureChaseMovementType::CanWalk:
walk = owner->IsWalking();
break;
case CreatureChaseMovementType::AlwaysWalk:
walk = true;
break;
default:
break;
case CreatureChaseMovementType::CanWalk:
walk = owner->IsWalking();
break;
case CreatureChaseMovementType::AlwaysWalk:
walk = true;
break;
default:
break;
}
}
owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
i_recalculateTravel = true;
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
init.SetFacing(target);
init.SetWalk(walk);
init.Launch();
DispatchSplineToPosition(owner, x, y, z, walk, shortenPath, maxTarget, forceDest, true);
}
}
@@ -339,9 +391,24 @@ void ChaseMovementGenerator<T>::MovementInform(T* owner)
if (!owner->IsCreature())
return;
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
if (CreatureAI* AI = owner->ToCreature()->AI())
AI->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter());
switch (m_currentMode)
{
default:
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
if (CreatureAI* AI = owner->ToCreature()->AI())
AI->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter());
break;
}
case CHASE_MODE_DISTANCING:
{
if (CreatureAI* AI = owner->ToCreature()->AI())
AI->DistancingEnded();
break;
}
}
m_currentMode = CHASE_MODE_NORMAL;
}
//-----------------------------------------------//
@@ -604,6 +671,13 @@ template bool ChaseMovementGenerator<Player>::DoUpdate(Player*, uint32);
template bool ChaseMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
template void ChaseMovementGenerator<Unit>::MovementInform(Unit*);
template void ChaseMovementGenerator<Creature>::SetOffsetAndAngle(std::optional<ChaseRange>, std::optional<ChaseAngle>);
template void ChaseMovementGenerator<Creature>::SetNewTarget(Unit*);
template void ChaseMovementGenerator<Creature>::DistanceYourself(Creature*, float);
template void ChaseMovementGenerator<Player>::SetOffsetAndAngle(std::optional<ChaseRange>, std::optional<ChaseAngle>);
template void ChaseMovementGenerator<Player>::SetNewTarget(Unit*);
template void ChaseMovementGenerator<Player>::DistanceYourself(Player*, float);
template void FollowMovementGenerator<Player>::DoInitialize(Player*);
template void FollowMovementGenerator<Creature>::DoInitialize(Creature*);
template void FollowMovementGenerator<Player>::DoFinalize(Player*);
@@ -34,12 +34,20 @@ protected:
FollowerReference i_target;
};
enum ChaseMovementMode
{
CHASE_MODE_NORMAL, // chasing target
CHASE_MODE_BACKPEDAL, // collision movement
CHASE_MODE_DISTANCING, // running away from melee
CHASE_MODE_FANNING, // mob collision movement
};
template<class T>
class ChaseMovementGenerator : public MovementGeneratorMedium<T, ChaseMovementGenerator<T>>, public TargetedMovementGeneratorBase
{
public:
ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range = {}, Optional<ChaseAngle> angle = {})
: TargetedMovementGeneratorBase(target), i_leashExtensionTimer(5000), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle) {}
: TargetedMovementGeneratorBase(target), i_leashExtensionTimer(5000), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle), m_currentMode(CHASE_MODE_NORMAL) {}
~ChaseMovementGenerator() { }
MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
@@ -58,6 +66,11 @@ public:
bool EnableWalking() const { return false; }
bool HasLostTarget(Unit* unit) const { return unit->GetVictim() != this->GetTarget(); }
void SetOffsetAndAngle(std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle);
void SetNewTarget(Unit* target);
void DistanceYourself(T* owner, float distance);
bool DispatchSplineToPosition(T* owner, float x, float y, float z, bool walk, bool cutPath, float maxTarget, bool forceDest, bool target = false);
private:
TimeTrackerSmall i_leashExtensionTimer;
std::unique_ptr<PathGenerator> i_path;
@@ -65,10 +78,12 @@ private:
bool i_recalculateTravel;
Optional<Position> _lastTargetPosition;
Optional<ChaseRange> const _range;
Optional<ChaseAngle> const _angle;
Optional<ChaseRange> _range;
Optional<ChaseAngle> _angle;
bool _movingTowards = true;
bool _mutualChase = true;
ChaseMovementMode m_currentMode;
};
template<class T>
+23 -12
View File
@@ -1126,7 +1126,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar
break;
}
ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
std::shared_ptr<ConditionList> condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
// handle emergency case - try to use other provided targets if no conditions provided
if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
@@ -1221,7 +1221,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
std::list<WorldObject*> targets;
SpellTargetObjectTypes objectType = targetType.GetObjectType();
SpellTargetCheckTypes selectionType = targetType.GetCheckType();
ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
std::shared_ptr<ConditionList> condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
float coneAngle = M_PI / 2;
float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
@@ -2119,7 +2119,7 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex)
}
}
uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList)
uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, std::shared_ptr<ConditionList> condList)
{
// this function selects which containers need to be searched for spell target
uint32 retMask = GRID_MAP_TYPE_MASK_ALL;
@@ -2164,7 +2164,9 @@ void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* refere
Cell::VisitObjects(pos->GetPositionX(), pos->GetPositionY(), referer->GetMap(), searcher, radius);
}
WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList)
WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objectType,
SpellTargetCheckTypes selectionType,
std::shared_ptr<ConditionList> condList)
{
WorldObject* target = nullptr;
uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
@@ -2176,7 +2178,11 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargetObjectTypes objec
return target;
}
void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList)
void Spell::SearchAreaTargets(std::list<WorldObject*> &targets, float range,
Position const *position, Unit *referer,
SpellTargetObjectTypes objectType,
SpellTargetCheckTypes selectionType,
std::shared_ptr<ConditionList> condList)
{
uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
if (!containerTypeMask)
@@ -2186,7 +2192,11 @@ void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Pos
SearchTargets<Acore::WorldObjectListSearcher<Acore::WorldObjectSpellAreaTargetCheck> > (searcher, containerTypeMask, m_caster, position, range);
}
void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellTargetSelectionCategories /*selectCategory*/, ConditionList* condList, bool isChainHeal)
void Spell::SearchChainTargets(
std::list<WorldObject*> &targets, uint32 chainTargets, WorldObject *target,
SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType,
SpellTargetSelectionCategories /*selectCategory*/,
std::shared_ptr<ConditionList> condList, bool isChainHeal)
{
// max dist for jump target selection
float jumpRadius = 0.0f;
@@ -2223,7 +2233,8 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
WorldObject* chainSource = m_spellInfo->HasAttribute(SPELL_ATTR2_CHAIN_FROM_CASTER) ? m_caster : target;
std::list<WorldObject*> tempTargets;
SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster, objectType, selectType, condList);
SearchAreaTargets(tempTargets, searchRadius, chainSource, m_caster,
objectType, selectType, condList);
tempTargets.remove(target);
// remove targets which are always invalid for chain spells
@@ -8984,7 +8995,7 @@ namespace Acore
{
WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo,
SpellTargetCheckTypes selectionType, ConditionList* condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
_targetSelectionType(selectionType), _condList(condList)
{
if (condList)
@@ -9067,7 +9078,7 @@ namespace Acore
}
WorldObjectSpellNearbyTargetCheck::WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
SpellTargetCheckTypes selectionType, ConditionList* condList)
SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList)
: WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(caster)
{
}
@@ -9084,7 +9095,7 @@ namespace Acore
}
WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster,
Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList)
Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList)
: WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList), _range(range), _position(position)
{
}
@@ -9104,7 +9115,7 @@ namespace Acore
}
WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster,
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList)
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList)
: WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList), _coneAngle(coneAngle)
{
}
@@ -9130,7 +9141,7 @@ namespace Acore
}
WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster,
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList)
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList)
: WorldObjectSpellAreaTargetCheck(range, position, caster, caster, spellInfo, selectionType, condList)
{
}
+23 -10
View File
@@ -445,12 +445,25 @@ public:
void SelectEffectTypeImplicitTargets(uint8 effIndex);
uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList);
uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType,
std::shared_ptr<ConditionList> condList);
template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius);
WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList = nullptr);
void SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, Unit* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionList* condList);
void SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellTargetSelectionCategories selectCategory, ConditionList* condList, bool isChainHeal);
WorldObject* SearchNearbyTarget(float range, SpellTargetObjectTypes objectType,
SpellTargetCheckTypes selectionType,
std::shared_ptr<ConditionList> condList = nullptr);
void SearchAreaTargets(std::list<WorldObject *> &targets, float range,
Position const *position, Unit *referer,
SpellTargetObjectTypes objectType,
SpellTargetCheckTypes selectionType,
std::shared_ptr<ConditionList> condList);
void SearchChainTargets(std::list<WorldObject *> &targets,
uint32 chainTargets, WorldObject *target,
SpellTargetObjectTypes objectType,
SpellTargetCheckTypes selectType,
SpellTargetSelectionCategories selectCategory,
std::shared_ptr<ConditionList> condList,
bool isChainHeal);
SpellCastResult prepare(SpellCastTargets const* targets, AuraEffect const* triggeredByAura = nullptr);
void cancel(bool bySelf = false);
@@ -801,10 +814,10 @@ namespace Acore
SpellInfo const* _spellInfo;
SpellTargetCheckTypes _targetSelectionType;
ConditionSourceInfo* _condSrcInfo;
ConditionList* _condList;
std::shared_ptr<ConditionList> _condList;
WorldObjectSpellTargetCheck(Unit* caster, Unit* referer, SpellInfo const* spellInfo,
SpellTargetCheckTypes selectionType, ConditionList* condList);
SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList);
~WorldObjectSpellTargetCheck();
bool operator()(WorldObject* target);
};
@@ -814,7 +827,7 @@ namespace Acore
float _range;
Position const* _position;
WorldObjectSpellNearbyTargetCheck(float range, Unit* caster, SpellInfo const* spellInfo,
SpellTargetCheckTypes selectionType, ConditionList* condList);
SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList);
bool operator()(WorldObject* target);
};
@@ -823,7 +836,7 @@ namespace Acore
float _range;
Position const* _position;
WorldObjectSpellAreaTargetCheck(float range, Position const* position, Unit* caster,
Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList);
Unit* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList);
bool operator()(WorldObject* target);
};
@@ -831,14 +844,14 @@ namespace Acore
{
float _coneAngle;
WorldObjectSpellConeTargetCheck(float coneAngle, float range, Unit* caster,
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList);
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList);
bool operator()(WorldObject* target);
};
struct WorldObjectSpellTrajTargetCheck : public WorldObjectSpellAreaTargetCheck
{
WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster,
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionList* condList);
SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, std::shared_ptr<ConditionList> condList);
bool operator()(WorldObject* target);
};
}
-22
View File
@@ -863,11 +863,6 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
_requireCooldownInfo = false;
}
SpellInfo::~SpellInfo()
{
_UnloadImplicitTargetConditionLists();
}
uint32 SpellInfo::GetCategory() const
{
return CategoryEntry ? CategoryEntry->Id : 0;
@@ -2873,23 +2868,6 @@ bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB)
return true;
}
void SpellInfo::_UnloadImplicitTargetConditionLists()
{
// find the same instances of ConditionList and delete them.
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
ConditionList* cur = Effects[i].ImplicitTargetConditions;
if (!cur)
continue;
for (uint8 j = i; j < MAX_SPELL_EFFECTS; ++j)
{
if (Effects[j].ImplicitTargetConditions == cur)
Effects[j].ImplicitTargetConditions = nullptr;
}
delete cur;
}
}
bool SpellInfo::CheckElixirStacking(Unit const* caster) const
{
if (!caster)
+3 -3
View File
@@ -39,6 +39,7 @@ struct SpellRadiusEntry;
struct SpellEntry;
struct SpellCastTimesEntry;
struct Condition;
typedef std::list<Condition*> ConditionList;
enum SpellCastTargetFlags
{
@@ -270,12 +271,12 @@ public:
uint32 ItemType;
uint32 TriggerSpell;
flag96 SpellClassMask;
std::list<Condition*>* ImplicitTargetConditions;
std::shared_ptr<ConditionList> ImplicitTargetConditions;
SpellEffectInfo() : _spellInfo(nullptr), _effIndex(0), Effect(0), ApplyAuraName(0), Amplitude(0), DieSides(0),
RealPointsPerLevel(0), BasePoints(0), PointsPerComboPoint(0), ValueMultiplier(0), DamageMultiplier(0),
BonusMultiplier(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(nullptr), ChainTarget(0),
ItemType(0), TriggerSpell(0), ImplicitTargetConditions(nullptr) {}
ItemType(0), TriggerSpell(0), ImplicitTargetConditions() {}
SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex);
bool IsEffect() const;
@@ -403,7 +404,6 @@ public:
bool _requireCooldownInfo;
SpellInfo(SpellEntry const* spellEntry);
~SpellInfo();
uint32 GetCategory() const;
bool HasEffect(SpellEffects effect) const;
-9
View File
@@ -2766,15 +2766,6 @@ void SpellMgr::UnloadSpellInfoStore()
mSpellInfoMap.clear();
}
void SpellMgr::UnloadSpellInfoImplicitTargetConditionLists()
{
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
if (mSpellInfoMap[i])
mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists();
}
}
void SpellMgr::LoadSpellSpecificAndAuraState()
{
uint32 oldMSTime = getMSTime();
-1
View File
@@ -786,7 +786,6 @@ public:
void LoadSpellInfoStore();
void LoadSpellCooldownOverrides();
void UnloadSpellInfoStore();
void UnloadSpellInfoImplicitTargetConditionLists();
void LoadSpellInfoCustomAttributes();
void LoadSpellInfoCorrections();
void LoadSpellSpecificAndAuraState();
@@ -887,6 +887,7 @@ static LocationXYZO ThrallSpawn[] =
// Valimathras Trashspawn
{ 1325.059f, 332.652f, -65.027f, 2.186f },
{ 1270.474f, 350.982f, -65.027f, 0.034f },
{ 1805.753f, 285.499f, 70.399f, 4.691f }
};
#define GOSSIP_WRYNN "Reporting for duty, your majesty! Let the assault begin!"
@@ -2382,7 +2383,8 @@ public:
switch (summoned->GetEntry())
{
case NPC_BLIGHT_ABBERATION:
summoned->AI()->AttackStart(me);
summoned->SetHomePosition(me->GetPosition());
summoned->AddThreat(me, 100.0f);
break;
case NPC_WARSONG_BATTLEGUARD:
summoned->ApplySpellImmune(0, IMMUNITY_ID, SPELL_SYLVANAS_BUFF, true);
@@ -2424,6 +2426,10 @@ public:
me->AddThreat(summoned, 100.0f);
summoned->AI()->AttackStart(me);
break;
case NPC_KHANOK:
summoned->SetHomePosition(me->GetPosition());
summoned->AddThreat(me, 100.0f);
summoned->AI()->AttackStart(me);
default:
break;
}
@@ -2580,10 +2586,8 @@ public:
// Bossspawn 1
if (Creature* temp = me->SummonCreature(NPC_BLIGHT_ABBERATION, ThrallSpawn[28].x, ThrallSpawn[28].y, ThrallSpawn[28].z, ThrallSpawn[28].o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900 * IN_MILLISECONDS))
{
temp->GetMotionMaster()->MoveJump(ThrallSpawn[62].x, ThrallSpawn[62].y, ThrallSpawn[62].z, 10.0f, 20.0f, 0);
temp->AddThreat(me, 100.0f);
me->AddThreat(temp, 100.0f);
temp->AI()->AttackStart(me);
me->AI()->AttackStart(temp);
}
break;
case 6:
@@ -2747,7 +2751,11 @@ public:
break;
// NPC_KHANOK - Inner Sunktum Spawn Middle
case 17:
me->SummonCreature(NPC_KHANOK, ThrallSpawn[68].x, ThrallSpawn[68].y, ThrallSpawn[68].z, TEMPSUMMON_DEAD_DESPAWN);
if (Creature* temp = me->SummonCreature(NPC_KHANOK, ThrallSpawn[68].x, ThrallSpawn[68].y, ThrallSpawn[68].z, TEMPSUMMON_DEAD_DESPAWN))
{
me->AddThreat(temp, 100.0f);
me->AI()->AttackStart(temp);
}
break;
case 18:
if (Creature* temp = me->SummonCreature(NPC_WARSONG_BATTLEGUARD, ThrallSpawn[69].x, ThrallSpawn[69].y, ThrallSpawn[69].z, ThrallSpawn[69].o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 240 * IN_MILLISECONDS))
@@ -3167,9 +3175,8 @@ public:
me->GetCreatureListWithEntryInGrid(HostileList, NPC_DOCTOR_H, 1000.0f);
me->GetCreatureListWithEntryInGrid(HostileList, NPC_CHEMIST_H, 1000.0f);
me->GetCreatureListWithEntryInGrid(HostileList, NPC_BLIGHT_SLINGER, 1000.0f);
if (!HostileList.empty())
for (std::list<Creature*>::iterator itr = HostileList.begin(); itr != HostileList.end(); itr++)
(*itr)->DespawnOrUnsummon();
for (auto& creature : HostileList)
creature->DespawnOrUnsummon();
for (uint8 i = 0; i < 7; ++i)
me->SummonGameObject(GO_HORDE_BANNER, ThrallSpawn[i + 37].x, ThrallSpawn[i + 37].y, ThrallSpawn[i + 37].z, ThrallSpawn[i + 37].o, 0.0f, 0.0f, 0.0f, 0.0f, 120 * IN_MILLISECONDS);
SpawnWave(6);
@@ -3620,9 +3627,11 @@ public:
valimathras->RemoveAura(SPELL_AURA_OF_VARIMATHRAS);
valimathras->RemoveAura(SPELL_OPENING_LEGION_PORTALS);
valimathras->AI()->Talk(SAY_VALIMATHRAS_ATTACK);
valimathras->SetHomePosition(me->GetPosition());
valimathras->AddThreat(me, 100.0f);
me->AddThreat(valimathras, 100.0f);
valimathras->AI()->AttackStart(me);
me->AI()->AttackStart(valimathras);
}
bStepping = false;
JumpToNextStep(0 * IN_MILLISECONDS);
@@ -3945,7 +3954,6 @@ public:
{
me->SetCorpseDelay(1);
me->SetRespawnTime(1);
_events.ScheduleEvent(EVENT_SUMMON_SKELETON, 20s);
_events.ScheduleEvent(EVENT_BLACK_ARROW, 15s);
_events.ScheduleEvent(EVENT_SHOOT, 5s);
_events.ScheduleEvent(EVENT_MULTI_SHOT, 6s);
@@ -3974,10 +3982,6 @@ public:
{
switch (eventId)
{
case EVENT_SUMMON_SKELETON:
DoCast(me, SPELL_SUMMON_SKELETON);
_events.ScheduleEvent(EVENT_SUMMON_SKELETON, 20s, 30s);
break;
case EVENT_BLACK_ARROW:
if (Unit* victim = me->GetVictim())
DoCast(victim, SPELL_BLACK_ARROW);
+49 -4
View File
@@ -3147,6 +3147,7 @@ enum BrewfestMountTransformation
SPELL_MOUNT_KODO_60 = 49378,
SPELL_BREWFEST_MOUNT_TRANSFORM = 49357,
SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE = 52845,
SPELL_FRESH_DWARVEN_HOPS = 66050,
};
class spell_item_brewfest_mount_transformation : public SpellScript
@@ -3169,25 +3170,26 @@ class spell_item_brewfest_mount_transformation : public SpellScript
Player* caster = GetCaster()->ToPlayer();
if (!caster)
{
return;
}
if (caster->HasMountedAura())
{
float speed = caster->GetSpeedRate(MOVE_RUN);
caster->RemoveAurasByType(SPELL_AURA_MOUNTED);
uint32 spell_id;
switch (GetSpellInfo()->Id)
{
case SPELL_BREWFEST_MOUNT_TRANSFORM:
if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f)
if (speed >= 2.0f)
spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100;
else
spell_id = caster->GetTeamId() == TEAM_ALLIANCE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60;
break;
case SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE:
if (caster->GetSpeedRate(MOVE_RUN) >= 2.0f)
if (speed >= 2.0f)
spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_100 : SPELL_MOUNT_KODO_100;
else
spell_id = caster->GetTeamId() == TEAM_HORDE ? SPELL_MOUNT_RAM_60 : SPELL_MOUNT_KODO_60;
@@ -3205,6 +3207,48 @@ class spell_item_brewfest_mount_transformation : public SpellScript
}
};
class spell_item_brewfest_hops : public AuraScript
{
PrepareAuraScript(spell_item_brewfest_hops);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo(
{
SPELL_BREWFEST_MOUNT_TRANSFORM,
SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE,
});
}
bool Load() override
{
_spell_id = GetSpellInfo()->Id == SPELL_FRESH_DWARVEN_HOPS ? SPELL_BREWFEST_MOUNT_TRANSFORM_REVERSE : SPELL_BREWFEST_MOUNT_TRANSFORM;
return true;
}
void CalcPeriodic(AuraEffect const* /*effect*/, bool& isPeriodic, int32& amplitude)
{
isPeriodic = true;
amplitude = 3 * IN_MILLISECONDS;
}
void Update(AuraEffect* /*effect*/)
{
Unit* caster = GetCaster();
if (!caster || caster->HasAnyAuras(SPELL_MOUNT_RAM_100, SPELL_MOUNT_RAM_60, SPELL_MOUNT_KODO_100, SPELL_MOUNT_KODO_60))
return;
caster->CastSpell(caster, _spell_id, true);
}
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_item_brewfest_hops::CalcPeriodic, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_item_brewfest_hops::Update, EFFECT_0, SPELL_AURA_DUMMY);
}
private:
uint32 _spell_id;
};
enum NitroBoots
{
SPELL_NITRO_BOOTS_SUCCESS = 54861,
@@ -4338,4 +4382,5 @@ void AddSC_item_spell_scripts()
RegisterSpellScript(spell_item_spell_reflectors);
RegisterSpellScript(spell_item_multiphase_goggles);
RegisterSpellScript(spell_item_bloodsail_admiral_hat);
RegisterSpellScript(spell_item_brewfest_hops);
}