Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -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
@@ -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);
|
||||
@@ -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*/);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user