Merge branch 'master' into Playerbot-updated
This commit is contained in:
@@ -42,7 +42,12 @@ jobs:
|
||||
|
||||
- name: Install requirements
|
||||
run: |
|
||||
sudo apt install -y bats
|
||||
sudo apt-get update
|
||||
# Install bats-core >= 1.5.0 to support bats_require_minimum_version
|
||||
sudo apt-get install -y git curl
|
||||
git clone --depth 1 https://github.com/bats-core/bats-core.git /tmp/bats-core
|
||||
sudo /tmp/bats-core/install.sh /usr/local
|
||||
bats --version
|
||||
./acore.sh install-deps
|
||||
|
||||
- name: Run bash script tests for ${{ matrix.test-module }}
|
||||
@@ -50,7 +55,7 @@ jobs:
|
||||
TERM: xterm-256color
|
||||
run: |
|
||||
cd apps/test-framework
|
||||
./run-tests.sh --tap
|
||||
./run-tests.sh --tap --all
|
||||
|
||||
build-and-test:
|
||||
name: Build and Integration Test
|
||||
@@ -75,12 +80,31 @@ jobs:
|
||||
# Configure dashboard
|
||||
sed -i 's/MTHREADS=.*/MTHREADS="4"/' conf/config.sh
|
||||
|
||||
- name: Test module commands
|
||||
run: |
|
||||
./acore.sh module install mod-autobalance
|
||||
./acore.sh module install mod-duel-reset
|
||||
|
||||
./acore.sh module list
|
||||
|
||||
./acore.sh module install --all
|
||||
./acore.sh module update mod-autobalance
|
||||
./acore.sh module update --all
|
||||
|
||||
- name: Run complete installation (deps, compile, database, client-data)
|
||||
run: |
|
||||
# This runs: install-deps, compile, database setup, client-data download
|
||||
./acore.sh init
|
||||
sudo npm install -g pm2
|
||||
timeout-minutes: 120
|
||||
|
||||
- name: Test module removal
|
||||
run: |
|
||||
./acore.sh module remove mod-autobalance
|
||||
./acore.sh module list
|
||||
./acore.sh module remove mod-duel-reset
|
||||
./acore.sh module list
|
||||
|
||||
- name: Test authserver dry-run
|
||||
run: |
|
||||
cd env/dist/bin
|
||||
@@ -92,3 +116,30 @@ jobs:
|
||||
cd env/dist/bin
|
||||
timeout 5m ./worldserver -dry-run
|
||||
continue-on-error: false
|
||||
|
||||
|
||||
- name: Test worldserver with startup scripts
|
||||
run: |
|
||||
./acore.sh sm create world worldserver --bin-path ./env/dist/bin --provider pm2
|
||||
./acore.sh sm show-config worldserver
|
||||
./acore.sh sm start worldserver
|
||||
./acore.sh sm wait-uptime worldserver 10 300
|
||||
./acore.sh sm send worldserver "account create tester password 3"
|
||||
./acore.sh sm send worldserver "account set gm tester 3"
|
||||
./acore.sh sm send worldserver "account set addon tester 1"
|
||||
./acore.sh sm wait-uptime worldserver 10 300
|
||||
./acore.sh sm stop worldserver
|
||||
./acore.sh sm delete worldserver
|
||||
timeout-minutes: 30
|
||||
continue-on-error: false
|
||||
|
||||
- name: Test authserver with startup scripts
|
||||
run: |
|
||||
./acore.sh sm create auth authserver --bin-path ./env/dist/bin --provider pm2
|
||||
./acore.sh sm show-config authserver
|
||||
./acore.sh sm start authserver
|
||||
./acore.sh sm wait-uptime authserver 10 300
|
||||
./acore.sh sm stop authserver
|
||||
./acore.sh sm delete authserver
|
||||
timeout-minutes: 30
|
||||
continue-on-error: false
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# =============================================================================
|
||||
# AzerothCore Menu System Library
|
||||
# =============================================================================
|
||||
# This library provides a unified menu system for AzerothCore scripts.
|
||||
# It supports ordered menu definitions, short commands, numeric selection,
|
||||
# and proper argument handling.
|
||||
#
|
||||
# Features:
|
||||
# - Single source of truth for menu definitions
|
||||
# - Automatic ID assignment (1, 2, 3...)
|
||||
# - Short command aliases (c, i, q, etc.)
|
||||
# - Interactive mode: numbers + long/short commands
|
||||
# - Direct mode: only long/short commands (no numbers)
|
||||
# - Proper argument forwarding
|
||||
#
|
||||
# Usage:
|
||||
# source "path/to/menu_system.sh"
|
||||
# menu_items=("command|short|description" ...)
|
||||
# menu_run "Menu Title" callback_function "${menu_items[@]}" "$@"
|
||||
# =============================================================================
|
||||
|
||||
# Global arrays for menu state (will be populated by menu_define)
|
||||
declare -a _MENU_KEYS=()
|
||||
declare -a _MENU_SHORTS=()
|
||||
declare -a _MENU_OPTIONS=()
|
||||
|
||||
# Parse menu items and populate global arrays
|
||||
# Usage: menu_define array_elements...
|
||||
function menu_define() {
|
||||
# Clear previous state
|
||||
_MENU_KEYS=()
|
||||
_MENU_SHORTS=()
|
||||
_MENU_OPTIONS=()
|
||||
|
||||
# Parse each menu item: "key|short|description"
|
||||
local item key short desc
|
||||
for item in "$@"; do
|
||||
IFS='|' read -r key short desc <<< "$item"
|
||||
_MENU_KEYS+=("$key")
|
||||
_MENU_SHORTS+=("$short")
|
||||
_MENU_OPTIONS+=("$key ($short): $desc")
|
||||
done
|
||||
}
|
||||
|
||||
# Display menu with numbered options
|
||||
# Usage: menu_display "Menu Title"
|
||||
function menu_display() {
|
||||
local title="$1"
|
||||
|
||||
echo "==== $title ===="
|
||||
for idx in "${!_MENU_OPTIONS[@]}"; do
|
||||
local num=$((idx + 1))
|
||||
printf "%2d) %s\n" "$num" "${_MENU_OPTIONS[$idx]}"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Find menu index by user input (number, long command, or short command)
|
||||
# Returns: index (0-based) or -1 if not found
|
||||
# Usage: index=$(menu_find_index "user_input")
|
||||
function menu_find_index() {
|
||||
local user_input="$1"
|
||||
|
||||
# Try numeric selection first
|
||||
if [[ "$user_input" =~ ^[0-9]+$ ]]; then
|
||||
local num=$((user_input - 1))
|
||||
if [[ $num -ge 0 && $num -lt ${#_MENU_KEYS[@]} ]]; then
|
||||
echo "$num"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try long command name
|
||||
local idx
|
||||
for idx in "${!_MENU_KEYS[@]}"; do
|
||||
if [[ "$user_input" == "${_MENU_KEYS[$idx]}" ]]; then
|
||||
echo "$idx"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Try short command
|
||||
for idx in "${!_MENU_SHORTS[@]}"; do
|
||||
if [[ "$user_input" == "${_MENU_SHORTS[$idx]}" ]]; then
|
||||
echo "$idx"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
echo "-1"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Handle direct execution (command line arguments)
|
||||
# Disables numeric selection to prevent confusion with command arguments
|
||||
# Usage: menu_direct_execute callback_function "$@"
|
||||
function menu_direct_execute() {
|
||||
local callback="$1"
|
||||
shift
|
||||
local user_input="$1"
|
||||
shift
|
||||
|
||||
# Disable numeric selection in direct mode
|
||||
if [[ "$user_input" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid option. Numeric selection is not allowed when passing arguments."
|
||||
echo "Use command name or short alias instead."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find command and execute
|
||||
local idx
|
||||
# try-catch
|
||||
{
|
||||
idx=$(menu_find_index "$user_input")
|
||||
} ||
|
||||
{
|
||||
idx=-1
|
||||
}
|
||||
|
||||
if [[ $idx -ge 0 ]]; then
|
||||
"$callback" "${_MENU_KEYS[$idx]}" "$@"
|
||||
return $?
|
||||
else
|
||||
# Handle help requests directly
|
||||
if [[ "$user_input" == "--help" || "$user_input" == "help" || "$user_input" == "-h" ]]; then
|
||||
echo "Available commands:"
|
||||
printf '%s\n' "${_MENU_OPTIONS[@]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Invalid option. Use --help to see available commands." >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle interactive menu selection
|
||||
# Usage: menu_interactive callback_function "Menu Title"
|
||||
function menu_interactive() {
|
||||
local callback="$1"
|
||||
local title="$2"
|
||||
|
||||
while true; do
|
||||
menu_display "$title"
|
||||
read -r -p "Please enter your choice: " REPLY
|
||||
|
||||
# Parse input to separate command from arguments
|
||||
local input_parts=()
|
||||
read -r -a input_parts <<< "$REPLY"
|
||||
local user_command="${input_parts[0]}"
|
||||
local user_args=("${input_parts[@]:1}")
|
||||
|
||||
# Find and execute command
|
||||
local idx
|
||||
idx=$(menu_find_index "$user_command")
|
||||
if [[ $idx -ge 0 ]]; then
|
||||
# Pass the command key and any additional arguments
|
||||
"$callback" "${_MENU_KEYS[$idx]}" "${user_args[@]}"
|
||||
local exit_code=$?
|
||||
# Exit loop if callback returns 0 (e.g., quit command)
|
||||
if [[ $exit_code -eq 0 && "${_MENU_KEYS[$idx]}" == "quit" ]]; then
|
||||
break
|
||||
fi
|
||||
else
|
||||
# Handle help request
|
||||
if [[ "$REPLY" == "--help" || "$REPLY" == "help" || "$REPLY" == "h" ]]; then
|
||||
echo "Available commands:"
|
||||
printf '%s\n' "${_MENU_OPTIONS[@]}"
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Invalid option. Please try again or use 'help' for available commands." >&2
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Main menu runner function
|
||||
# Usage: menu_run "Menu Title" callback_function "$@"
|
||||
# The menu items array should be defined globally before calling this function
|
||||
function menu_run() {
|
||||
local title="$1"
|
||||
local callback="$2"
|
||||
shift 2
|
||||
|
||||
# Define menu from globally available menu items array
|
||||
# This expects the calling script to have set up the menu items
|
||||
|
||||
# Handle direct execution if arguments provided
|
||||
if [[ $# -gt 0 ]]; then
|
||||
menu_direct_execute "$callback" "$@"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Run interactive menu
|
||||
menu_interactive "$callback" "$title"
|
||||
}
|
||||
|
||||
# Alternative menu runner that accepts menu items directly
|
||||
# Usage: menu_run_with_items "Menu Title" callback_function -- "${menu_items_array[@]}" -- "$@"
|
||||
function menu_run_with_items() {
|
||||
local title="$1"
|
||||
local callback="$2"
|
||||
shift 2
|
||||
|
||||
# Parse parameters: menu items are between first and second "--"
|
||||
local menu_items=()
|
||||
local script_args=()
|
||||
|
||||
# Skip first "--"
|
||||
if [[ "$1" == "--" ]]; then
|
||||
shift
|
||||
else
|
||||
echo "Error: menu_run_with_items requires -- separator before menu items" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Collect menu items until second "--"
|
||||
while [[ $# -gt 0 && "$1" != "--" ]]; do
|
||||
menu_items+=("$1")
|
||||
shift
|
||||
done
|
||||
|
||||
# Skip second "--" if present
|
||||
if [[ "$1" == "--" ]]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remaining args are script arguments
|
||||
script_args=("$@")
|
||||
|
||||
# Define menu from provided array
|
||||
menu_define "${menu_items[@]}"
|
||||
|
||||
# Handle direct execution if arguments provided
|
||||
if [[ ${#script_args[@]} -gt 0 ]]; then
|
||||
menu_direct_execute "$callback" "${script_args[@]}"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Run interactive menu
|
||||
menu_interactive "$callback" "$title"
|
||||
}
|
||||
|
||||
# Utility function to show available commands (for --help)
|
||||
# Usage: menu_show_help
|
||||
function menu_show_help() {
|
||||
echo "Available commands:"
|
||||
printf '%s\n' "${_MENU_OPTIONS[@]}"
|
||||
}
|
||||
|
||||
# Utility function to get command key by index
|
||||
# Usage: key=$(menu_get_key index)
|
||||
function menu_get_key() {
|
||||
local idx="$1"
|
||||
if [[ $idx -ge 0 && $idx -lt ${#_MENU_KEYS[@]} ]]; then
|
||||
echo "${_MENU_KEYS[$idx]}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Utility function to get all command keys
|
||||
# Usage: keys=($(menu_get_all_keys))
|
||||
function menu_get_all_keys() {
|
||||
printf '%s\n' "${_MENU_KEYS[@]}"
|
||||
}
|
||||
+49
-60
@@ -5,72 +5,61 @@ set -e
|
||||
CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
source "$CURRENT_PATH/includes/includes.sh"
|
||||
source "$AC_PATH_APPS/bash_shared/menu_system.sh"
|
||||
|
||||
function run_option() {
|
||||
re='^[0-9]+$'
|
||||
if [[ $1 =~ $re ]] && test "${comp_functions[$1-1]+'test'}"; then
|
||||
${comp_functions[$1-1]}
|
||||
elif [ -n "$(type -t comp_$1)" ] && [ "$(type -t comp_$1)" = function ]; then
|
||||
fun="comp_$1"
|
||||
$fun
|
||||
else
|
||||
echo "invalid option, use --help option for the commands list"
|
||||
fi
|
||||
}
|
||||
# Menu definition using the new system
|
||||
# Format: "key|short|description"
|
||||
comp_menu_items=(
|
||||
"build|b|Configure and compile"
|
||||
"clean|cl|Clean build files"
|
||||
"configure|cfg|Run CMake"
|
||||
"compile|cmp|Compile only"
|
||||
"all|a|clean, configure and compile"
|
||||
"ccacheClean|cc|Clean ccache files, normally not needed"
|
||||
"ccacheShowStats|cs|show ccache statistics"
|
||||
"quit|q|Close this menu"
|
||||
)
|
||||
|
||||
function comp_quit() {
|
||||
exit 0
|
||||
}
|
||||
# Menu command handler - called by menu system for each command
|
||||
function handle_compiler_command() {
|
||||
local key="$1"
|
||||
shift
|
||||
|
||||
comp_options=(
|
||||
"build: Configure and compile"
|
||||
"clean: Clean build files"
|
||||
"configure: Run CMake"
|
||||
"compile: Compile only"
|
||||
"all: clean, configure and compile"
|
||||
"ccacheClean: Clean ccache files, normally not needed"
|
||||
"ccacheShowStats: show ccache statistics"
|
||||
"quit: Close this menu")
|
||||
comp_functions=(
|
||||
"comp_build"
|
||||
"comp_clean"
|
||||
"comp_configure"
|
||||
"comp_compile"
|
||||
"comp_all"
|
||||
"comp_ccacheClean"
|
||||
"comp_ccacheShowStats"
|
||||
"comp_quit")
|
||||
|
||||
PS3='[ Please enter your choice ]: '
|
||||
|
||||
runHooks "ON_AFTER_OPTIONS" #you can create your custom options
|
||||
|
||||
function _switch() {
|
||||
_reply="$1"
|
||||
_opt="$2"
|
||||
|
||||
case $_reply in
|
||||
""|"--help")
|
||||
echo "Available commands:"
|
||||
printf '%s\n' "${options[@]}"
|
||||
case "$key" in
|
||||
"build")
|
||||
comp_build
|
||||
;;
|
||||
"clean")
|
||||
comp_clean
|
||||
;;
|
||||
"configure")
|
||||
comp_configure
|
||||
;;
|
||||
"compile")
|
||||
comp_compile
|
||||
;;
|
||||
"all")
|
||||
comp_all
|
||||
;;
|
||||
"ccacheClean")
|
||||
comp_ccacheClean
|
||||
;;
|
||||
"ccacheShowStats")
|
||||
comp_ccacheShowStats
|
||||
;;
|
||||
"quit")
|
||||
echo "Closing compiler menu..."
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
run_option $_reply $_opt
|
||||
;;
|
||||
echo "Invalid option. Use --help to see available commands."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Hook support (preserved from original)
|
||||
runHooks "ON_AFTER_OPTIONS" # you can create your custom options
|
||||
|
||||
while true
|
||||
do
|
||||
# run option directly if specified in argument
|
||||
[ ! -z $1 ] && _switch $@
|
||||
[ ! -z $1 ] && exit 0
|
||||
|
||||
select opt in "${comp_options[@]}"
|
||||
do
|
||||
echo "==== ACORE COMPILER ===="
|
||||
_switch $REPLY
|
||||
break;
|
||||
done
|
||||
done
|
||||
# Run the menu system
|
||||
menu_run_with_items "ACORE COMPILER" handle_compiler_command -- "${comp_menu_items[@]}" -- "$@"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
# Require minimum BATS version to avoid warnings
|
||||
bats_require_minimum_version 1.5.0
|
||||
# Require minimum BATS version when supported (older distro packages lack this)
|
||||
if type -t bats_require_minimum_version >/dev/null 2>&1; then
|
||||
bats_require_minimum_version 1.5.0
|
||||
fi
|
||||
|
||||
# AzerothCore Compiler Scripts Test Suite
|
||||
# Tests the functionality of the compiler scripts using the unified test framework
|
||||
@@ -34,8 +36,8 @@ teardown() {
|
||||
run bash -c "echo '' | timeout 5s $COMPILER_SCRIPT 2>&1 || true"
|
||||
# The script might exit with timeout (124) or success (0), both are acceptable for this test
|
||||
[[ "$status" -eq 0 ]] || [[ "$status" -eq 124 ]]
|
||||
# Check if output contains expected content - looking for menu options
|
||||
[[ "$output" =~ "build:" ]] || [[ "$output" =~ "clean:" ]] || [[ "$output" =~ "Please enter your choice" ]] || [[ -z "$output" ]]
|
||||
# Check if output contains expected content - looking for menu options (old or new format)
|
||||
[[ "$output" =~ "build:" ]] || [[ "$output" =~ "clean:" ]] || [[ "$output" =~ "Please enter your choice" ]] || [[ "$output" =~ "build (b):" ]] || [[ "$output" =~ "ACORE COMPILER" ]] || [[ -z "$output" ]]
|
||||
}
|
||||
|
||||
@test "compiler: should accept option numbers" {
|
||||
@@ -52,16 +54,16 @@ teardown() {
|
||||
|
||||
@test "compiler: should handle invalid option gracefully" {
|
||||
run timeout 5s "$COMPILER_SCRIPT" invalidOption
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "invalid option" ]]
|
||||
# Should exit with error code for invalid option
|
||||
[ "$status" -eq 1 ]
|
||||
# Output check is optional as error message might be buffered
|
||||
}
|
||||
|
||||
@test "compiler: should handle invalid number gracefully" {
|
||||
run bash -c "echo '999' | timeout 5s $COMPILER_SCRIPT 2>/dev/null || true"
|
||||
# The script might exit with timeout (124) or success (0), both are acceptable
|
||||
run bash -c "echo '999' | timeout 5s $COMPILER_SCRIPT 2>&1 || true"
|
||||
# The script might exit with timeout (124) or success (0) for interactive mode
|
||||
[[ "$status" -eq 0 ]] || [[ "$status" -eq 124 ]]
|
||||
# Check if output contains expected content, or if there's no output due to timeout, that's also acceptable
|
||||
[[ "$output" =~ "invalid option" ]] || [[ "$output" =~ "Please enter your choice" ]] || [[ -z "$output" ]]
|
||||
# In interactive mode, the script should continue asking for input or timeout
|
||||
}
|
||||
|
||||
@test "compiler: should quit with quit option" {
|
||||
|
||||
@@ -118,142 +118,28 @@ function inst_allInOne() {
|
||||
inst_download_client_data
|
||||
}
|
||||
|
||||
function inst_getVersionBranch() {
|
||||
local res="master"
|
||||
local v="not-defined"
|
||||
local MODULE_MAJOR=0
|
||||
local MODULE_MINOR=0
|
||||
local MODULE_PATCH=0
|
||||
local MODULE_SPECIAL=0;
|
||||
local ACV_MAJOR=0
|
||||
local ACV_MINOR=0
|
||||
local ACV_PATCH=0
|
||||
local ACV_SPECIAL=0;
|
||||
local curldata=$(curl -f --silent -H 'Cache-Control: no-cache' "$1" || echo "{}")
|
||||
local parsed=$(echo "$curldata" | "$AC_PATH_DEPS/jsonpath/JSONPath.sh" -b '$.compatibility.*.[version,branch]')
|
||||
############################################################
|
||||
# Module helpers and dispatcher #
|
||||
############################################################
|
||||
|
||||
semverParseInto "$ACORE_VERSION" ACV_MAJOR ACV_MINOR ACV_PATCH ACV_SPECIAL
|
||||
|
||||
if [[ ! -z "$parsed" ]]; then
|
||||
readarray -t vers < <(echo "$parsed")
|
||||
local idx
|
||||
res="none"
|
||||
# since we've the pair version,branch alternated in not associative and one-dimensional
|
||||
# array, we've to simulate the association with length/2 trick
|
||||
for idx in `seq 0 $((${#vers[*]}/2-1))`; do
|
||||
semverParseInto "${vers[idx*2]}" MODULE_MAJOR MODULE_MINOR MODULE_PATCH MODULE_SPECIAL
|
||||
if [[ $MODULE_MAJOR -eq $ACV_MAJOR && $MODULE_MINOR -le $ACV_MINOR ]]; then
|
||||
res="${vers[idx*2+1]}"
|
||||
v="${vers[idx*2]}"
|
||||
fi
|
||||
done
|
||||
# Returns the default branch name of a GitHub repo in the azerothcore org.
|
||||
# If the API call fails, defaults to "master".
|
||||
function inst_get_default_branch() {
|
||||
local repo="$1"
|
||||
local def
|
||||
def=$(curl --silent "https://api.github.com/repos/azerothcore/${repo}" \
|
||||
| "$AC_PATH_DEPS/jsonpath/JSONPath.sh" -b '$.default_branch')
|
||||
if [ -z "$def" ]; then
|
||||
def="master"
|
||||
fi
|
||||
|
||||
echo "$v" "$res"
|
||||
}
|
||||
|
||||
function inst_module_search {
|
||||
|
||||
local res="$1"
|
||||
local idx=0;
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Type what to search or leave blank for full list"
|
||||
read -p "Insert name: " res
|
||||
fi
|
||||
|
||||
local search="+$res"
|
||||
|
||||
echo "Searching $res..."
|
||||
echo "";
|
||||
|
||||
readarray -t MODS < <(curl --silent "https://api.github.com/search/repositories?q=org%3Aazerothcore${search}+fork%3Atrue+topic%3Acore-module+sort%3Astars&type=" \
|
||||
| "$AC_PATH_DEPS/jsonpath/JSONPath.sh" -b '$.items.*.name')
|
||||
while (( ${#MODS[@]} > idx )); do
|
||||
mod="${MODS[idx++]}"
|
||||
read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/azerothcore/$mod/master/acore-module.json")
|
||||
|
||||
if [[ "$b" != "none" ]]; then
|
||||
echo "-> $mod (tested with AC version: $v)"
|
||||
else
|
||||
echo "-> $mod (no revision available for AC v$AC_VERSION, it could not work!)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "";
|
||||
echo "";
|
||||
}
|
||||
|
||||
function inst_module_install {
|
||||
local res
|
||||
if [ -z "$1" ]; then
|
||||
echo "Type the name of the module to install"
|
||||
read -p "Insert name: " res
|
||||
else
|
||||
res="$1"
|
||||
fi
|
||||
|
||||
read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/azerothcore/$res/master/acore-module.json")
|
||||
|
||||
if [[ "$b" != "none" ]]; then
|
||||
Joiner:add_repo "https://github.com/azerothcore/$res" "$res" "$b" && echo "Done, please re-run compiling and db assembly. Read instruction on module repository for more information"
|
||||
else
|
||||
echo "Cannot install $res module: it doesn't exists or no version compatible with AC v$ACORE_VERSION are available"
|
||||
fi
|
||||
|
||||
echo "";
|
||||
echo "";
|
||||
}
|
||||
|
||||
function inst_module_update {
|
||||
local res;
|
||||
local _tmp;
|
||||
local branch;
|
||||
local p;
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Type the name of the module to update"
|
||||
read -p "Insert name: " res
|
||||
else
|
||||
res="$1"
|
||||
fi
|
||||
|
||||
_tmp=$PWD
|
||||
|
||||
if [ -d "$J_PATH_MODULES/$res/" ]; then
|
||||
read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/azerothcore/$res/master/acore-module.json")
|
||||
|
||||
cd "$J_PATH_MODULES/$res/"
|
||||
|
||||
# use current branch if something wrong with json
|
||||
if [[ "$v" == "none" || "$v" == "not-defined" ]]; then
|
||||
b=`git rev-parse --abbrev-ref HEAD`
|
||||
fi
|
||||
|
||||
Joiner:upd_repo "https://github.com/azerothcore/$res" "$res" "$b" && echo "Done, please re-run compiling and db assembly" || echo "Cannot update"
|
||||
cd $_tmp
|
||||
else
|
||||
echo "Cannot update! Path doesn't exist"
|
||||
fi;
|
||||
|
||||
echo "";
|
||||
echo "";
|
||||
}
|
||||
|
||||
function inst_module_remove {
|
||||
if [ -z "$1" ]; then
|
||||
echo "Type the name of the module to remove"
|
||||
read -p "Insert name: " res
|
||||
else
|
||||
res="$1"
|
||||
fi
|
||||
|
||||
Joiner:remove "$res" && echo "Done, please re-run compiling" || echo "Cannot remove"
|
||||
|
||||
echo "";
|
||||
echo "";
|
||||
echo "$def"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Module Management System
|
||||
# =============================================================================
|
||||
# Load the module manager functions from the dedicated modules-manager directory
|
||||
source "$AC_PATH_INSTALLER/includes/modules-manager/modules.sh"
|
||||
|
||||
function inst_simple_restarter {
|
||||
echo "Running $1 ..."
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
# AzerothCore Module Manager
|
||||
|
||||
This directory contains the module management system for AzerothCore, providing advanced functionality for installing, updating, and managing server modules.
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
- **Advanced Syntax**: Support for `repo[:dirname][@branch[:commit]]` format
|
||||
- **Cross-Format Recognition**: Intelligent matching across URLs, SSH, and simple names
|
||||
- **Custom Directory Naming**: Prevent conflicts with custom directory names
|
||||
- **Duplicate Prevention**: Smart detection and prevention of duplicate installations
|
||||
- **Multi-Host Support**: GitHub, GitLab, and other Git hosts
|
||||
- **Module Exclusion**: Support for excluding modules via environment variable
|
||||
- **Interactive Menu System**: Easy-to-use menu interface for module management
|
||||
- **Colored Output**: Enhanced terminal output with color support (respects NO_COLOR)
|
||||
- **Flat Directory Structure**: Uses flat module installation (no owner subfolders)
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
```
|
||||
modules-manager/
|
||||
├── modules.sh # Core module management functions
|
||||
└── README.md # This documentation file
|
||||
```
|
||||
|
||||
## 🔧 Module Specification Syntax
|
||||
|
||||
The module manager supports flexible syntax for specifying modules:
|
||||
|
||||
### New Syntax Format
|
||||
```bash
|
||||
repo[:dirname][@branch[:commit]]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
| Specification | Description |
|
||||
|---------------|-------------|
|
||||
| `mod-transmog` | Simple module name, uses default branch and directory |
|
||||
| `mod-transmog:my-custom-dir` | Custom directory name |
|
||||
| `mod-transmog@develop` | Specific branch |
|
||||
| `mod-transmog:custom@develop:abc123` | Custom directory, branch, and commit |
|
||||
| `https://github.com/owner/repo.git@main` | Full URL with branch |
|
||||
| `git@github.com:owner/repo.git:custom-dir` | SSH URL with custom directory |
|
||||
|
||||
## 🎯 Usage Examples
|
||||
|
||||
### Installing Modules
|
||||
|
||||
```bash
|
||||
# Simple module installation
|
||||
./acore.sh module install mod-transmog
|
||||
|
||||
# Install with custom directory name
|
||||
./acore.sh module install mod-transmog:my-transmog-dir
|
||||
|
||||
# Install specific branch
|
||||
./acore.sh module install mod-transmog@develop
|
||||
|
||||
# Install with full specification
|
||||
./acore.sh module install mod-transmog:custom-dir@develop:abc123
|
||||
|
||||
# Install from URL
|
||||
./acore.sh module install https://github.com/azerothcore/mod-transmog.git@main
|
||||
|
||||
# Install multiple modules
|
||||
./acore.sh module install mod-transmog mod-eluna:custom-eluna
|
||||
|
||||
# Install all modules from list
|
||||
./acore.sh module install --all
|
||||
```
|
||||
|
||||
### Updating Modules
|
||||
|
||||
```bash
|
||||
# Update specific module
|
||||
./acore.sh module update mod-transmog
|
||||
|
||||
# Update all modules
|
||||
./acore.sh module update --all
|
||||
|
||||
# Update with branch specification
|
||||
./acore.sh module update mod-transmog@develop
|
||||
```
|
||||
|
||||
### Removing Modules
|
||||
|
||||
```bash
|
||||
# Remove by simple name (cross-format recognition)
|
||||
./acore.sh module remove mod-transmog
|
||||
|
||||
# Remove by URL (recognizes same module)
|
||||
./acore.sh module remove https://github.com/azerothcore/mod-transmog.git
|
||||
|
||||
# Remove multiple modules
|
||||
./acore.sh module remove mod-transmog mod-eluna
|
||||
```
|
||||
|
||||
### Searching Modules
|
||||
|
||||
```bash
|
||||
# Search for modules
|
||||
./acore.sh module search transmog
|
||||
|
||||
# Search with multiple terms
|
||||
./acore.sh module search auction house
|
||||
|
||||
# Search with input prompt
|
||||
./acore.sh module search
|
||||
```
|
||||
|
||||
### Listing Installed Modules
|
||||
|
||||
```bash
|
||||
# List all installed modules
|
||||
./acore.sh module list
|
||||
```
|
||||
|
||||
### Interactive Menu
|
||||
|
||||
```bash
|
||||
# Start interactive menu system
|
||||
./acore.sh module
|
||||
|
||||
# Menu options:
|
||||
# s - Search for available modules
|
||||
# i - Install one or more modules
|
||||
# u - Update installed modules
|
||||
# r - Remove installed modules
|
||||
# l - List installed modules
|
||||
# h - Show detailed help
|
||||
# q - Close this menu
|
||||
```
|
||||
|
||||
## 🔍 Cross-Format Recognition
|
||||
|
||||
The system intelligently recognizes the same module across different specification formats:
|
||||
|
||||
```bash
|
||||
# These all refer to the same module:
|
||||
mod-transmog
|
||||
azerothcore/mod-transmog
|
||||
https://github.com/azerothcore/mod-transmog.git
|
||||
git@github.com:azerothcore/mod-transmog.git
|
||||
```
|
||||
|
||||
This allows:
|
||||
- Installing with one format and removing with another
|
||||
- Preventing duplicates regardless of specification format
|
||||
- Consistent module tracking across different input methods
|
||||
|
||||
## 🛡️ Conflict Prevention
|
||||
|
||||
The system prevents common conflicts:
|
||||
|
||||
### Directory Conflicts
|
||||
```bash
|
||||
# If 'mod-transmog' directory already exists:
|
||||
$ ./acore.sh module install mod-transmog:mod-transmog
|
||||
Possible solutions:
|
||||
1. Use a different directory name: mod-transmog:my-custom-name
|
||||
2. Remove the existing directory first
|
||||
3. Use the update command if this is the same module
|
||||
```
|
||||
|
||||
### Duplicate Module Prevention
|
||||
The system uses intelligent owner/name matching to prevent installing the same module multiple times, even when specified in different formats.
|
||||
|
||||
## 🚫 Module Exclusion
|
||||
|
||||
You can exclude modules from installation using the `MODULES_EXCLUDE_LIST` environment variable:
|
||||
|
||||
```bash
|
||||
# Exclude specific modules (space-separated)
|
||||
export MODULES_EXCLUDE_LIST="mod-test-module azerothcore/mod-dev-only"
|
||||
./acore.sh module install --all # Will skip excluded modules
|
||||
|
||||
# Supports cross-format matching
|
||||
export MODULES_EXCLUDE_LIST="https://github.com/azerothcore/mod-transmog.git"
|
||||
./acore.sh module install mod-transmog # Will be skipped as excluded
|
||||
```
|
||||
|
||||
The exclusion system:
|
||||
- Uses the same cross-format recognition as other module operations
|
||||
- Works with all installation methods (`install`, `install --all`)
|
||||
- Provides clear feedback when modules are skipped
|
||||
- Supports URLs, owner/name format, and simple names
|
||||
|
||||
## 🎨 Color Support
|
||||
|
||||
The module manager provides enhanced terminal output with colors:
|
||||
|
||||
- **Info**: Cyan text for informational messages
|
||||
- **Success**: Green text for successful operations
|
||||
- **Warning**: Yellow text for warnings
|
||||
- **Error**: Red text for errors
|
||||
- **Headers**: Bold cyan text for section headers
|
||||
|
||||
Color support is automatically disabled when:
|
||||
- Output is not to a terminal (piped/redirected)
|
||||
- `NO_COLOR` environment variable is set
|
||||
- Terminal doesn't support colors
|
||||
|
||||
You can force color output with:
|
||||
```bash
|
||||
export FORCE_COLOR=1
|
||||
```
|
||||
|
||||
## 🔄 Integration
|
||||
|
||||
### Including in Scripts
|
||||
```bash
|
||||
# Source the module functions
|
||||
source "$AC_PATH_INSTALLER/includes/modules-manager/modules.sh"
|
||||
|
||||
# Use module functions
|
||||
inst_module_install "mod-transmog:custom-dir@develop"
|
||||
```
|
||||
|
||||
### Testing
|
||||
The module system is tested through the main installer test suite:
|
||||
```bash
|
||||
./apps/installer/test/test_module_commands.bats
|
||||
```
|
||||
|
||||
## 📋 Module List Format
|
||||
|
||||
Modules are tracked in `conf/modules.list` with the format:
|
||||
```
|
||||
# Comments start with #
|
||||
repo_reference branch commit
|
||||
|
||||
# Examples:
|
||||
azerothcore/mod-transmog master abc123def456
|
||||
https://github.com/custom/mod-custom.git develop def456abc789
|
||||
mod-eluna:custom-eluna-dir main 789abc123def
|
||||
```
|
||||
|
||||
The list maintains:
|
||||
- **Alphabetical ordering** by normalized owner/name for consistency
|
||||
- **Original format preservation** of how modules were specified
|
||||
- **Automatic deduplication** across different specification formats
|
||||
- **Custom directory tracking** when specified
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `MODULES_LIST_FILE` | Override default modules list path | `$AC_PATH_ROOT/conf/modules.list` |
|
||||
| `MODULES_EXCLUDE_LIST` | Space-separated list of modules to exclude | - |
|
||||
| `J_PATH_MODULES` | Modules installation directory | `$AC_PATH_ROOT/modules` |
|
||||
| `AC_PATH_ROOT` | AzerothCore root path | - |
|
||||
| `NO_COLOR` | Disable colored output | - |
|
||||
| `FORCE_COLOR` | Force colored output even when not TTY | - |
|
||||
|
||||
### Default Paths
|
||||
- **Modules list**: `$AC_PATH_ROOT/conf/modules.list`
|
||||
- **Installation directory**: `$J_PATH_MODULES` (flat structure, no owner subfolders)
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Core Functions
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `inst_module()` | Main dispatcher and interactive menu |
|
||||
| `inst_parse_module_spec()` | Parse advanced module syntax |
|
||||
| `inst_extract_owner_name()` | Normalize modules for cross-format recognition |
|
||||
| `inst_mod_list_*()` | Module list management (read/write/update) |
|
||||
| `inst_module_*()` | Module operations (install/update/remove/search) |
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Flat Directory Structure**: All modules install directly under `modules/` without owner subdirectories
|
||||
- **Smart Conflict Detection**: Prevents directory name conflicts with helpful suggestions
|
||||
- **Cross-Platform Compatibility**: Works on Linux, macOS, and Windows (Git Bash)
|
||||
- **Version Compatibility**: Checks `acore-module.json` for AzerothCore version compatibility
|
||||
- **Git Integration**: Uses Joiner system for Git repository management
|
||||
|
||||
### Debug Mode
|
||||
|
||||
For debugging module operations, you can examine the generated commands:
|
||||
```bash
|
||||
# Check what Joiner commands would be executed
|
||||
tail -f /tmp/joiner_called.txt # In test environments
|
||||
```
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
When modifying the module manager:
|
||||
|
||||
1. **Maintain backwards compatibility** with existing module list format
|
||||
2. **Update tests** in `test_module_commands.bats` for new functionality
|
||||
3. **Update this documentation** for any new features or changes
|
||||
4. **Test cross-format recognition** thoroughly across all supported formats
|
||||
5. **Ensure helpful error messages** for common user mistakes
|
||||
6. **Test exclusion functionality** with various module specification formats
|
||||
7. **Verify color output** works correctly in different terminal environments
|
||||
|
||||
### Testing Guidelines
|
||||
|
||||
```bash
|
||||
# Run all module-related tests
|
||||
cd apps/installer
|
||||
bats test/test_module_commands.bats
|
||||
|
||||
# Test with different environments
|
||||
NO_COLOR=1 ./acore.sh module list
|
||||
FORCE_COLOR=1 ./acore.sh module help
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CURRENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit ; pwd )
|
||||
|
||||
source "$CURRENT_PATH/modules.sh"
|
||||
|
||||
inst_module "$@"
|
||||
File diff suppressed because it is too large
Load Diff
+70
-68
@@ -1,105 +1,107 @@
|
||||
#!/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.),
|
||||
# or short alias (i, c, etc.)
|
||||
# - All selection methods work in interactive mode
|
||||
#
|
||||
# Direct Command Mode:
|
||||
# - Only command names and short aliases are accepted (e.g., './acore.sh compiler build', './acore.sh c build')
|
||||
# - Numeric selection is disabled to prevent confusion with command arguments
|
||||
# - Examples: './acore.sh init', './acore.sh compiler clean', './acore.sh module install mod-name'
|
||||
#
|
||||
# Menu System:
|
||||
# - Uses unified menu system from bash_shared/menu_system.sh
|
||||
# - Single source of truth for menu definitions
|
||||
# - Consistent behavior across all AzerothCore tools
|
||||
|
||||
CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
source "$CURRENT_PATH/includes/includes.sh"
|
||||
source "$AC_PATH_APPS/bash_shared/menu_system.sh"
|
||||
|
||||
PS3='[Please enter your choice]: '
|
||||
options=(
|
||||
"init (i): First Installation" # 1
|
||||
"install-deps (d): Configure OS dep" # 2
|
||||
"pull (u): Update Repository" # 3
|
||||
"reset (r): Reset & Clean Repository" # 4
|
||||
"compiler (c): Run compiler tool" # 5
|
||||
"module-search (ms): Module Search by keyword" # 6
|
||||
"module-install (mi): Module Install by name" # 7
|
||||
"module-update (mu): Module Update by name" # 8
|
||||
"module-remove: (mr): Module Remove by name" # 9
|
||||
"client-data: (gd): download client data from github repository (beta)" # 10
|
||||
"run-worldserver (rw): execute a simple restarter for worldserver" # 11
|
||||
"run-authserver (ra): execute a simple restarter for authserver" # 12
|
||||
"docker (dr): Run docker tools" # 13
|
||||
"version (v): Show AzerothCore version" # 14
|
||||
"service-manager (sm): Run service manager to run authserver and worldserver in background" # 15
|
||||
"quit: Exit from this menu" # 16
|
||||
)
|
||||
# Menu: single ordered source of truth (no functions in strings)
|
||||
# Format: "key|short|description"
|
||||
menu_items=(
|
||||
"init|i|First Installation"
|
||||
"install-deps|d|Configure OS dep"
|
||||
"pull|u|Update Repository"
|
||||
"reset|r|Reset & Clean Repository"
|
||||
"compiler|c|Run compiler tool"
|
||||
"module|m|Module manager (search/install/update/remove)"
|
||||
"client-data|gd|download client data from github repository (beta)"
|
||||
"run-worldserver|rw|execute a simple restarter for worldserver"
|
||||
"run-authserver|ra|execute a simple restarter for authserver"
|
||||
"docker|dr|Run docker tools"
|
||||
"version|v|Show AzerothCore version"
|
||||
"service-manager|sm|Run service manager to run authserver and worldserver in background"
|
||||
"quit|q|Exit from this menu"
|
||||
)
|
||||
|
||||
function _switch() {
|
||||
_reply="$1"
|
||||
_opt="$2"
|
||||
|
||||
case $_reply in
|
||||
""|"i"|"init"|"1")
|
||||
# Menu command handler - called by menu system for each command
|
||||
function handle_menu_command() {
|
||||
local key="$1"
|
||||
shift
|
||||
|
||||
case "$key" in
|
||||
"init")
|
||||
inst_allInOne
|
||||
;;
|
||||
""|"d"|"install-deps"|"2")
|
||||
"install-deps")
|
||||
inst_configureOS
|
||||
;;
|
||||
""|"u"|"pull"|"3")
|
||||
"pull")
|
||||
inst_updateRepo
|
||||
;;
|
||||
""|"r"|"reset"|"4")
|
||||
"reset")
|
||||
inst_resetRepo
|
||||
;;
|
||||
""|"c"|"compiler"|"5")
|
||||
bash "$AC_PATH_APPS/compiler/compiler.sh" $_opt
|
||||
"compiler")
|
||||
bash "$AC_PATH_APPS/compiler/compiler.sh" "$@"
|
||||
;;
|
||||
""|"ms"|"module-search"|"6")
|
||||
inst_module_search "$_opt"
|
||||
"module")
|
||||
bash "$AC_PATH_APPS/installer/includes/modules-manager/module-main.sh" "$@"
|
||||
;;
|
||||
""|"mi"|"module-install"|"7")
|
||||
inst_module_install "$_opt"
|
||||
;;
|
||||
""|"mu"|"module-update"|"8")
|
||||
inst_module_update "$_opt"
|
||||
;;
|
||||
""|"mr"|"module-remove"|"9")
|
||||
inst_module_remove "$_opt"
|
||||
;;
|
||||
""|"gd"|"client-data"|"10")
|
||||
"client-data")
|
||||
inst_download_client_data
|
||||
;;
|
||||
""|"rw"|"run-worldserver"|"11")
|
||||
"run-worldserver")
|
||||
inst_simple_restarter worldserver
|
||||
;;
|
||||
""|"ra"|"run-authserver"|"12")
|
||||
"run-authserver")
|
||||
inst_simple_restarter authserver
|
||||
;;
|
||||
""|"dr"|"docker"|"13")
|
||||
DOCKER=1 bash "$AC_PATH_ROOT/apps/docker/docker-cmd.sh" "${@:2}"
|
||||
"docker")
|
||||
DOCKER=1 bash "$AC_PATH_ROOT/apps/docker/docker-cmd.sh" "$@"
|
||||
exit
|
||||
;;
|
||||
""|"v"|"version"|"14")
|
||||
# denoRunFile "$AC_PATH_APPS/installer/main.ts" "version"
|
||||
"version")
|
||||
printf "AzerothCore Rev. %s\n" "$ACORE_VERSION"
|
||||
exit
|
||||
;;
|
||||
""|"sm"|"service-manager"|"15")
|
||||
bash "$AC_PATH_APPS/startup-scripts/src/service-manager.sh" "${@:2}"
|
||||
"service-manager")
|
||||
bash "$AC_PATH_APPS/startup-scripts/src/service-manager.sh" "$@"
|
||||
exit
|
||||
;;
|
||||
""|"quit"|"16")
|
||||
"quit")
|
||||
echo "Goodbye!"
|
||||
exit
|
||||
;;
|
||||
""|"--help")
|
||||
echo "Available commands:"
|
||||
printf '%s\n' "${options[@]}"
|
||||
*)
|
||||
echo "Invalid option. Use --help to see available commands."
|
||||
return 1
|
||||
;;
|
||||
*) echo "invalid option, use --help option for the commands list";;
|
||||
esac
|
||||
}
|
||||
|
||||
while true
|
||||
do
|
||||
# run option directly if specified in argument
|
||||
[ ! -z $1 ] && _switch $@ # old method: "${options[$cmdopt-1]}"
|
||||
[ ! -z $1 ] && exit 0
|
||||
|
||||
echo "==== ACORE DASHBOARD ===="
|
||||
select opt in "${options[@]}"
|
||||
do
|
||||
_switch $REPLY
|
||||
break
|
||||
done
|
||||
done
|
||||
# Run the menu system
|
||||
menu_run_with_items "ACORE DASHBOARD" handle_menu_command -- "${menu_items[@]}" -- "$@"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# BATS Test Configuration
|
||||
|
||||
# Set test timeout (in seconds)
|
||||
export BATS_TEST_TIMEOUT=30
|
||||
|
||||
# Enable verbose output for debugging
|
||||
export BATS_VERBOSE_RUN=1
|
||||
|
||||
# Test output format
|
||||
export BATS_FORMATTER=pretty
|
||||
|
||||
# Enable colored output
|
||||
export BATS_NO_PARALLELIZE_ACROSS_FILES=1
|
||||
export BATS_NO_PARALLELIZE_WITHIN_FILE=1
|
||||
+755
@@ -0,0 +1,755 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
# Tests for installer module commands (search/install/update/remove)
|
||||
# Focused on installer:module install behavior using a mocked joiner
|
||||
|
||||
load '../../test-framework/bats_libs/acore-support'
|
||||
load '../../test-framework/bats_libs/acore-assert'
|
||||
|
||||
setup() {
|
||||
acore_test_setup
|
||||
# Point to the installer src directory (not needed in this test)
|
||||
|
||||
# Set installer/paths environment for the test
|
||||
export AC_PATH_APPS="$TEST_DIR/apps"
|
||||
export AC_PATH_ROOT="$TEST_DIR"
|
||||
export AC_PATH_DEPS="$TEST_DIR/deps"
|
||||
export AC_PATH_MODULES="$TEST_DIR/modules"
|
||||
export MODULES_LIST_FILE="$TEST_DIR/conf/modules.list"
|
||||
|
||||
# Create stubbed deps: joiner.sh (sourced by includes) and semver
|
||||
mkdir -p "$TEST_DIR/deps/acore/joiner"
|
||||
cat > "$TEST_DIR/deps/acore/joiner/joiner.sh" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Stub joiner functions used by installer
|
||||
Joiner:add_repo() {
|
||||
# arguments: url name branch basedir
|
||||
echo "ADD $@" > "$TEST_DIR/joiner_called.txt"
|
||||
return 0
|
||||
}
|
||||
Joiner:upd_repo() {
|
||||
echo "UPD $@" > "$TEST_DIR/joiner_called.txt"
|
||||
return 0
|
||||
}
|
||||
Joiner:remove() {
|
||||
echo "REM $@" > "$TEST_DIR/joiner_called.txt"
|
||||
return 0
|
||||
}
|
||||
EOF
|
||||
chmod +x "$TEST_DIR/deps/acore/joiner/joiner.sh"
|
||||
|
||||
mkdir -p "$TEST_DIR/deps/semver_bash"
|
||||
# Minimal semver stub
|
||||
cat > "$TEST_DIR/deps/semver_bash/semver.sh" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# semver stub
|
||||
semver::satisfies() { return 0; }
|
||||
EOF
|
||||
chmod +x "$TEST_DIR/deps/semver_bash/semver.sh"
|
||||
|
||||
# Provide a minimal compiler includes file expected by installer
|
||||
mkdir -p "$TEST_DIR/apps/compiler/includes"
|
||||
touch "$TEST_DIR/apps/compiler/includes/includes.sh"
|
||||
|
||||
# Provide minimal bash_shared includes to satisfy installer include
|
||||
mkdir -p "$TEST_DIR/apps/bash_shared"
|
||||
cat > "$TEST_DIR/apps/bash_shared/includes.sh" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# minimal stub
|
||||
EOF
|
||||
|
||||
# Copy the menu system needed by modules.sh
|
||||
cp "$AC_TEST_ROOT/apps/bash_shared/menu_system.sh" "$TEST_DIR/apps/bash_shared/"
|
||||
|
||||
# Copy the real installer app into the test apps dir
|
||||
mkdir -p "$TEST_DIR/apps"
|
||||
cp -r "$(cd "$AC_TEST_ROOT/apps/installer" && pwd)" "$TEST_DIR/apps/installer"
|
||||
}
|
||||
|
||||
teardown() {
|
||||
acore_test_teardown
|
||||
}
|
||||
|
||||
@test "module install should call joiner and record entry in modules list" {
|
||||
cd "$TEST_DIR"
|
||||
|
||||
# Source installer includes and call the install function directly to avoid menu interaction
|
||||
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_install example-module@main:abcd1234"
|
||||
|
||||
# Check that joiner was called
|
||||
[ -f "$TEST_DIR/joiner_called.txt" ]
|
||||
grep -q "ADD" "$TEST_DIR/joiner_called.txt"
|
||||
|
||||
# Check modules list was created and contains the repo_ref and branch
|
||||
[ -f "$TEST_DIR/conf/modules.list" ]
|
||||
grep -q "azerothcore/example-module main" "$TEST_DIR/conf/modules.list"
|
||||
}
|
||||
|
||||
@test "module install with owner/name format should work" {
|
||||
cd "$TEST_DIR"
|
||||
|
||||
# Test with owner/name format
|
||||
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_install myorg/mymodule"
|
||||
|
||||
# Check that joiner was called with correct URL
|
||||
[ -f "$TEST_DIR/joiner_called.txt" ]
|
||||
grep -q "ADD https://github.com/myorg/mymodule mymodule" "$TEST_DIR/joiner_called.txt"
|
||||
|
||||
# Check modules list contains the entry
|
||||
[ -f "$TEST_DIR/conf/modules.list" ]
|
||||
grep -q "myorg/mymodule" "$TEST_DIR/conf/modules.list"
|
||||
}
|
||||
|
||||
@test "module remove should call joiner remove and update modules list" {
|
||||
cd "$TEST_DIR"
|
||||
|
||||
# First install a module
|
||||
bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_install test-module"
|
||||
|
||||
# Then remove it
|
||||
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_remove test-module"
|
||||
|
||||
# Check that joiner remove was called
|
||||
[ -f "$TEST_DIR/joiner_called.txt" ]
|
||||
# With flat structure, basedir is empty; ensure name is present
|
||||
grep -q "REM test-module" "$TEST_DIR/joiner_called.txt"
|
||||
|
||||
# Check modules list no longer contains the entry
|
||||
[ -f "$TEST_DIR/conf/modules.list" ]
|
||||
! grep -q "azerothcore/test-module" "$TEST_DIR/conf/modules.list"
|
||||
}
|
||||
|
||||
# Tests for intelligent module management (duplicate prevention and cross-format removal)
|
||||
|
||||
@test "inst_extract_owner_name should extract owner/name from various formats" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test simple name
|
||||
run inst_extract_owner_name "mod-transmog"
|
||||
[ "$output" = "azerothcore/mod-transmog" ]
|
||||
|
||||
# Test owner/name format
|
||||
run inst_extract_owner_name "azerothcore/mod-transmog"
|
||||
[ "$output" = "azerothcore/mod-transmog" ]
|
||||
|
||||
# Test HTTPS URL
|
||||
run inst_extract_owner_name "https://github.com/azerothcore/mod-transmog.git"
|
||||
[ "$output" = "azerothcore/mod-transmog" ]
|
||||
|
||||
# Test SSH URL
|
||||
run inst_extract_owner_name "git@github.com:azerothcore/mod-transmog.git"
|
||||
[ "$output" = "azerothcore/mod-transmog" ]
|
||||
|
||||
# Test GitLab URL
|
||||
run inst_extract_owner_name "https://gitlab.com/myorg/mymodule.git"
|
||||
[ "$output" = "myorg/mymodule" ]
|
||||
}
|
||||
|
||||
@test "inst_extract_owner_name should handle URLs with ports correctly" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test HTTPS URL with port
|
||||
run inst_extract_owner_name "https://example.com:8080/user/repo.git"
|
||||
[ "$output" = "user/repo" ]
|
||||
|
||||
# Test SSH URL with port
|
||||
run inst_extract_owner_name "ssh://git@example.com:2222/owner/module"
|
||||
[ "$output" = "owner/module" ]
|
||||
|
||||
# Test URL with port and custom directory (should ignore the directory part)
|
||||
run inst_extract_owner_name "https://gitlab.internal:9443/team/project.git:custom-dir"
|
||||
[ "$output" = "team/project" ]
|
||||
|
||||
# Test complex URL with port (should extract owner/name correctly)
|
||||
run inst_extract_owner_name "https://git.company.com:8443/department/awesome-module.git"
|
||||
[ "$output" = "department/awesome-module" ]
|
||||
}
|
||||
|
||||
@test "duplicate module entries should be prevented across different formats" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Add module via simple name
|
||||
inst_mod_list_upsert "mod-transmog" "master" "abc123"
|
||||
|
||||
# Verify it's in the list
|
||||
grep -q "mod-transmog master abc123" "$TEST_DIR/conf/modules.list"
|
||||
|
||||
# Add same module via owner/name format - should replace, not duplicate
|
||||
inst_mod_list_upsert "azerothcore/mod-transmog" "dev" "def456"
|
||||
|
||||
# Should only have one entry (the new one)
|
||||
[ "$(grep -c "azerothcore/mod-transmog" "$TEST_DIR/conf/modules.list")" -eq 1 ]
|
||||
grep -q "azerothcore/mod-transmog dev def456" "$TEST_DIR/conf/modules.list"
|
||||
! grep -q "mod-transmog master abc123" "$TEST_DIR/conf/modules.list"
|
||||
}
|
||||
|
||||
@test "module installed via URL should be recognized when checking with different formats" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Install via HTTPS URL
|
||||
inst_mod_list_upsert "https://github.com/azerothcore/mod-transmog.git" "master" "abc123"
|
||||
|
||||
# Should be detected as installed using simple name
|
||||
run inst_mod_is_installed "mod-transmog"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Should be detected as installed using owner/name
|
||||
run inst_mod_is_installed "azerothcore/mod-transmog"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Should be detected as installed using SSH URL
|
||||
run inst_mod_is_installed "git@github.com:azerothcore/mod-transmog.git"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Non-existent module should not be detected
|
||||
run inst_mod_is_installed "mod-nonexistent"
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "module installed via URL with port should be recognized correctly" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Install via URL with port
|
||||
inst_mod_list_upsert "https://gitlab.internal:9443/myorg/my-module.git" "master" "abc123"
|
||||
|
||||
# Should be detected as installed using normalized owner/name
|
||||
run inst_mod_is_installed "myorg/my-module"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Should be detected when checking with different URL format
|
||||
run inst_mod_is_installed "ssh://git@gitlab.internal:9443/myorg/my-module"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Should be detected when checking with custom directory syntax
|
||||
run inst_mod_is_installed "myorg/my-module:custom-dir"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Different module should not be detected
|
||||
run inst_mod_is_installed "myorg/different-module"
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "cross-format module removal should work" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Install via SSH URL
|
||||
inst_mod_list_upsert "git@github.com:azerothcore/mod-transmog.git" "master" "abc123"
|
||||
|
||||
# Verify it's installed
|
||||
grep -q "git@github.com:azerothcore/mod-transmog.git" "$TEST_DIR/conf/modules.list"
|
||||
|
||||
# Remove using simple name
|
||||
inst_mod_list_remove "mod-transmog"
|
||||
|
||||
# Should be completely removed
|
||||
! grep -q "azerothcore/mod-transmog" "$TEST_DIR/conf/modules.list"
|
||||
! grep -q "git@github.com:azerothcore/mod-transmog.git" "$TEST_DIR/conf/modules.list"
|
||||
}
|
||||
|
||||
@test "module installation should prevent duplicates when already installed" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Install via simple name first
|
||||
inst_mod_list_upsert "mod-worldchat" "master" "abc123"
|
||||
|
||||
# Try to install same module via URL - should detect it's already installed
|
||||
run inst_mod_is_installed "https://github.com/azerothcore/mod-worldchat.git"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Add via URL should replace the existing entry
|
||||
inst_mod_list_upsert "https://github.com/azerothcore/mod-worldchat.git" "dev" "def456"
|
||||
|
||||
# Should only have one entry
|
||||
[ "$(grep -c "azerothcore/mod-worldchat" "$TEST_DIR/conf/modules.list")" -eq 1 ]
|
||||
grep -q "https://github.com/azerothcore/mod-worldchat.git dev def456" "$TEST_DIR/conf/modules.list"
|
||||
}
|
||||
|
||||
@test "module update --all uses flat structure (no branch subfolders)" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Prepare modules.list with one entry and a matching local directory
|
||||
mkdir -p "$TEST_DIR/conf"
|
||||
echo "azerothcore/mod-transmog master abc123" > "$TEST_DIR/conf/modules.list"
|
||||
mkdir -p "$TEST_DIR/modules/mod-transmog"
|
||||
|
||||
# Run update all
|
||||
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_update --all"
|
||||
|
||||
# Verify Joiner:upd_repo received flat structure args (no basedir)
|
||||
[ -f "$TEST_DIR/joiner_called.txt" ]
|
||||
grep -q "UPD https://github.com/azerothcore/mod-transmog mod-transmog master" "$TEST_DIR/joiner_called.txt"
|
||||
}
|
||||
|
||||
@test "module update specific uses flat structure with override branch" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Create local directory so update proceeds
|
||||
mkdir -p "$TEST_DIR/modules/mymodule"
|
||||
|
||||
# Run update specifying owner/name and branch
|
||||
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_update myorg/mymodule@dev"
|
||||
|
||||
# Should call joiner with name 'mymodule' and branch 'dev' (no basedir)
|
||||
[ -f "$TEST_DIR/joiner_called.txt" ]
|
||||
grep -q "UPD https://github.com/myorg/mymodule mymodule dev" "$TEST_DIR/joiner_called.txt"
|
||||
}
|
||||
|
||||
@test "custom directory names should work with new syntax" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test parsing with custom directory name
|
||||
run inst_parse_module_spec "mod-transmog:my-custom-dir@develop:abc123"
|
||||
[ "$status" -eq 0 ]
|
||||
# Should output: repo_ref owner name branch commit url dirname
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "azerothcore/mod-transmog" ]
|
||||
[ "$owner" = "azerothcore" ]
|
||||
[ "$name" = "mod-transmog" ]
|
||||
[ "$branch" = "develop" ]
|
||||
[ "$commit" = "abc123" ]
|
||||
[ "$url" = "https://github.com/azerothcore/mod-transmog" ]
|
||||
[ "$dirname" = "my-custom-dir" ]
|
||||
}
|
||||
|
||||
@test "directory conflict detection should work" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Create a fake existing directory
|
||||
mkdir -p "$TEST_DIR/modules/existing-dir"
|
||||
|
||||
# Should detect conflict
|
||||
run inst_check_module_conflict "existing-dir" "mod-test"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ "Directory 'existing-dir' already exists" ]]
|
||||
[[ "$output" =~ "Use a different directory name: mod-test:my-custom-name" ]]
|
||||
|
||||
# Should not detect conflict for non-existing directory
|
||||
run inst_check_module_conflict "non-existing-dir" "mod-test"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "module update should work with custom directories" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# First add module with custom directory to list
|
||||
inst_mod_list_upsert "azerothcore/mod-transmog:custom-dir" "master" "abc123"
|
||||
|
||||
# Create fake module directory structure
|
||||
mkdir -p "$TEST_DIR/modules/custom-dir/.git"
|
||||
echo "ref: refs/heads/master" > "$TEST_DIR/modules/custom-dir/.git/HEAD"
|
||||
|
||||
# Mock git commands in the fake module directory
|
||||
cat > "$TEST_DIR/modules/custom-dir/.git/config" << 'EOF'
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
[remote "origin"]
|
||||
url = https://github.com/azerothcore/mod-transmog
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
EOF
|
||||
|
||||
# Test update with custom directory should work
|
||||
# Note: This would require more complex mocking for full integration test
|
||||
# For now, just test the parsing recognizes the custom directory
|
||||
run inst_parse_module_spec "azerothcore/mod-transmog:custom-dir"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$dirname" = "custom-dir" ]
|
||||
}
|
||||
|
||||
@test "URL formats should be properly normalized" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test various URL formats produce same owner/name
|
||||
run inst_extract_owner_name "https://github.com/azerothcore/mod-transmog"
|
||||
local url_format="$output"
|
||||
|
||||
run inst_extract_owner_name "https://github.com/azerothcore/mod-transmog.git"
|
||||
local url_git_format="$output"
|
||||
|
||||
run inst_extract_owner_name "git@github.com:azerothcore/mod-transmog.git"
|
||||
local ssh_format="$output"
|
||||
|
||||
run inst_extract_owner_name "azerothcore/mod-transmog"
|
||||
local owner_name_format="$output"
|
||||
|
||||
run inst_extract_owner_name "mod-transmog"
|
||||
local simple_format="$output"
|
||||
|
||||
# All should normalize to the same owner/name
|
||||
[ "$url_format" = "azerothcore/mod-transmog" ]
|
||||
[ "$url_git_format" = "azerothcore/mod-transmog" ]
|
||||
[ "$ssh_format" = "azerothcore/mod-transmog" ]
|
||||
[ "$owner_name_format" = "azerothcore/mod-transmog" ]
|
||||
[ "$simple_format" = "azerothcore/mod-transmog" ]
|
||||
}
|
||||
|
||||
# Tests for module exclusion functionality
|
||||
|
||||
@test "module exclusion should work with MODULES_EXCLUDE_LIST" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test exclusion with simple name
|
||||
export MODULES_EXCLUDE_LIST="mod-test-module"
|
||||
run inst_mod_is_excluded "mod-test-module"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Test exclusion with owner/name format
|
||||
export MODULES_EXCLUDE_LIST="azerothcore/mod-test"
|
||||
run inst_mod_is_excluded "mod-test"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Test exclusion with space-separated list
|
||||
export MODULES_EXCLUDE_LIST="mod-one mod-two mod-three"
|
||||
run inst_mod_is_excluded "mod-two"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Test exclusion with newline-separated list
|
||||
export MODULES_EXCLUDE_LIST="
|
||||
mod-alpha
|
||||
mod-beta
|
||||
mod-gamma
|
||||
"
|
||||
run inst_mod_is_excluded "mod-beta"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Test exclusion with URL format
|
||||
export MODULES_EXCLUDE_LIST="https://github.com/azerothcore/mod-transmog.git"
|
||||
run inst_mod_is_excluded "mod-transmog"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Test non-excluded module
|
||||
export MODULES_EXCLUDE_LIST="mod-other"
|
||||
run inst_mod_is_excluded "mod-transmog"
|
||||
[ "$status" -eq 1 ]
|
||||
|
||||
# Test empty exclusion list
|
||||
unset MODULES_EXCLUDE_LIST
|
||||
run inst_mod_is_excluded "mod-transmog"
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "install --all should skip excluded modules" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Setup modules list with excluded module
|
||||
mkdir -p "$TEST_DIR/conf"
|
||||
cat > "$TEST_DIR/conf/modules.list" << 'EOF'
|
||||
azerothcore/mod-transmog master abc123
|
||||
azerothcore/mod-excluded master def456
|
||||
EOF
|
||||
|
||||
# Set exclusion list
|
||||
export MODULES_EXCLUDE_LIST="mod-excluded"
|
||||
|
||||
# Mock the install process to capture output
|
||||
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_install --all 2>&1"
|
||||
|
||||
# Should show that excluded module was skipped
|
||||
[[ "$output" == *"azerothcore/mod-excluded"* && "$output" == *"Excluded by MODULES_EXCLUDE_LIST"* && "$output" == *"skipping"* ]]
|
||||
}
|
||||
|
||||
@test "exclusion should work with multiple formats in same list" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test multiple exclusion formats
|
||||
export MODULES_EXCLUDE_LIST="mod-test https://github.com/azerothcore/mod-transmog.git custom/mod-other"
|
||||
|
||||
run inst_mod_is_excluded "mod-test"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run inst_mod_is_excluded "azerothcore/mod-transmog"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run inst_mod_is_excluded "custom/mod-other"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run inst_mod_is_excluded "mod-allowed"
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
# Tests for color support functionality
|
||||
|
||||
@test "color functions should work correctly" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test that print functions exist and work
|
||||
run print_info "test message"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run print_warn "test warning"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run print_error "test error"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run print_success "test success"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run print_skip "test skip"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run print_header "test header"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "color support should respect NO_COLOR environment variable" {
|
||||
cd "$TEST_DIR"
|
||||
|
||||
# Test with NO_COLOR set
|
||||
export NO_COLOR=1
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Colors should be empty when NO_COLOR is set
|
||||
[ -z "$C_RED" ]
|
||||
[ -z "$C_GREEN" ]
|
||||
[ -z "$C_RESET" ]
|
||||
}
|
||||
|
||||
# Tests for interactive menu system
|
||||
|
||||
@test "module help should display comprehensive help" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
run inst_module_help
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Should contain key sections
|
||||
[[ "$output" =~ "Module Manager Help" ]]
|
||||
[[ "$output" =~ "Usage:" ]]
|
||||
[[ "$output" =~ "Module Specification Syntax:" ]]
|
||||
[[ "$output" =~ "Examples:" ]]
|
||||
}
|
||||
|
||||
@test "module list should show installed modules correctly" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Setup modules list
|
||||
mkdir -p "$TEST_DIR/conf"
|
||||
cat > "$TEST_DIR/conf/modules.list" << 'EOF'
|
||||
azerothcore/mod-transmog master abc123
|
||||
custom/mod-test develop def456
|
||||
EOF
|
||||
|
||||
run inst_module_list
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Should show both modules
|
||||
[[ "$output" =~ "mod-transmog" ]]
|
||||
[[ "$output" =~ "custom/mod-test" ]]
|
||||
[[ "$output" =~ "master" ]]
|
||||
[[ "$output" =~ "develop" ]]
|
||||
}
|
||||
|
||||
@test "module list should handle empty list gracefully" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Ensure empty modules list
|
||||
mkdir -p "$TEST_DIR/conf"
|
||||
touch "$TEST_DIR/conf/modules.list"
|
||||
|
||||
run inst_module_list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "No modules installed" ]]
|
||||
}
|
||||
|
||||
# Tests for advanced parsing edge cases
|
||||
|
||||
@test "parsing should handle complex URL formats" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test GitLab URL with custom directory and branch
|
||||
run inst_parse_module_spec "https://gitlab.com/myorg/mymodule.git:custom-dir@develop:abc123"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "https://gitlab.com/myorg/mymodule.git" ]
|
||||
[ "$owner" = "myorg" ]
|
||||
[ "$name" = "mymodule" ]
|
||||
[ "$branch" = "develop" ]
|
||||
[ "$commit" = "abc123" ]
|
||||
[ "$dirname" = "custom-dir" ]
|
||||
}
|
||||
|
||||
@test "parsing should handle URLs with ports correctly (fix for port/dirname confusion)" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test HTTPS URL with port - should NOT treat port as dirname
|
||||
run inst_parse_module_spec "https://example.com:8080/user/repo.git"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "https://example.com:8080/user/repo.git" ]
|
||||
[ "$owner" = "user" ]
|
||||
[ "$name" = "repo" ]
|
||||
[ "$branch" = "-" ]
|
||||
[ "$commit" = "-" ]
|
||||
[ "$url" = "https://example.com:8080/user/repo.git" ]
|
||||
[ "$dirname" = "repo" ] # Should default to repo name, NOT port number
|
||||
}
|
||||
|
||||
@test "parsing should handle URLs with ports and custom directory correctly" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test URL with port AND custom directory - should parse custom directory correctly
|
||||
run inst_parse_module_spec "https://example.com:8080/user/repo.git:custom-dir"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "https://example.com:8080/user/repo.git" ]
|
||||
[ "$owner" = "user" ]
|
||||
[ "$name" = "repo" ]
|
||||
[ "$branch" = "-" ]
|
||||
[ "$commit" = "-" ]
|
||||
[ "$url" = "https://example.com:8080/user/repo.git" ]
|
||||
[ "$dirname" = "custom-dir" ] # Should be custom-dir, not port number
|
||||
}
|
||||
|
||||
@test "parsing should handle SSH URLs with ports correctly" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test SSH URL with port
|
||||
run inst_parse_module_spec "ssh://git@example.com:2222/user/repo"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "ssh://git@example.com:2222/user/repo" ]
|
||||
[ "$owner" = "user" ]
|
||||
[ "$name" = "repo" ]
|
||||
[ "$dirname" = "repo" ] # Should be repo name, not port number
|
||||
}
|
||||
|
||||
@test "parsing should handle SSH URLs with ports and custom directory" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test SSH URL with port and custom directory
|
||||
run inst_parse_module_spec "ssh://git@example.com:2222/user/repo:my-custom-dir@develop"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "ssh://git@example.com:2222/user/repo" ]
|
||||
[ "$owner" = "user" ]
|
||||
[ "$name" = "repo" ]
|
||||
[ "$branch" = "develop" ]
|
||||
[ "$dirname" = "my-custom-dir" ]
|
||||
}
|
||||
|
||||
@test "parsing should handle complex URLs with ports, custom dirs, and branches" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Test comprehensive URL with port, custom directory, branch, and commit
|
||||
run inst_parse_module_spec "https://gitlab.example.com:9443/myorg/myrepo.git:custom-name@feature-branch:abc123def"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "https://gitlab.example.com:9443/myorg/myrepo.git" ]
|
||||
[ "$owner" = "myorg" ]
|
||||
[ "$name" = "myrepo" ]
|
||||
[ "$branch" = "feature-branch" ]
|
||||
[ "$commit" = "abc123def" ]
|
||||
[ "$url" = "https://gitlab.example.com:9443/myorg/myrepo.git" ]
|
||||
[ "$dirname" = "custom-name" ]
|
||||
}
|
||||
|
||||
@test "URL port parsing regression test - ensure ports are not confused with directory names" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# These are the problematic cases that the fix addresses
|
||||
local test_cases=(
|
||||
"https://example.com:8080/repo.git"
|
||||
"https://gitlab.internal:9443/group/project.git"
|
||||
"ssh://git@server.com:2222/owner/repo"
|
||||
"https://git.company.com:8443/team/module.git"
|
||||
)
|
||||
|
||||
for spec in "${test_cases[@]}"; do
|
||||
run inst_parse_module_spec "$spec"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
|
||||
# Critical: dirname should NEVER be a port number
|
||||
[[ ! "$dirname" =~ ^[0-9]+$ ]] || {
|
||||
echo "FAIL: Port number '$dirname' incorrectly parsed as directory name for spec: $spec"
|
||||
return 1
|
||||
}
|
||||
|
||||
# dirname should be the repository name by default
|
||||
local expected_name
|
||||
if [[ "$spec" =~ /([^/]+)(\.git)?$ ]]; then
|
||||
expected_name="${BASH_REMATCH[1]}"
|
||||
expected_name="${expected_name%.git}"
|
||||
fi
|
||||
[ "$dirname" = "$expected_name" ] || {
|
||||
echo "FAIL: Expected dirname '$expected_name' but got '$dirname' for spec: $spec"
|
||||
return 1
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
@test "parsing should handle URL with custom directory but no branch" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
run inst_parse_module_spec "https://github.com/owner/repo.git:my-dir"
|
||||
[ "$status" -eq 0 ]
|
||||
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||
[ "$repo_ref" = "https://github.com/owner/repo.git" ]
|
||||
[ "$dirname" = "my-dir" ]
|
||||
[ "$branch" = "-" ]
|
||||
}
|
||||
|
||||
@test "modules list should maintain alphabetical order" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
# Add modules in random order
|
||||
inst_mod_list_upsert "zeta/mod-z" "master" "abc"
|
||||
inst_mod_list_upsert "alpha/mod-a" "master" "def"
|
||||
inst_mod_list_upsert "beta/mod-b" "master" "ghi"
|
||||
|
||||
# Read the list and verify alphabetical order
|
||||
local entries=()
|
||||
while read -r repo_ref branch commit; do
|
||||
[[ -z "$repo_ref" ]] && continue
|
||||
entries+=("$repo_ref")
|
||||
done < <(inst_mod_list_read)
|
||||
|
||||
# Should be in alphabetical order by owner/name
|
||||
[ "${entries[0]}" = "alpha/mod-a" ]
|
||||
[ "${entries[1]}" = "beta/mod-b" ]
|
||||
[ "${entries[2]}" = "zeta/mod-z" ]
|
||||
}
|
||||
|
||||
@test "module dispatcher should handle unknown commands gracefully" {
|
||||
cd "$TEST_DIR"
|
||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||
|
||||
run inst_module "unknown-command"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ "Unknown module command" ]]
|
||||
}
|
||||
@@ -305,6 +305,31 @@ Services support two restart policies:
|
||||
./service-manager.sh delete auth
|
||||
```
|
||||
|
||||
#### Health and Console Commands
|
||||
|
||||
Use these commands to programmatically check service health and interact with the console (used by CI workflows):
|
||||
|
||||
```bash
|
||||
# Check if service is currently running (exit 0 if running)
|
||||
./service-manager.sh is-running world
|
||||
|
||||
# Print current uptime in seconds (fails if not running)
|
||||
./service-manager.sh uptime-seconds world
|
||||
|
||||
# Wait until uptime >= 10s (optional timeout 240s)
|
||||
./service-manager.sh wait-uptime world 10 240
|
||||
|
||||
# Send a console command (uses pm2 send or tmux/screen)
|
||||
./service-manager.sh send world "server info"
|
||||
|
||||
# Show provider, configs and run-engine settings
|
||||
./service-manager.sh show-config world
|
||||
```
|
||||
|
||||
Notes:
|
||||
- For `send`, PM2 provider uses `pm2 send` with the process ID; systemd provider requires a session manager (tmux/screen). If no attachable session is configured, the command fails.
|
||||
- `wait-uptime` fails with a non-zero exit code if the service does not reach the requested uptime within the timeout window.
|
||||
|
||||
#### Service Configuration
|
||||
```bash
|
||||
# Update service settings
|
||||
@@ -624,4 +649,3 @@ sudo npm install -g pm2
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -279,6 +279,11 @@ function print_help() {
|
||||
echo " $base_name start|stop|restart|status <service-name>"
|
||||
echo " $base_name logs <service-name> [--follow]"
|
||||
echo " $base_name attach <service-name>"
|
||||
echo " $base_name is-running <service-name> # exit 0 if running, 1 otherwise"
|
||||
echo " $base_name uptime-seconds <service-name> # print uptime in seconds (fails if not running)"
|
||||
echo " $base_name wait-uptime <service> <sec> [t] # wait until uptime >= seconds (timeout t, default 120)"
|
||||
echo " $base_name send <service-name> <command...> # send console command to service"
|
||||
echo " $base_name show-config <service-name> # print current service + run-engine config"
|
||||
echo " $base_name edit-config <service-name>"
|
||||
echo ""
|
||||
echo "Providers:"
|
||||
@@ -735,7 +740,7 @@ EOF
|
||||
systemctl --user enable "$service_name.service"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Systemd service '$service_name' created successfully${NC}"
|
||||
echo -e "${GREEN}Systemd service '$service_name' created successfully with session manager '$session_manager'${NC}"
|
||||
|
||||
# Add to registry
|
||||
add_service_to_registry "$service_name" "systemd" "service" "$command" "" "$systemd_type" "$restart_policy" "$session_manager" "$gdb_enabled" "" "$server_config"
|
||||
@@ -1473,6 +1478,253 @@ function attach_to_service() {
|
||||
fi
|
||||
}
|
||||
|
||||
#########################################
|
||||
# Runtime helpers: status / send / show #
|
||||
#########################################
|
||||
|
||||
function service_is_running() {
|
||||
local service_name="$1"
|
||||
|
||||
local service_info=$(get_service_info "$service_name")
|
||||
if [ -z "$service_info" ]; then
|
||||
echo -e "${RED}Error: Service '$service_name' not found${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local provider=$(echo "$service_info" | jq -r '.provider')
|
||||
|
||||
if [ "$provider" = "pm2" ]; then
|
||||
# pm2 jlist -> JSON array with .name and .pm2_env.status
|
||||
if pm2 jlist | jq -e ".[] | select(.name==\"$service_name\" and .pm2_env.status==\"online\")" >/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
elif [ "$provider" = "systemd" ]; then
|
||||
# Check user service first, then system
|
||||
if systemctl --user is-active --quiet "$service_name.service" 2>/dev/null; then
|
||||
return 0
|
||||
elif systemctl is-active --quiet "$service_name.service" 2>/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function service_send_command() {
|
||||
local service_name="$1"; shift || true
|
||||
local cmd_str="$*"
|
||||
if [ -z "$service_name" ] || [ -z "$cmd_str" ]; then
|
||||
echo -e "${RED}Error: send requires <service-name> and <command>${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local service_info=$(get_service_info "$service_name")
|
||||
if [ -z "$service_info" ]; then
|
||||
echo -e "${RED}Error: Service '$service_name' not found${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local provider=$(echo "$service_info" | jq -r '.provider')
|
||||
local config_file="$CONFIG_DIR/$service_name.conf"
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo -e "${RED}Error: Service configuration file not found: $config_file${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Load run-engine config path
|
||||
# shellcheck source=/dev/null
|
||||
source "$config_file"
|
||||
if [ -z "${RUN_ENGINE_CONFIG_FILE:-}" ] || [ ! -f "$RUN_ENGINE_CONFIG_FILE" ]; then
|
||||
echo -e "${RED}Error: Run-engine configuration file not found for $service_name${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
if ! source "$RUN_ENGINE_CONFIG_FILE"; then
|
||||
echo -e "${RED}Error: Failed to source run-engine configuration file: $RUN_ENGINE_CONFIG_FILE${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local session_manager="${SESSION_MANAGER:-auto}"
|
||||
local session_name="${SESSION_NAME:-$service_name}"
|
||||
|
||||
if [ "$provider" = "pm2" ]; then
|
||||
# Use pm2 send (requires pm2 >= 5)
|
||||
local pm2_id_json
|
||||
pm2_id_json=$(pm2 id "$service_name" 2>/dev/null || true)
|
||||
local numeric_id
|
||||
numeric_id=$(echo "$pm2_id_json" | jq -r '.[0] // empty')
|
||||
if [ -z "$numeric_id" ]; then
|
||||
echo -e "${RED}Error: PM2 process '$service_name' not found${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
echo -e "${YELLOW}Sending to PM2 process $service_name (ID: $numeric_id): $cmd_str${NC}"
|
||||
pm2 send "$numeric_id" "$cmd_str" ENTER
|
||||
return $?
|
||||
fi
|
||||
|
||||
# systemd provider: need a session manager to interact with the console
|
||||
case "$session_manager" in
|
||||
tmux|auto)
|
||||
if command -v tmux >/dev/null 2>&1 && tmux has-session -t "$session_name" 2>/dev/null; then
|
||||
echo -e "${YELLOW}Sending to tmux session $session_name: $cmd_str${NC}"
|
||||
tmux send-keys -t "$session_name" "$cmd_str" C-m
|
||||
return $?
|
||||
elif [ "$session_manager" = "tmux" ]; then
|
||||
echo -e "${RED}Error: tmux session '$session_name' not available${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
;;&
|
||||
screen|auto)
|
||||
if command -v screen >/dev/null 2>&1; then
|
||||
echo -e "${YELLOW}Sending to screen session $session_name: $cmd_str${NC}"
|
||||
screen -S "$session_name" -X stuff "$cmd_str\n"
|
||||
return $?
|
||||
elif [ "$session_manager" = "screen" ]; then
|
||||
echo -e "${RED}Error: screen not installed${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
none|*)
|
||||
echo -e "${RED}Error: No session manager configured (SESSION_MANAGER=$session_manager). Cannot send command.${NC}" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo -e "${RED}Error: Unable to find usable session (tmux/screen) to send command.${NC}" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
function show_config() {
|
||||
local service_name="$1"
|
||||
if [ -z "$service_name" ]; then
|
||||
echo -e "${RED}Error: Service name required for show-config${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local service_info=$(get_service_info "$service_name")
|
||||
if [ -z "$service_info" ]; then
|
||||
echo -e "${RED}Error: Service '$service_name' not found${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local provider=$(echo "$service_info" | jq -r '.provider')
|
||||
local cfg_file="$CONFIG_DIR/$service_name.conf"
|
||||
echo -e "${BLUE}Service: $service_name${NC}"
|
||||
echo "Provider: $provider"
|
||||
echo "Config file: $cfg_file"
|
||||
if [ -f "$cfg_file" ]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "$cfg_file"
|
||||
echo "RUN_ENGINE_CONFIG_FILE: ${RUN_ENGINE_CONFIG_FILE:-<none>}"
|
||||
if [ -n "${RUN_ENGINE_CONFIG_FILE:-}" ] && [ -f "$RUN_ENGINE_CONFIG_FILE" ]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "$RUN_ENGINE_CONFIG_FILE"
|
||||
echo "Session manager: ${SESSION_MANAGER:-}"
|
||||
echo "Session name: ${SESSION_NAME:-}"
|
||||
echo "BINPATH: ${BINPATH:-}"
|
||||
echo "SERVERBIN: ${SERVERBIN:-}"
|
||||
echo "CONFIG: ${CONFIG:-}"
|
||||
echo "RESTART_POLICY: ${RESTART_POLICY:-}"
|
||||
fi
|
||||
else
|
||||
echo "Config file not found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Return uptime in seconds for a service (echo integer), non-zero exit if not running
|
||||
function service_uptime_seconds() {
|
||||
local service_name="$1"
|
||||
local service_info=$(get_service_info "$service_name")
|
||||
if [ -z "$service_info" ]; then
|
||||
echo -e "${RED}Error: Service '$service_name' not found${NC}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local provider=$(echo "$service_info" | jq -r '.provider')
|
||||
|
||||
if [ "$provider" = "pm2" ]; then
|
||||
check_pm2 || return 1
|
||||
local info_json
|
||||
info_json=$(pm2 jlist 2>/dev/null)
|
||||
local pm_uptime_ms
|
||||
pm_uptime_ms=$(echo "$info_json" | jq -r ".[] | select(.name==\"$service_name\").pm2_env.pm_uptime // empty")
|
||||
local status
|
||||
status=$(echo "$info_json" | jq -r ".[] | select(.name==\"$service_name\").pm2_env.status // empty")
|
||||
if [ -z "$pm_uptime_ms" ] || [ "$status" != "online" ]; then
|
||||
return 1
|
||||
fi
|
||||
# Current time in ms (fallback to seconds*1000 if %N unsupported)
|
||||
local now_ms
|
||||
if date +%s%N >/dev/null 2>&1; then
|
||||
now_ms=$(( $(date +%s%N) / 1000000 ))
|
||||
else
|
||||
now_ms=$(( $(date +%s) * 1000 ))
|
||||
fi
|
||||
local diff_ms=$(( now_ms - pm_uptime_ms ))
|
||||
[ "$diff_ms" -lt 0 ] && diff_ms=0
|
||||
echo $(( diff_ms / 1000 ))
|
||||
return 0
|
||||
elif [ "$provider" = "systemd" ]; then
|
||||
check_systemd || return 1
|
||||
local systemd_type="--user"
|
||||
[ -f "/etc/systemd/system/$service_name.service" ] && systemd_type="--system"
|
||||
|
||||
# Get ActiveEnterTimestampMonotonic in usec and ActiveState
|
||||
local prop
|
||||
if [ "$systemd_type" = "--system" ]; then
|
||||
prop=$(systemctl show "$service_name.service" --property=ActiveEnterTimestampMonotonic,ActiveState 2>/dev/null)
|
||||
else
|
||||
prop=$(systemctl --user show "$service_name.service" --property=ActiveEnterTimestampMonotonic,ActiveState 2>/dev/null)
|
||||
fi
|
||||
local state
|
||||
state=$(echo "$prop" | awk -F= '/^ActiveState=/{print $2}')
|
||||
[ "$state" != "active" ] && return 1
|
||||
local enter_us
|
||||
enter_us=$(echo "$prop" | awk -F= '/^ActiveEnterTimestampMonotonic=/{print $2}')
|
||||
# Current monotonic time in seconds since boot
|
||||
local now_s
|
||||
now_s=$(cut -d' ' -f1 /proc/uptime)
|
||||
# Compute uptime = now_monotonic - enter_monotonic
|
||||
# enter_us may be empty on some systems; fallback to 0
|
||||
enter_us=${enter_us:-0}
|
||||
# Convert now_s to microseconds using awk for precision, then compute diff
|
||||
local diff_s
|
||||
diff_s=$(awk -v now="$now_s" -v enter="$enter_us" 'BEGIN{printf "%d", (now*1000000 - enter)/1000000}')
|
||||
[ "$diff_s" -lt 0 ] && diff_s=0
|
||||
echo "$diff_s"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait until service has at least <min_seconds> uptime. Optional timeout seconds (default 120)
|
||||
function wait_service_uptime() {
|
||||
local service_name="$1"
|
||||
local min_seconds="$2"
|
||||
local timeout="${3:-120}"
|
||||
local waited=0
|
||||
|
||||
while [ "$waited" -le "$timeout" ]; do
|
||||
if secs=$(service_uptime_seconds "$service_name" 2>/dev/null); then
|
||||
if [ "$secs" -ge "$min_seconds" ]; then
|
||||
echo -e "${GREEN}Service '$service_name' has reached ${secs}s uptime (required: ${min_seconds}s)${NC}"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
waited=$((waited + 1))
|
||||
done
|
||||
echo -e "${RED}Timeout: $service_name did not reach ${min_seconds}s uptime within ${timeout}s${NC}" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
function attach_pm2_process() {
|
||||
local service_name="$1"
|
||||
|
||||
@@ -1629,7 +1881,7 @@ case "${1:-help}" in
|
||||
delete_service "$2"
|
||||
;;
|
||||
list)
|
||||
list_services "$2"
|
||||
list_services "${2:-}"
|
||||
;;
|
||||
restore)
|
||||
restore_missing_services
|
||||
@@ -1670,6 +1922,52 @@ case "${1:-help}" in
|
||||
fi
|
||||
attach_to_service "$2"
|
||||
;;
|
||||
uptime-seconds)
|
||||
if [ $# -lt 2 ]; then
|
||||
echo -e "${RED}Error: Service name required for uptime-seconds command${NC}"
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
service_uptime_seconds "$2"
|
||||
;;
|
||||
wait-uptime)
|
||||
if [ $# -lt 3 ]; then
|
||||
echo -e "${RED}Error: Usage: $0 wait-uptime <service-name> <min-seconds> [timeout]${NC}"
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
wait_service_uptime "$2" "$3" "${4:-120}"
|
||||
;;
|
||||
is-running)
|
||||
if [ $# -lt 2 ]; then
|
||||
echo -e "${RED}Error: Service name required for is-running command${NC}"
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
if service_is_running "$2"; then
|
||||
echo -e "${GREEN}Service '$2' is running${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${YELLOW}Service '$2' is not running${NC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
send)
|
||||
if [ $# -lt 3 ]; then
|
||||
echo -e "${RED}Error: Not enough arguments for send command${NC}"
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
service_send_command "$2" "${@:3}"
|
||||
;;
|
||||
show-config)
|
||||
if [ $# -lt 2 ]; then
|
||||
echo -e "${RED}Error: Service name required for show-config command${NC}"
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
show_config "$2"
|
||||
;;
|
||||
help|--help|-h)
|
||||
print_help
|
||||
;;
|
||||
|
||||
@@ -143,6 +143,130 @@ teardown() {
|
||||
[[ "$output" =~ "on-failure|always" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: help lists health and console commands" {
|
||||
run "$SCRIPT_DIR/service-manager.sh" help
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "is-running <service-name>" ]]
|
||||
[[ "$output" =~ "uptime-seconds <service-name>" ]]
|
||||
[[ "$output" =~ "wait-uptime <service> <sec>" ]]
|
||||
[[ "$output" =~ "send <service-name>" ]]
|
||||
[[ "$output" =~ "show-config <service-name>" ]]
|
||||
}
|
||||
|
||||
@test "service-manager: pm2 uptime and wait-uptime work with mocked pm2" {
|
||||
command -v jq >/dev/null 2>&1 || skip "jq not installed"
|
||||
export AC_SERVICE_CONFIG_DIR="$TEST_DIR/services"
|
||||
mkdir -p "$AC_SERVICE_CONFIG_DIR"
|
||||
# Create registry with pm2 provider service
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/service_registry.json" << 'EOF'
|
||||
[
|
||||
{"name":"test-world","provider":"pm2","type":"service","bin_path":"/bin/worldserver","args":"","systemd_type":"--user","restart_policy":"always"}
|
||||
]
|
||||
EOF
|
||||
# Create minimal service config and run-engine config files required by 'send'
|
||||
echo "RUN_ENGINE_CONFIG_FILE=\"$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf\"" > "$AC_SERVICE_CONFIG_DIR/test-world.conf"
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf" << 'EOF'
|
||||
export SESSION_MANAGER="none"
|
||||
export SESSION_NAME="test-world"
|
||||
EOF
|
||||
# Mock pm2
|
||||
cat > "$TEST_DIR/bin/pm2" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
case "$1" in
|
||||
jlist)
|
||||
# Produce a JSON with uptime ~20 seconds
|
||||
if date +%s%N >/dev/null 2>&1; then
|
||||
nowms=$(( $(date +%s%N) / 1000000 ))
|
||||
else
|
||||
nowms=$(( $(date +%s) * 1000 ))
|
||||
fi
|
||||
up=$(( nowms - 20000 ))
|
||||
echo "[{\"name\":\"test-world\",\"pm2_env\":{\"status\":\"online\",\"pm_uptime\":$up}}]"
|
||||
;;
|
||||
id)
|
||||
echo "[1]"
|
||||
;;
|
||||
attach|send|list|describe|logs)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$TEST_DIR/bin/pm2"
|
||||
|
||||
run "$SCRIPT_DIR/service-manager.sh" uptime-seconds test-world
|
||||
debug_on_failure
|
||||
[ "$status" -eq 0 ]
|
||||
# Output should be a number >= 10
|
||||
[[ "$output" =~ ^[0-9]+$ ]]
|
||||
[ "$output" -ge 10 ]
|
||||
|
||||
run "$SCRIPT_DIR/service-manager.sh" wait-uptime test-world 10 5
|
||||
debug_on_failure
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "service-manager: send works under pm2 with mocked pm2" {
|
||||
command -v jq >/dev/null 2>&1 || skip "jq not installed"
|
||||
export AC_SERVICE_CONFIG_DIR="$TEST_DIR/services"
|
||||
mkdir -p "$AC_SERVICE_CONFIG_DIR"
|
||||
# Create registry and config as in previous test
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/service_registry.json" << 'EOF'
|
||||
[
|
||||
{"name":"test-world","provider":"pm2","type":"service","bin_path":"/bin/worldserver","args":"","systemd_type":"--user","restart_policy":"always"}
|
||||
]
|
||||
EOF
|
||||
echo "RUN_ENGINE_CONFIG_FILE=\"$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf\"" > "$AC_SERVICE_CONFIG_DIR/test-world.conf"
|
||||
cat > "$AC_SERVICE_CONFIG_DIR/test-world-run-engine.conf" << 'EOF'
|
||||
export SESSION_MANAGER="none"
|
||||
export SESSION_NAME="test-world"
|
||||
EOF
|
||||
# pm2 mock
|
||||
cat > "$TEST_DIR/bin/pm2" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
case "$1" in
|
||||
jlist)
|
||||
if date +%s%N >/dev/null 2>&1; then
|
||||
nowms=$(( $(date +%s%N) / 1000000 ))
|
||||
else
|
||||
nowms=$(( $(date +%s) * 1000 ))
|
||||
fi
|
||||
up=$(( nowms - 15000 ))
|
||||
echo "[{\"name\":\"test-world\",\"pm2_env\":{\"status\":\"online\",\"pm_uptime\":$up}}]"
|
||||
;;
|
||||
id)
|
||||
echo "[1]"
|
||||
;;
|
||||
send)
|
||||
# simulate success
|
||||
exit 0
|
||||
;;
|
||||
attach|list|describe|logs)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$TEST_DIR/bin/pm2"
|
||||
|
||||
run "$SCRIPT_DIR/service-manager.sh" send test-world "server info"
|
||||
debug_on_failure
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "service-manager: wait-uptime times out for unknown service" {
|
||||
command -v jq >/dev/null 2>&1 || skip "jq not installed"
|
||||
export AC_SERVICE_CONFIG_DIR="$TEST_DIR/services"
|
||||
mkdir -p "$AC_SERVICE_CONFIG_DIR"
|
||||
echo "[]" > "$AC_SERVICE_CONFIG_DIR/service_registry.json"
|
||||
run "$SCRIPT_DIR/service-manager.sh" wait-uptime unknown 2 1
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
# ===== EXAMPLE SCRIPTS TESTS =====
|
||||
|
||||
@test "examples: restarter-world should show configuration error" {
|
||||
|
||||
Vendored
+23
@@ -149,4 +149,27 @@ export CPUPROFILESIGNAL=${CPUPROFILESIGNAL:-12}
|
||||
# Other values for HEAPCHECK: minimal, normal (equivalent to "1"), strict, draconian
|
||||
#export HEAPCHECK=${HEAPCHECK:-normal}
|
||||
|
||||
##############################################
|
||||
#
|
||||
# MODULES LIST FILE (for installer `module` commands)
|
||||
#
|
||||
# Path to the file where the installer records installed modules
|
||||
# with their branch and commit. You can override this path by
|
||||
# setting the MODULES_LIST_FILE inside your config.sh or as an environment variable.
|
||||
# By default it points inside the repository conf folder.
|
||||
# Format of each line:
|
||||
# <module-name> <branch> <commit>
|
||||
# Lines starting with '#' and empty lines are ignored.
|
||||
export MODULES_LIST_FILE=${MODULES_LIST_FILE:-"$AC_PATH_ROOT/conf/modules.list"}
|
||||
|
||||
# Space/newline separated list of modules to exclude when using
|
||||
# 'module install --all' and 'module update --all'. Items can be specified
|
||||
# as simple names (e.g., mod-transmog), owner/name, or full URLs.
|
||||
# Example:
|
||||
# export MODULES_EXCLUDE_LIST="azerothcore/mod-transmog azerothcore/mod-autobalance"
|
||||
export MODULES_EXCLUDE_LIST=""
|
||||
|
||||
NO_COLOR=${NO_COLOR:-}
|
||||
FORCE_COLOR=${FORCE_COLOR:-}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-- DB update 2025_07_29_00 -> 2025_09_03_00
|
||||
-- Add petition_id column to petition table
|
||||
ALTER TABLE `petition` ADD COLUMN `petition_id` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `petitionguid`;
|
||||
-- Populate petition_id based on petitionguid
|
||||
UPDATE `petition` SET `petition_id` = CASE WHEN `petitionguid` <= 2147483647 THEN `petitionguid` ELSE `petitionguid` - 2147483648 END WHERE `petition_id` = 0;
|
||||
-- Add index on petition_id
|
||||
ALTER TABLE `petition` ADD INDEX `idx_petition_id` (`petition_id`);
|
||||
-- Add petition_id column to petition_sign table
|
||||
ALTER TABLE `petition_sign` ADD COLUMN `petition_id` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `petitionguid`;
|
||||
-- Populate petition_id in petition_sign from petition table
|
||||
UPDATE `petition_sign` AS `ps` JOIN `petition` AS `p` ON `p`.`petitionguid` = `ps`.`petitionguid` SET `ps`.`petition_id` = `p`.`petition_id` WHERE `ps`.`petition_id` = 0;
|
||||
-- Add index on petition_id and playerguid in petition_sign
|
||||
ALTER TABLE `petition_sign` ADD INDEX `idx_petition_id_player` (`petition_id`, `playerguid`);
|
||||
-- Update enchantments in item_instance with petition_id prefix
|
||||
UPDATE `item_instance` AS `ii` JOIN `petition` AS `p` ON `p`.`petitionguid` = `ii`.`guid` SET `ii`.`enchantments` = CONCAT(`p`.`petition_id`, SUBSTRING(`ii`.`enchantments`, LOCATE(' ', `ii`.`enchantments`))) WHERE `ii`.`enchantments` IS NOT NULL AND `ii`.`enchantments` <> '';
|
||||
@@ -0,0 +1,14 @@
|
||||
-- DB update 2025_08_30_03 -> 2025_09_02_00
|
||||
|
||||
-- Morbid Carcass, Vault Geist, Rabid Cannibal, Death Knight Master
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (29719, 29720, 29722, 29738));
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (29719, 29720, 29722, 29738));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(29719, 0, 0, 0, 0, 0, 100, 0, 8000, 12000, 8000, 12000, 0, 0, 11, 40504, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Morbid Carcass - In Combat - Cast \'Cleave\''),
|
||||
(29719, 0, 1, 0, 9, 0, 100, 0, 8000, 12000, 8000, 12000, 8, 40, 11, 50335, 0, 0, 0, 0, 0, 5, 40, 0, 0, 0, 0, 0, 0, 0, 'Morbid Carcass - Within 8-40 Range - Cast \'Scourge Hook\''),
|
||||
(29720, 0, 0, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 97, 20, 10, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Vault Geist - On Aggro - Jump To Pos'),
|
||||
(29720, 0, 1, 0, 0, 0, 100, 0, 4000, 6000, 18000, 24000, 0, 0, 11, 36590, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Vault Geist - In Combat - Cast \'Rip\''),
|
||||
(29738, 0, 0, 0, 0, 0, 100, 0, 0, 0, 20000, 24000, 0, 0, 11, 50688, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Master - In Combat - Cast \'Plague Strike\''),
|
||||
(29738, 0, 1, 0, 60, 0, 100, 0, 0, 0, 30000, 30000, 0, 0, 11, 50689, 32, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Death Knight Master - On Update - Cast \'Blood Presence\''),
|
||||
(29722, 0, 0, 0, 0, 0, 100, 0, 2000, 4000, 18000, 22000, 0, 0, 11, 30639, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Rabid Cannibal - In Combat - Cast \'Carnivorous Bite\'');
|
||||
@@ -0,0 +1,4 @@
|
||||
-- DB update 2025_09_02_00 -> 2025_09_02_01
|
||||
DELETE FROM `creature` WHERE `guid` = 1741 AND `id1` = 14724;
|
||||
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`, `CreateObject`, `Comment`) VALUES
|
||||
(1741, 14724, 0, 0, 0, 0, 0, 1, 1, 0, -4823.649, -1299.3605, 501.95117, 0.959931075572967529, 300, 0, 0, 1220, 0, 0, 0, 0, 0, '', 45613, 1, NULL);
|
||||
@@ -0,0 +1,5 @@
|
||||
-- DB update 2025_09_02_01 -> 2025_09_02_02
|
||||
--
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28851) AND (`source_type` = 0) AND (`id` IN (2));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28851, 0, 2, 0, 28, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 3000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Enraged Mammoth - On Passenger Removed - Despawn In 3000 ms');
|
||||
@@ -0,0 +1,151 @@
|
||||
-- DB update 2025_09_02_02 -> 2025_09_03_00
|
||||
-- Update gameobject 'various doodad' with sniffed values
|
||||
-- updated spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (193692, 193766, 193765, 193764, 193763, 193762, 193761, 193760, 193759, 193758, 193757, 193756, 193755, 193754, 193753, 193752, 193751, 193750, 193749, 193748, 193747, 193746, 193745, 193744, 193743, 193742, 193741, 193740, 193739, 193738, 193737, 193736, 193735, 193734, 193733, 193732, 193731, 193730, 193729, 193728, 193727, 193726, 193725, 193724, 193723, 193722, 193721, 193720, 193719, 193718, 193717, 193716, 193715, 193714, 193713, 193712, 193711, 193710, 193709, 193708, 193707, 193706, 193705, 193704, 193703, 193702, 193701, 193700, 193699, 193698, 193697, 193696, 193693, 193691, 193678, 193677, 193676, 193674, 193669, 193668, 193666, 193665, 193664, 193663, 193659, 193658, 193657, 193662, 193660, 193661, 193654, 193652, 193651, 193649, 193650, 193671, 193670, 193645, 193644, 193643, 193642, 193637, 193632, 193631, 193630, 193653, 193636, 193635, 193634, 193633, 193681, 193680)) AND (`guid` IN (255513, 268696, 268697, 268698, 268699, 268700, 268701, 268702, 268703, 268704, 268705, 268706, 268707, 268708, 268709, 268710, 268711, 268712, 268713, 268714, 268715, 268716, 268717, 268718, 268719, 268720, 268721, 268722, 268723, 268724, 268725, 268726, 268727, 268728, 268729, 268730, 268731, 268732, 268733, 268734, 268735, 268736, 268737, 268738, 268739, 268740, 268741, 268742, 268743, 268744, 268745, 268746, 268747, 268748, 268749, 268750, 268751, 268752, 268753, 268754, 268755, 268756, 268757, 268758, 268759, 268760, 268761, 268762, 268763, 268764, 268765, 268766, 268772, 268773, 268774, 268775, 268779, 268780, 268781, 268782, 268783, 268784, 268785, 268786, 268790, 268791, 268792, 268793, 268794, 268795, 268799, 268800, 268807, 268808, 268809, 268815, 268816, 268818, 268819, 268820, 268821, 268822, 268825, 268826, 268827, 268829, 268832, 268833, 268834, 268835, 268839, 268840));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(255513, 193692, 571, 0, 0, 1, 1, 7882.8623046875, 2043.8250732421875, 600.73297119140625, 4.665524959564208984, 0.187406539916992187, -0.31766891479492187, -0.64971733093261718, 0.66470491886138916, 120, 255, 1, "", 46368, NULL),
|
||||
(268696, 193766, 571, 0, 0, 1, 1, 7637.41064453125, 2072.35791015625, 600.27178955078125, 1.248236894607543945, 0.51220560073852539, 0.357756614685058593, 0.46212005615234375, 0.629365265369415283, 120, 255, 1, "", 50664, NULL),
|
||||
(268697, 193765, 571, 0, 0, 1, 1, 7635.556640625, 2046.7196044921875, 601.6680908203125, 1.269469738006591796, -0.03150653839111328, 0.077538490295410156, 0.589531898498535156, 0.803397297859191894, 120, 255, 1, "", 50664, NULL),
|
||||
(268698, 193764, 571, 0, 0, 1, 1, 7625.869140625, 2060.052978515625, 604.26983642578125, 0.078540004789829254, 0, 0, 0.039259910583496093, 0.999229073524475097, 120, 255, 1, "", 50664, NULL),
|
||||
(268699, 193763, 571, 0, 0, 1, 1, 7625.7724609375, 2060.06494140625, 600.8868408203125, 0.063891783356666564, 0, 0, 0.031940460205078125, 0.999489784240722656, 120, 255, 1, "", 50664, NULL),
|
||||
(268700, 193762, 571, 0, 0, 1, 1, 7625.6640625, 2060.03564453125, 604.1954345703125, 3.22885894775390625, 0, 0, -0.99904823303222656, 0.043619260191917419, 120, 255, 1, "", 50664, NULL),
|
||||
(268701, 193761, 571, 0, 0, 1, 1, 7629.734375, 2062.71484375, 600.2579345703125, 2.95832991600036621, 0, 0, 0.995804786682128906, 0.091503240168094635, 120, 255, 1, "", 50664, NULL),
|
||||
(268702, 193760, 571, 0, 0, 1, 1, 7630.5419921875, 2062.549560546875, 600.24835205078125, 4.249876976013183593, 0, 0, -0.85035228729248046, 0.526213824748992919, 120, 255, 1, "", 50664, NULL),
|
||||
(268703, 193759, 571, 0, 0, 1, 1, 7629.98193359375, 2061.771240234375, 600.24383544921875, 3.351046562194824218, 0, 0, -0.99452114105224609, 0.104535527527332305, 120, 255, 1, "", 50664, NULL),
|
||||
(268704, 193758, 571, 0, 0, 1, 1, 7628.8798828125, 2060.107666015625, 600.49481201171875, 4.721115589141845703, 0, 0, -0.70401477813720703, 0.71018528938293457, 120, 255, 1, "", 50664, NULL),
|
||||
(268705, 193757, 571, 0, 0, 1, 1, 7628.60400390625, 2060.201171875, 599.6319580078125, 4.616395950317382812, 0, 0, -0.74021816253662109, 0.672366797924041748, 120, 255, 1, "", 50664, NULL),
|
||||
(268706, 193756, 571, 0, 0, 1, 1, 7628.60400390625, 2060.201171875, 598.53387451171875, 6.143558979034423828, 0, 0, -0.06975650787353515, 0.997564077377319335, 120, 255, 1, "", 50664, NULL),
|
||||
(268707, 193755, 571, 0, 0, 1, 1, 7617.7353515625, 2050.1357421875, 600.6690673828125, 5.480334281921386718, 0, 0, -0.39073085784912109, 0.920504987239837646, 120, 255, 1, "", 50664, NULL),
|
||||
(268708, 193754, 571, 0, 0, 1, 1, 7630.58837890625, 2060.197998046875, 600.16461181640625, 0.017452461645007133, 0, 0, 0.008726119995117187, 0.999961912631988525, 120, 255, 1, "", 50664, NULL),
|
||||
(268709, 193753, 571, 0, 0, 1, 1, 7615.00048828125, 2053.274658203125, 601.31890869140625, 4.834563255310058593, -0.07124805450439453, -0.11837959289550781, -0.65368366241455078, 0.744048118591308593, 120, 255, 1, "", 50664, NULL),
|
||||
(268710, 193752, 571, 0, 0, 1, 1, 7614.63818359375, 2053.234130859375, 601.3212890625, 4.1538848876953125, 0, 0, -0.8746194839477539, 0.484810054302215576, 120, 255, 1, "", 50664, NULL),
|
||||
(268711, 193751, 571, 0, 0, 1, 1, 7614.73583984375, 2052.607177734375, 601.3494873046875, 5.52397012710571289, 0.025708198547363281, 0.1858978271484375, -0.35620498657226562, 0.915368258953094482, 120, 255, 1, "", 50664, NULL),
|
||||
(268712, 193750, 571, 0, 0, 1, 1, 7614.7763671875, 2052.47705078125, 600.12860107421875, 0.759216904640197753, 0, 0, 0.370556831359863281, 0.928809821605682373, 120, 255, 1, "", 50664, NULL),
|
||||
(268713, 193749, 571, 0, 0, 1, 1, 7621.33642578125, 2045.822998046875, 600.0079345703125, 5.864306926727294921, 0, 0, -0.20791149139404296, 0.978147625923156738, 120, 255, 1, "", 50664, NULL),
|
||||
(268714, 193748, 571, 0, 0, 1, 1, 7621.1689453125, 2048.1103515625, 600.03460693359375, 3.194002151489257812, 0, 0, -0.99965667724609375, 0.026201646775007247, 120, 255, 1, "", 50664, NULL),
|
||||
(268715, 193747, 571, 0, 0, 1, 1, 7619.73583984375, 2046.9991455078125, 600.139892578125, 4.127707481384277343, 0, 0, -0.880889892578125, 0.473321229219436645, 120, 255, 1, "", 50664, NULL),
|
||||
(268716, 193746, 571, 0, 0, 1, 1, 7611.34130859375, 2059.42138671875, 600.2303466796875, 0.680676698684692382, 0, 0, 0.333806037902832031, 0.942641794681549072, 120, 255, 1, "", 50664, NULL),
|
||||
(268717, 193745, 571, 0, 0, 1, 1, 7611.443359375, 2061.458740234375, 600.2303466796875, 2.076939344406127929, 0, 0, 0.861628532409667968, 0.50753939151763916, 120, 255, 1, "", 50664, NULL),
|
||||
(268718, 193744, 571, 0, 0, 1, 1, 7611.46630859375, 2060.24267578125, 601.098876953125, 1.474833250045776367, 0.740206718444824218, 0.672366142272949218, 0.004041671752929687, 0.001196039956994354, 120, 255, 1, "", 50664, NULL),
|
||||
(268719, 193743, 571, 0, 0, 1, 1, 7629.513671875, 2043.40283203125, 600.21649169921875, 2.303830623626708984, 0, 0, 0.913544654846191406, 0.406738430261611938, 120, 255, 1, "", 50664, NULL),
|
||||
(268720, 193742, 571, 0, 0, 1, 1, 7627.474609375, 2043.3980712890625, 600.215576171875, 3.70009779930114746, 0, 0, -0.96126174926757812, 0.275637149810791015, 120, 255, 1, "", 50664, NULL),
|
||||
(268721, 193741, 571, 0, 0, 1, 1, 7628.4716796875, 2043.3489990234375, 601.08172607421875, 3.097992658615112304, -0.02180719375610351, -0.99975299835205078, -0.00331974029541015, 0.002718634903430938, 120, 255, 1, "", 50664, NULL),
|
||||
(268722, 193740, 571, 0, 0, 1, 1, 7620.10205078125, 2074.37548828125, 601.4208984375, 6.012660503387451171, 0, 0, -0.13485050201416015, 0.990865945816040039, 120, 255, 1, "", 50664, NULL),
|
||||
(268723, 193739, 571, 0, 0, 1, 1, 7621.29052734375, 2074.291748046875, 601.4190673828125, 0.157077088952064514, 0, 0, 0.078457832336425781, 0.996917426586151123, 120, 255, 1, "", 50664, NULL),
|
||||
(268724, 193738, 571, 0, 0, 1, 1, 7621.4072265625, 2072.64208984375, 601.4334716796875, 1.954769015312194824, 0, 0, 0.829037666320800781, 0.559192776679992675, 120, 255, 1, "", 50664, NULL),
|
||||
(268725, 193737, 571, 0, 0, 1, 1, 7620.9501953125, 2073.94580078125, 600.21722412109375, 5.253442287445068359, 0, 0, -0.49242305755615234, 0.870355963706970214, 120, 255, 1, "", 50664, NULL),
|
||||
(268726, 193736, 571, 0, 0, 1, 1, 7618.22607421875, 2070.371337890625, 600.55718994140625, 3.892086982727050781, 0, 0, -0.93041706085205078, 0.366502493619918823, 120, 255, 1, "", 50664, NULL),
|
||||
(268727, 193735, 571, 0, 0, 1, 1, 7613.96484375, 2068.400634765625, 600.26336669921875, 5.410520076751708984, 0.18164825439453125, -0.05159950256347656, -0.42017078399658203, 0.887579798698425292, 120, 255, 1, "", 50664, NULL),
|
||||
(268728, 193734, 571, 0, 0, 1, 1, 7614.1796875, 2069.150146484375, 600.2694091796875, 2.277705669403076171, 0.4829254150390625, 0.523255348205566406, -0.48152923583984375, 0.510995566844940185, 120, 255, 1, "", 50664, NULL),
|
||||
(268729, 193733, 571, 0, 0, 1, 1, 7614.11865234375, 2068.62841796875, 600.2442626953125, 2.862335443496704101, 0, 0, 0.990267753601074218, 0.139175355434417724, 120, 255, 1, "", 50664, NULL),
|
||||
(268730, 193732, 571, 0, 0, 1, 1, 7613.57958984375, 2067.849365234375, 600.361083984375, 0.758936166763305664, 0.710488319396972656, 0.047131538391113281, -0.70103359222412109, 0.039202630519866943, 120, 255, 1, "", 50664, NULL),
|
||||
(268731, 193731, 571, 0, 0, 1, 1, 7613.70166015625, 2066.873779296875, 600.338623046875, 5.733424663543701171, -0.62461566925048828, 0.353822708129882812, 0.599942207336425781, 0.353177070617675781, 120, 255, 1, "", 50664, NULL),
|
||||
(268732, 193730, 571, 0, 0, 1, 1, 7613.63330078125, 2067.5244140625, 600.229736328125, 2.809975385665893554, 0, 0, 0.986285209655761718, 0.165049895644187927, 120, 255, 1, "", 50664, NULL),
|
||||
(268733, 193729, 571, 0, 0, 1, 1, 7627.837890625, 2076.871337890625, 600.24664306640625, 5.471607208251953125, 0, 0, -0.39474391937255859, 0.918791174888610839, 120, 255, 1, "", 50664, NULL),
|
||||
(268734, 193728, 571, 0, 0, 1, 1, 7628.87841796875, 2076.95263671875, 601.11578369140625, 6.265766620635986328, 0.999953269958496093, -0.00871753692626953, 0.00246429443359375, 0.00337409065105021, 120, 255, 1, "", 50664, NULL),
|
||||
(268735, 193727, 571, 0, 0, 1, 1, 7629.87646484375, 2076.929931640625, 600.24664306640625, 0.584683895111083984, 0, 0, 0.288195610046386718, 0.957571566104888916, 120, 255, 1, "", 50664, NULL),
|
||||
(268736, 193726, 571, 0, 0, 1, 1, 7644.1845703125, 2052.05908203125, 600.23858642578125, 2.085667610168457031, 0, 0, 0.863835334777832031, 0.503774285316467285, 120, 255, 1, "", 50664, NULL),
|
||||
(268737, 193725, 571, 0, 0, 1, 1, 7644.37548828125, 2052.462158203125, 600.2384033203125, 4.598945140838623046, 0, 0, -0.74605655670166015, 0.665882587432861328, 120, 255, 1, "", 50664, NULL),
|
||||
(268738, 193724, 571, 0, 0, 1, 1, 7644.04248046875, 2052.38671875, 600.23297119140625, 0.706856131553649902, 0.038586616516113281, -0.14088153839111328, 0.340669631958007812, 0.928766727447509765, 120, 255, 1, "", 50664, NULL),
|
||||
(268739, 193723, 571, 0, 0, 1, 1, 7636.345703125, 2046.3046875, 601.35015869140625, 0.575957715511322021, -0.09489917755126953, 0.161904335021972656, 0.286963462829589843, 0.939379096031188964, 120, 255, 1, "", 50664, NULL),
|
||||
(268740, 193722, 571, 0, 0, 1, 1, 7636.70751953125, 2047.2916259765625, 601.309326171875, 3.010666131973266601, 0, 0, 0.997858047485351562, 0.065416477620601654, 120, 255, 1, "", 50664, NULL),
|
||||
(268741, 193721, 571, 0, 0, 1, 1, 7636.48095703125, 2046.31298828125, 600.129638671875, 2.094393253326416015, 0, 0, 0.866024971008300781, 0.50000077486038208, 120, 255, 1, "", 50664, NULL),
|
||||
(268742, 193720, 571, 0, 0, 1, 1, 7639.40576171875, 2049.9814453125, 600.68109130859375, 0.750488698482513427, 0, 0, 0.366499900817871093, 0.930418074131011962, 120, 255, 1, "", 50664, NULL),
|
||||
(268743, 193719, 571, 0, 0, 1, 1, 7642.1875, 2066.251953125, 601.51141357421875, 4.319693565368652343, 0.329238414764404296, -0.62578010559082031, -0.54365253448486328, 0.452154040336608886, 120, 255, 1, "", 50664, NULL),
|
||||
(268744, 193718, 571, 0, 0, 1, 1, 7641.9541015625, 2051.512939453125, 600.240234375, 2.923415660858154296, 0, 0, 0.994055747985839843, 0.108872212469577789, 120, 255, 1, "", 50664, NULL),
|
||||
(268745, 193717, 571, 0, 0, 1, 1, 7642.1845703125, 2051.5986328125, 600.46063232421875, 5.174901962280273437, 0, 0, -0.52621364593505859, 0.850352406501770019, 120, 255, 1, "", 50664, NULL),
|
||||
(268746, 193716, 571, 0, 0, 1, 1, 7642.3935546875, 2051.588134765625, 600.239990234375, 3.63901376724243164, 0, 0, -0.96923065185546875, 0.246154293417930603, 120, 255, 1, "", 50664, NULL),
|
||||
(268747, 193715, 571, 0, 0, 1, 1, 7642.1396484375, 2051.818115234375, 600.2618408203125, 5.349435329437255859, 0, 0, -0.45009803771972656, 0.892979145050048828, 120, 255, 1, "", 50664, NULL),
|
||||
(268748, 193714, 571, 0, 0, 1, 1, 7642.29345703125, 2051.72412109375, 600.26397705078125, 4.860742568969726562, 0, 0, -0.65275955200195312, 0.757565200328826904, 120, 255, 1, "", 50664, NULL),
|
||||
(268749, 193713, 571, 0, 0, 1, 1, 7642.54052734375, 2051.8837890625, 600.25, 1.844759345054626464, 0.050289154052734375, 0.201838493347167968, 0.769841194152832031, 0.603387713432312011, 120, 255, 1, "", 50664, NULL),
|
||||
(268750, 193712, 571, 0, 0, 1, 1, 7642.7177734375, 2051.58984375, 600.26141357421875, 1.710421562194824218, 0, 0, 0.754709243774414062, 0.656059443950653076, 120, 255, 1, "", 50664, NULL),
|
||||
(268751, 193711, 571, 0, 0, 1, 1, 7645.83544921875, 2061.108642578125, 600.2529296875, 3.848450660705566406, 0, 0, -0.93819141387939453, 0.346116840839385986, 120, 255, 1, "", 50664, NULL),
|
||||
(268752, 193710, 571, 0, 0, 1, 1, 7645.78662109375, 2059.0693359375, 600.252685546875, 5.244716167449951171, 0, 0, -0.4962158203125, 0.86819922924041748, 120, 255, 1, "", 50664, NULL),
|
||||
(268753, 193709, 571, 0, 0, 1, 1, 7645.86181640625, 2060.064697265625, 601.121826171875, 4.642610549926757812, 0.681998252868652343, -0.73134136199951171, -0.00068855285644531, 0.004207443445920944, 120, 255, 1, "", 50664, NULL),
|
||||
(268754, 193708, 571, 0, 0, 1, 1, 7636.177734375, 2073.49462890625, 601.4434814453125, 3.420847892761230468, -0.21741914749145507, -0.08422660827636718, -0.96116828918457031, 0.1476154625415802, 120, 255, 1, "", 50664, NULL),
|
||||
(268755, 193707, 571, 0, 0, 1, 1, 7639.47998046875, 2069.831787109375, 600.65679931640625, 2.347463846206665039, 0, 0, 0.922200202941894531, 0.386712819337844848, 120, 255, 1, "", 50664, NULL),
|
||||
(268756, 193706, 571, 0, 0, 1, 1, 7642.2158203125, 2066.698486328125, 601.4727783203125, 5.715955257415771484, 0, 0, -0.27982807159423828, 0.960050106048583984, 120, 255, 1, "", 50664, NULL),
|
||||
(268757, 193705, 571, 0, 0, 1, 1, 7641.5390625, 2066.837890625, 601.4727783203125, 0.401424884796142578, 0, 0, 0.199367523193359375, 0.979924798011779785, 120, 255, 1, "", 50664, NULL),
|
||||
(268758, 193704, 571, 0, 0, 1, 1, 7642.36376953125, 2067.4638671875, 601.4591064453125, 3.395873546600341796, 0.056763648986816406, 0.014508247375488281, -0.99017143249511718, 0.126995846629142761, 120, 255, 1, "", 50664, NULL),
|
||||
(268759, 193703, 571, 0, 0, 1, 1, 7642.8466796875, 2067.182861328125, 601.47882080078125, 2.1816558837890625, -0.18238639831542968, 0.044202804565429687, 0.875073432922363281, 0.446125298738479614, 120, 255, 1, "", 50664, NULL),
|
||||
(268760, 193702, 571, 0, 0, 1, 1, 7643.08251953125, 2067.653564453125, 601.462158203125, 3.307400941848754882, -0.08287525177001953, 0.042493820190429687, -0.99254989624023437, 0.078553743660449981, 120, 255, 1, "", 50664, NULL),
|
||||
(268761, 193701, 571, 0, 0, 1, 1, 7642.833984375, 2067.318359375, 600.256591796875, 3.70009779930114746, 0, 0, -0.96126174926757812, 0.275637149810791015, 120, 255, 1, "", 50664, NULL),
|
||||
(268762, 193700, 571, 0, 0, 1, 1, 7638.7451171875, 2073.489501953125, 600.251220703125, 1.247907638549804687, 0, 0, 0.584248542785644531, 0.811574757099151611, 120, 255, 1, "", 50664, NULL),
|
||||
(268763, 193699, 571, 0, 0, 1, 1, 7637.20556640625, 2073.30859375, 601.41949462890625, 4.347476005554199218, 0.06531381607055664, 0.67337799072265625, -0.33799266815185546, 0.654260754585266113, 120, 255, 1, "", 50664, NULL),
|
||||
(268764, 193698, 571, 0, 0, 1, 1, 7636.033203125, 2073.449951171875, 600.2333984375, 4.354224681854248046, -0.00527000427246093, -0.02503776550292968, -0.82129764556884765, 0.569925904273986816, 120, 255, 1, "", 50664, NULL),
|
||||
(268765, 193697, 571, 0, 0, 1, 1, 7635.75830078125, 2074.88037109375, 600.2703857421875, 3.333590030670166015, 0, 0, -0.99539566040039062, 0.095851235091686248, 120, 255, 1, "", 50664, NULL),
|
||||
(268766, 193696, 571, 0, 0, 1, 1, 7637.640625, 2074.039306640625, 600.2724609375, 2.609261274337768554, 0, 0, 0.964786529541015625, 0.263034075498580932, 120, 255, 1, "", 50664, NULL),
|
||||
(268772, 193693, 571, 0, 0, 1, 1, 7892.458984375, 2073.525146484375, 601.7738037109375, 5.521906852722167968, -0.67214488983154296, 0.21199798583984375, -0.31161308288574218, 0.637318909168243408, 120, 255, 1, "", 46368, NULL),
|
||||
(268773, 193691, 571, 0, 0, 1, 1, 7891.21435546875, 2057.974853515625, 604.2218017578125, 3.124123096466064453, 0, 0, 0.99996185302734375, 0.008734640665352344, 120, 255, 1, "", 46368, NULL),
|
||||
(268774, 193678, 571, 0, 0, 1, 1, 7891.45458984375, 2058.0087890625, 600.86529541015625, 0.011531894095242023, 0, 0, 0.005765914916992187, 0.999983370304107666, 120, 255, 1, "", 46368, NULL),
|
||||
(268775, 193677, 571, 0, 0, 1, 1, 7891.65234375, 2058.012939453125, 604.251953125, 6.265733242034912109, 0, 0, -0.00872611999511718, 0.999961912631988525, 120, 255, 1, "", 46368, NULL),
|
||||
(268779, 193676, 571, 0, 0, 1, 1, 7888.271484375, 2058.06640625, 600.46380615234375, 1.579522013664245605, 0, 0, 0.710185050964355468, 0.704015016555786132, 120, 255, 1, "", 46368, NULL),
|
||||
(268780, 193674, 571, 0, 0, 1, 1, 7888.546875, 2057.972900390625, 598.50286865234375, 3.001946926116943359, 0, 0, 0.997563362121582031, 0.069766148924827575, 120, 255, 1, "", 46368, NULL),
|
||||
(268781, 193669, 571, 0, 0, 1, 1, 7877.67138671875, 2048.341796875, 600.62579345703125, 5.489060401916503906, 0, 0, -0.38671112060546875, 0.922200918197631835, 120, 255, 1, "", 46368, NULL),
|
||||
(268782, 193668, 571, 0, 0, 1, 1, 7886.5634765625, 2057.9765625, 600.13427734375, 3.159062385559082031, 0, 0, -0.99996185302734375, 0.008734640665352344, 120, 255, 1, "", 46368, NULL),
|
||||
(268783, 193666, 571, 0, 0, 1, 1, 7874.21435546875, 2051.378173828125, 601.40032958984375, 5.759586811065673828, 0.030743122100830078, 0.030928611755371093, -0.25936603546142578, 0.964794039726257324, 120, 255, 1, "", 46368, NULL),
|
||||
(268784, 193665, 571, 0, 0, 1, 1, 7874.3037109375, 2050.991455078125, 601.44683837890625, 5.32325601577758789, 0.044202804565429687, 0.182386398315429687, -0.4461221694946289, 0.875075042247772216, 120, 255, 1, "", 46368, NULL),
|
||||
(268785, 193664, 571, 0, 0, 1, 1, 7874.00244140625, 2050.78515625, 601.4483642578125, 4.642575740814208984, -0.07862043380737304, -0.12896251678466796, -0.71886634826660156, 0.678541600704193115, 120, 255, 1, "", 46368, NULL),
|
||||
(268786, 193663, 571, 0, 0, 1, 1, 7874.31689453125, 2050.85595703125, 600.2255859375, 0.558503925800323486, 0, 0, 0.275636672973632812, 0.961261868476867675, 120, 255, 1, "", 46368, NULL),
|
||||
(268790, 193659, 571, 0, 0, 1, 1, 7871.31591796875, 2057.065185546875, 600.2220458984375, 0.706856250762939453, 0, 0, 0.346116065979003906, 0.938191711902618408, 120, 255, 1, "", 46368, NULL),
|
||||
(268791, 193658, 571, 0, 0, 1, 1, 7871.3642578125, 2059.104248046875, 600.22412109375, 2.103119850158691406, 0, 0, 0.868198394775390625, 0.496217250823974609, 120, 255, 1, "", 46368, NULL),
|
||||
(268792, 193657, 571, 0, 0, 1, 1, 7871.28857421875, 2058.10986328125, 601.09088134765625, 1.501015067100524902, 0.731341838836669921, 0.681998252868652343, 0.00405120849609375, 0.001035800902172923, 120, 255, 1, "", 46368, NULL),
|
||||
(268793, 193662, 571, 0, 0, 1, 1, 7889.31298828125, 2041.3023681640625, 600.216796875, 2.33001255989074707, 0, 0, 0.918790817260742187, 0.394744753837585449, 120, 255, 1, "", 46368, NULL),
|
||||
(268794, 193660, 571, 0, 0, 1, 1, 7887.27392578125, 2041.244140625, 600.21728515625, 3.72628021240234375, 0, 0, -0.95757102966308593, 0.288197338581085205, 120, 255, 1, "", 46368, NULL),
|
||||
(268795, 193661, 571, 0, 0, 1, 1, 7888.27294921875, 2041.2213134765625, 601.0849609375, 3.12417149543762207, -0.00871896743774414, -0.99995326995849609, -0.00328731536865234, 0.002583741443231701, 120, 255, 1, "", 46368, NULL),
|
||||
(268799, 193654, 571, 0, 0, 1, 1, 7880.66943359375, 2071.861328125, 600.09869384765625, 5.235987663269042968, 0, 0, -0.5, 0.866025388240814208, 120, 255, 1, "", 46368, NULL),
|
||||
(268800, 193652, 571, 0, 0, 1, 1, 7877.7451171875, 2068.192626953125, 600.65087890625, 3.892086982727050781, 0, 0, -0.93041706085205078, 0.366502493619918823, 120, 255, 1, "", 46368, NULL),
|
||||
(268807, 193651, 571, 0, 0, 1, 1, 7887.63720703125, 2074.77099609375, 600.18682861328125, 5.445429801940917968, 0, 0, -0.40673542022705078, 0.91354602575302124, 120, 255, 1, "", 46368, NULL),
|
||||
(268808, 193649, 571, 0, 0, 1, 1, 7888.68017578125, 2074.82470703125, 601.05072021484375, 6.239586830139160156, 0.999753475189208984, -0.0218057632446289, 0.002421379089355468, 0.00341796875, 120, 255, 1, "", 46368, NULL),
|
||||
(268809, 193650, 571, 0, 0, 1, 1, 7889.67724609375, 2074.776123046875, 600.18499755859375, 0.558503925800323486, 0, 0, 0.275636672973632812, 0.961261868476867675, 120, 255, 1, "", 46368, NULL),
|
||||
(268815, 193671, 571, 0, 0, 1, 1, 7896.20068359375, 2044.22802734375, 600.18603515625, 2.111847877502441406, 0, 0, 0.870355606079101562, 0.492423713207244873, 120, 255, 1, "", 46368, NULL),
|
||||
(268816, 193670, 571, 0, 0, 1, 1, 7898.9248046875, 2047.802734375, 600.52520751953125, 0.750488698482513427, 0, 0, 0.366499900817871093, 0.930418074131011962, 120, 255, 1, "", 46368, NULL),
|
||||
(268818, 193645, 571, 0, 0, 1, 1, 7903.21923828125, 2050.816650390625, 600.10931396484375, 1.256635904312133789, 0, 0, 0.587784767150878906, 0.809017360210418701, 120, 255, 1, "", 46368, NULL),
|
||||
(268819, 193644, 571, 0, 0, 1, 1, 7903.2822265625, 2050.578857421875, 600.28997802734375, 3.508116960525512695, 0, 0, -0.98325443267822265, 0.182238012552261352, 120, 255, 1, "", 46368, NULL),
|
||||
(268820, 193643, 571, 0, 0, 1, 1, 7903.251953125, 2050.372314453125, 599.96185302734375, 1.972219824790954589, 0, 0, 0.83388519287109375, 0.55193793773651123, 120, 255, 1, "", 46368, NULL),
|
||||
(268821, 193642, 571, 0, 0, 1, 1, 7903.5048828125, 2050.60205078125, 600.26007080078125, 3.682650327682495117, 0, 0, -0.96362972259521484, 0.26724100112915039, 120, 255, 1, "", 46368, NULL),
|
||||
(268822, 193637, 571, 0, 0, 1, 1, 7902.48046875, 2048.71728515625, 600.2122802734375, 5.166173934936523437, 0, 0, -0.52991962432861328, 0.848047912120819091, 120, 255, 1, "", 46368, NULL),
|
||||
(268825, 193632, 571, 0, 0, 1, 1, 7905.810546875, 2058.752685546875, 600.1993408203125, 3.822272777557373046, 0, 0, -0.94264125823974609, 0.333807557821273803, 120, 255, 1, "", 46368, NULL),
|
||||
(268826, 193631, 571, 0, 0, 1, 1, 7905.70849609375, 2056.715576171875, 600.1993408203125, 5.218533515930175781, 0, 0, -0.5075387954711914, 0.861628890037536621, 120, 255, 1, "", 46368, NULL),
|
||||
(268827, 193630, 571, 0, 0, 1, 1, 7905.68505859375, 2057.931640625, 601.06793212890625, 4.616430282592773437, 0.672366619110107421, -0.74020576477050781, -0.00074100494384765, 0.00424973014742136, 120, 255, 1, "", 46368, NULL),
|
||||
(268829, 193653, 571, 0, 0, 1, 1, 7899.41552734375, 2068.0380859375, 600.639404296875, 2.338739633560180664, 0, 0, 0.920504570007324218, 0.3907318115234375, 120, 255, 1, "", 46368, NULL),
|
||||
(268832, 193636, 571, 0, 0, 1, 1, 7902.55126953125, 2066.074951171875, 601.30126953125, 3.508113622665405273, -0.08671522140502929, 0.033976554870605468, -0.97968578338623046, 0.177600175142288208, 120, 255, 1, "", 46368, NULL),
|
||||
(268833, 193635, 571, 0, 0, 1, 1, 7902.6494140625, 2066.373046875, 601.30133056640625, 4.389505863189697265, -0.07650041580200195, -0.06483268737792968, -0.80701732635498046, 0.581951439380645751, 120, 255, 1, "", 46368, NULL),
|
||||
(268834, 193634, 571, 0, 0, 1, 1, 7902.3046875, 2066.493408203125, 601.3028564453125, 3.708826541900634765, 0, 0, -0.96004962921142578, 0.279829770326614379, 120, 255, 1, "", 46368, NULL),
|
||||
(268835, 193633, 571, 0, 0, 1, 1, 7902.375, 2065.69677734375, 600.09716796875, 3.900813102722167968, 0, 0, -0.92880916595458984, 0.370558410882949829, 120, 255, 1, "", 46368, NULL),
|
||||
(268839, 193681, 571, 0, 0, 1, 1, 7895.1708984375, 2072.284423828125, 600.2469482421875, 1.517560839653015136, 0, 0, 0.688036918640136718, 0.725675702095031738, 120, 255, 1, "", 46368, NULL),
|
||||
(268840, 193680, 571, 0, 0, 1, 1, 7893.27880859375, 2073.20849609375, 600.249755859375, 0.280996710062026977, 0, 0, 0.140036582946777343, 0.990146338939666748, 120, 255, 1, "", 46368, NULL);
|
||||
|
||||
-- new spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (193638, 193639, 193640, 193641, 193646, 193647, 193648, 193655, 193656, 193667, 193672, 193673, 193675, 193679, 193682, 193683, 193684, 193685, 193686, 193687, 193688, 193689, 193690, 193694, 193695)) AND (`guid` IN (2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(2077, 193638, 571, 0, 0, 1, 1, 7902.05078125, 2048.413330078125, 600.2374267578125, 4.581534385681152343, -0.28159475326538085, 0.654002189636230468, 0.270960807800292968, 0.647738933563232421, 120, 255, 1, "", 46368, NULL),
|
||||
(2078, 193639, 571, 0, 0, 1, 1, 7903.22216796875, 2050.048828125, 599.98638916015625, 0.043632153421640396, 0, 0, 0.021814346313476562, 0.99976205825805664, 120, 255, 1, "", 46368, NULL),
|
||||
(2079, 193640, 571, 0, 0, 1, 1, 7903.53271484375, 2050.19677734375, 600.09759521484375, 0.177969858050346374, 0.183217525482177734, 0.098484039306640625, 0.070977210998535156, 0.975548326969146728, 120, 255, 1, "", 46368, NULL),
|
||||
(2080, 193641, 571, 0, 0, 1, 1, 7903.39697265625, 2050.458740234375, 600.12481689453125, 3.194002151489257812, 0, 0, -0.99965667724609375, 0.026201646775007247, 120, 255, 1, "", 46368, NULL),
|
||||
(2081, 193646, 571, 0, 0, 1, 1, 7904.517578125, 2052.545166015625, 600.2119140625, 6.065019607543945312, 0, 0, -0.10886669158935546, 0.994056344032287597, 120, 255, 1, "", 46368, NULL),
|
||||
(2082, 193647, 571, 0, 0, 1, 1, 7903.68505859375, 2052.069091796875, 600.21636962890625, 0.680676698684692382, 0, 0, 0.333806037902832031, 0.942641794681549072, 120, 255, 1, "", 46368, NULL),
|
||||
(2083, 193648, 571, 0, 0, 1, 1, 7904.35107421875, 2051.583740234375, 600.22607421875, 5.672319889068603515, 0, 0, -0.3007059097290039, 0.953716933727264404, 120, 255, 1, "", 46368, NULL),
|
||||
(2084, 193655, 571, 0, 0, 1, 1, 7880.44384765625, 2070.882568359375, 601.27783203125, 6.152286052703857421, 0, 0, -0.06540298461914062, 0.997858941555023193, 120, 255, 1, "", 46368, NULL),
|
||||
(2085, 193656, 571, 0, 0, 1, 1, 7880.8056640625, 2071.86962890625, 601.318603515625, 3.717553138732910156, 0.161904335021972656, 0.094899177551269531, -0.93937873840332031, 0.286964625120162963, 120, 255, 1, "", 46368, NULL),
|
||||
(2086, 193667, 571, 0, 0, 1, 1, 7874.93603515625, 2051.4755859375, 601.44091796875, 2.574358940124511718, 0, 0, 0.960049629211425781, 0.279829770326614379, 120, 255, 1, "", 46368, NULL),
|
||||
(2087, 193672, 571, 0, 0, 1, 1, 7895.59130859375, 2044.85791015625, 601.402587890625, 4.127707481384277343, 0, 0, -0.880889892578125, 0.473321229219436645, 120, 255, 1, "", 46368, NULL),
|
||||
(2088, 193673, 571, 0, 0, 1, 1, 7895.86083984375, 2043.8819580078125, 601.3876953125, 3.298687219619750976, 0, 0, -0.99691677093505859, 0.078466430306434631, 120, 255, 1, "", 46368, NULL),
|
||||
(2089, 193675, 571, 0, 0, 1, 1, 7888.546875, 2057.972900390625, 599.6009521484375, 1.474801421165466308, 0, 0, 0.672366142272949218, 0.740218758583068847, 120, 255, 1, "", 46368, NULL),
|
||||
(2090, 193679, 571, 0, 0, 1, 1, 7893.048828125, 2071.62255859375, 600.365478515625, 3.813161611557006835, -0.69073057174682617, -0.15002155303955078, -0.69123363494873046, 0.150269299745559692, 120, 255, 1, "", 46368, NULL),
|
||||
(2091, 193682, 571, 0, 0, 1, 1, 7895.12890625, 2072.302978515625, 601.992919921875, 0.365644693374633789, 0, 0, 0.181805610656738281, 0.983334481716156005, 120, 255, 1, "", 46368, NULL),
|
||||
(2092, 193683, 571, 0, 0, 1, 1, 7875.3193359375, 2053.161376953125, 600.2493896484375, 1.278458118438720703, 0.212913990020751953, -0.32244300842285156, 0.543003082275390625, 0.745550692081451416, 120, 255, 1, "", 46368, NULL),
|
||||
(2093, 193684, 571, 0, 0, 1, 1, 7898.14697265625, 2066.417236328125, 600.31329345703125, 0.75534135103225708, 0, 0, 0.368756294250488281, 0.929526090621948242, 120, 255, 1, "", 46368, NULL),
|
||||
(2094, 193685, 571, 0, 0, 1, 1, 7897.3955078125, 2049.253173828125, 600.3131103515625, 5.459003925323486328, 0, 0, -0.40052604675292968, 0.916285336017608642, 120, 255, 1, "", 46368, NULL),
|
||||
(2095, 193686, 571, 0, 0, 1, 1, 7878.8671875, 2049.250244140625, 600.31298828125, 0.75534135103225708, 0, 0, 0.368756294250488281, 0.929526090621948242, 120, 255, 1, "", 46368, NULL),
|
||||
(2096, 193687, 571, 0, 0, 1, 1, 7878.82861328125, 2066.62109375, 600.31317138671875, 5.432824611663818359, 0, 0, -0.41248512268066406, 0.910964369773864746, 120, 255, 1, "", 46368, NULL),
|
||||
(2097, 193688, 571, 0, 0, 1, 1, 7881.25048828125, 2043.955078125, 600.2493896484375, 1.4564744234085083, 0, 0, 0.665555000305175781, 0.746348798274993896, 120, 255, 1, "", 46368, NULL),
|
||||
(2098, 193689, 571, 0, 0, 1, 1, 7879.41748046875, 2044.993408203125, 600.2493896484375, 0.219910025596618652, 0, 0, 0.10973358154296875, 0.993961036205291748, 120, 255, 1, "", 46368, NULL),
|
||||
(2099, 193690, 571, 0, 0, 1, 1, 7881.208984375, 2043.9761962890625, 600.2493896484375, 0.304556638002395629, 0, 0, 0.151690483093261718, 0.988428056240081787, 120, 255, 1, "", 46368, NULL),
|
||||
(2100, 193694, 571, 0, 0, 1, 1, 7886.49609375, 2059.90869140625, 600.2626953125, 5.452062606811523437, 0, 0, -0.40370368957519531, 0.914889812469482421, 120, 255, 1, "", 46368, NULL),
|
||||
(2101, 193695, 571, 0, 0, 1, 1, 7885.58935546875, 2059.190185546875, 600.76806640625, 2.337379932403564453, 0.248764514923095703, 0.376603126525878906, 0.836214065551757812, 0.311500102281570434, 120, 255, 1, "", 46368, NULL);
|
||||
|
||||
-- remove duplicate spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (193706, 193712, 193713, 193719, 193698, 193699, 193700, 193705, 193708, 193722, 193723, 193724, 193725, 193726, 193730, 193731, 193732, 193733, 193734, 193735, 193738, 193739, 193740, 193759, 193760, 193761, 193749, 193747, 193748, 193692)) AND (`guid` IN (268830, 268824, 268823, 268817, 268838, 268837, 268836, 268831, 268828, 268814, 268813, 268812, 268811, 268810, 268806, 268805, 268804, 268803, 268802, 268801, 268798, 268797, 268796, 268778, 268777, 268776, 268787, 268789, 268788, 256036, 257787, 258233, 260066, 260579, 261410, 261970, 262680, 263207, 263653, 265211, 266056, 267263, 267510, 267905, 268771));
|
||||
DELETE FROM `gameobject_addon` WHERE (`guid` IN (268830, 268824, 268823, 268817, 268838, 268837, 268836, 268831, 268828, 268814, 268813, 268812, 268811, 268810, 268806, 268805, 268804, 268803, 268802, 268801, 268798, 268797, 268796, 268778, 268777, 268776, 268787, 268789, 268788, 256036, 257787, 258233, 260066, 260579, 261410, 261970, 262680, 263207, 263653, 265211, 266056, 267263, 267510, 267905, 268771));
|
||||
DELETE FROM `game_event_gameobject` WHERE (`eventEntry` = 0) AND (`guid` IN (268830, 268824, 268823, 268817, 268838, 268837, 268836, 268831, 268828, 268814, 268813, 268812, 268811, 268810, 268806, 268805, 268804, 268803, 268802, 268801, 268798, 268797, 268796, 268778, 268777, 268776, 268787, 268789, 268788, 256036, 257787, 258233, 260066, 260579, 261410, 261970, 262680, 263207, 263653, 265211, 266056, 267263, 267510, 267905, 268771));
|
||||
@@ -0,0 +1,12 @@
|
||||
-- DB update 2025_09_03_00 -> 2025_09_03_01
|
||||
--
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 44407);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(17, 0, 44407, 0, 0, 31, 1, 3, 24747, 0, 0, 0, 0, '', 'Hawk Hunting must target Fjord Hawk');
|
||||
|
||||
UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 24747;
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 24747) AND (`source_type` = 0);
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_hawk_hunting';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(44407, 'spell_hawk_hunting');
|
||||
@@ -0,0 +1,9 @@
|
||||
-- DB update 2025_09_03_01 -> 2025_09_03_02
|
||||
--
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (16423, 16437, 16438, 16422);
|
||||
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (16423, 16437, 16438, 16422);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(16423, 0, 0, 0, 0, 0, 100, 0, 0, 0, 5000, 10000, 0, 0, 11, 28265, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Spectral Apparition - In Combat - Cast \'Scourge Strike\''),
|
||||
(16437, 0, 0, 0, 0, 0, 100, 0, 0, 0, 5000, 10000, 0, 0, 11, 28265, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Spectral Spirit - In Combat - Cast \'Scourge Strike\''),
|
||||
(16422, 0, 0, 0, 0, 0, 100, 0, 0, 0, 5000, 10000, 0, 0, 11, 28265, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeletal Soldier - In Combat - Cast \'Scourge Strike\''),
|
||||
(16438, 0, 0, 0, 0, 0, 100, 0, 0, 0, 5000, 10000, 0, 0, 11, 28265, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Skeletal Trooper - In Combat - Cast \'Scourge Strike\'');
|
||||
@@ -0,0 +1,7 @@
|
||||
-- DB update 2025_09_03_02 -> 2025_09_04_00
|
||||
--
|
||||
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 188141;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 1 AND `entryorguid` = 188141);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(188141, 1, 0, 0, 64, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 3000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Frozen Phylactery - On Gossip Hello - Despawn In 3000 ms');
|
||||
@@ -0,0 +1,2 @@
|
||||
-- DB update 2025_09_04_00 -> 2025_09_04_01
|
||||
UPDATE `creature_model_info` SET `DisplayID_Other_Gender` = 0 WHERE `DisplayID` IN (16292, 16294);
|
||||
@@ -0,0 +1,18 @@
|
||||
-- DB update 2025_09_04_01 -> 2025_09_04_02
|
||||
-- Update gameobject 'Gravestone' with sniffed values
|
||||
-- updated spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (192256)) AND (`guid` IN (76993));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(76993, 192256, 571, 0, 0, 1, 1, 9025.6845703125, -1178.6163330078125, 1058.107666015625, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 46368, NULL);
|
||||
|
||||
-- new spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (192257, 192258, 192260, 192265, 192380)) AND (`guid` BETWEEN 265 AND 269);
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(265, 192257, 571, 0, 0, 1, 1, 8094.673828125, -995.29864501953125, 936.18206787109375, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 53788, NULL),
|
||||
(266, 192258, 571, 0, 0, 1, 1, 7832.95556640625, -2018.984375, 1224.683349609375, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 52237, NULL),
|
||||
(267, 192260, 571, 0, 0, 1, 1, 7463.06689453125, -3326.37841796875, 897.74884033203125, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 47720, NULL),
|
||||
(268, 192265, 571, 0, 0, 1, 1, 6942.8603515625, -552.515625, 914.403564453125, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 50664, NULL),
|
||||
(269, 192380, 571, 0, 0, 1, 1, 6431.64404296875, -1186.592041015625, 446.2081298828125, 3.141592741012573242, 0, 0, -1, 0, 120, 255, 1, "", 47720, NULL);
|
||||
|
||||
-- remaining spawns (no sniffed values available)
|
||||
-- (`guid` IN (77187))
|
||||
@@ -0,0 +1,23 @@
|
||||
-- DB update 2025_09_04_02 -> 2025_09_04_03
|
||||
--
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24170);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(24170, 0, 0, 3, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Draconis Gastritis Bunny - On Just Summoned - Store Targetlist'),
|
||||
(24170, 0, 1, 4, 6, 0, 100, 0, 0, 0, 0, 0, 0, 0, 33, 24170, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 0, 'Draconis Gastritis Bunny - On Just Died - Quest Credit \'null\''),
|
||||
(24170, 0, 2, 0, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Draconis Gastritis Bunny - On Just Summoned - Set Visibility Off'),
|
||||
(24170, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 50, 186598, 45, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Draconis Gastritis Bunny - On Just Summoned - Summon Gameobject \'Tillinghast\'s Plagued Meat\''),
|
||||
(24170, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 1, 0, 0, 0, 20, 186598, 10, 0, 0, 0, 0, 0, 0, 'Draconis Gastritis Bunny - On Just Died - Despawn Instant');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 23689);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(23689, 0, 1, 4, 65, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 36809, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - On Follow Complete - Cast \'Overpowering Sickness\''),
|
||||
(23689, 0, 3, 5, 1, 0, 100, 512, 10000, 10000, 10000, 10000, 0, 0, 29, 0, 0, 24170, 0, 0, 0, 19, 24170, 75, 0, 0, 0, 0, 0, 0, 'Proto-Drake - Out of Combat - Start Follow Closest Creature \'Draconis Gastritis Bunny\''),
|
||||
(23689, 0, 4, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 19, 24170, 10, 0, 0, 0, 0, 0, 0, 'Proto-Drake - On Follow Complete - Kill Target'),
|
||||
(23689, 0, 5, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - Out of Combat - Set Event Phase 1'),
|
||||
(23689, 0, 6, 0, 1, 1, 100, 512, 45000, 45000, 45000, 45000, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - Out of Combat - Despawn Instant (Phase 1)'),
|
||||
-- update comments with Keira
|
||||
(23689, 0, 8, 0, 8, 0, 100, 0, 40969, 0, 120000, 120000, 0, 0, 69, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - On Spellhit \'Malister`s Frost Wand\' - Move To Invoker'),
|
||||
(23689, 0, 9, 0, 9, 0, 100, 513, 0, 0, 0, 0, 0, 20, 101, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - Within 0-20 Range - Set Home Position (No Repeat)'),
|
||||
(23689, 0, 10, 0, 9, 0, 100, 0, 0, 0, 2000, 3500, 0, 5, 11, 51219, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - Within 0-5 Range - Cast \'Flame Breath\''),
|
||||
(23689, 0, 11, 0, 0, 0, 100, 0, 3000, 9000, 30000, 45000, 0, 0, 11, 42362, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - In Combat - Cast \'Flames of Birth\''),
|
||||
(23689, 0, 12, 0, 9, 0, 100, 0, 0, 0, 10000, 15000, 0, 20, 11, 41572, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Proto-Drake - Within 0-20 Range - Cast \'Wing Buffet\'');
|
||||
@@ -0,0 +1,64 @@
|
||||
-- DB update 2025_09_04_03 -> 2025_09_05_00
|
||||
-- Prevent removal on evade
|
||||
DELETE FROM `spell_custom_attr` WHERE `spell_id` IN (50665, 50681, 50695);
|
||||
INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES
|
||||
(50665, 2048),
|
||||
(50681, 2048),
|
||||
(50695, 2048);
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28148);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28148, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Reset - Set Event Phase 1'),
|
||||
(28148, 0, 1, 2, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50695, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Just Summoned - Cast \'Bleeding Out\''),
|
||||
(28148, 0, 2, 3, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Just Summoned - Start Follow Invoker'),
|
||||
(28148, 0, 3, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Just Summoned - Remove FlagStandstate Sit Down'),
|
||||
(28148, 0, 4, 0, 23, 1, 100, 513, 50695, 0, 0, 0, 0, 0, 80, 2814800, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Aura \'Bleeding Out\' - Run Script (Phase 1) (No Repeat)'),
|
||||
(28148, 0, 5, 6, 40, 0, 100, 513, 4, 0, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Point 4 of Path Any Reached - Set Flag Standstate Sit Down (No Repeat)'),
|
||||
(28148, 0, 6, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 20000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Point 4 of Path Any Reached - Despawn In 20000 ms (No Repeat)'),
|
||||
(28148, 0, 7, 8, 8, 1, 100, 512, 50669, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Set Event Phase 2 (Phase 1)'),
|
||||
(28148, 0, 8, 9, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50698, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Cast \'Kill Credit Jospehine 01\' (Phase 1)'),
|
||||
(28148, 0, 9, 10, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50711, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Cast \'Strip Aura Josephine 01\' (Phase 1)'),
|
||||
(28148, 0, 10, 11, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 86, 50699, 2, 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Cross Cast \'Josephine Kill Credit\' (Phase 1)'),
|
||||
(28148, 0, 11, 12, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 86, 50712, 2, 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Cross Cast \'Strip Aura Josephine\' (Phase 1)'),
|
||||
(28148, 0, 12, 13, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Stop Follow (Phase 1)'),
|
||||
(28148, 0, 13, 14, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Say Line 0 (Phase 1)'),
|
||||
(28148, 0, 14, 15, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 0, 28148, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Start Waypoint Path 28148 (Phase 1)'),
|
||||
(28148, 0, 15, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Josephine - On Spellhit \'Quest Credit\' - Remove Npc Flags Gossip (Phase 1)');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28142) AND (`source_type` = 0);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28142, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Reset - Set Event Phase 1'),
|
||||
(28142, 0, 1, 2, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50681, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Just Summoned - Cast \'Bleeding Out\''),
|
||||
(28142, 0, 2, 3, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Just Summoned - Start Follow Invoker'),
|
||||
(28142, 0, 3, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Just Summoned - Remove FlagStandstate Sit Down'),
|
||||
(28142, 0, 4, 0, 23, 1, 100, 513, 50681, 0, 0, 0, 0, 0, 80, 2814200, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Aura \'Bleeding Out\' - Run Script (Phase 1) (No Repeat)'),
|
||||
(28142, 0, 5, 6, 40, 0, 100, 513, 5, 0, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Point 5 of Path Any Reached - Set Flag Standstate Sit Down (No Repeat)'),
|
||||
(28142, 0, 6, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 20000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Point 5 of Path Any Reached - Despawn In 20000 ms (No Repeat)'),
|
||||
(28142, 0, 7, 8, 8, 1, 100, 512, 50669, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Set Event Phase 2 (Phase 1)'),
|
||||
(28142, 0, 8, 9, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50683, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Cast \'Kill Credit Lamoof 01\' (Phase 1)'),
|
||||
(28142, 0, 9, 10, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50723, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Cast \'Strip Aura Lamoof 01\' (Phase 1)'),
|
||||
(28142, 0, 10, 11, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 86, 50684, 2, 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Cross Cast \'Lamoof Kill Credit\' (Phase 1)'),
|
||||
(28142, 0, 11, 12, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 86, 50722, 2, 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Cross Cast \'Strip Aura Lamoof\' (Phase 1)'),
|
||||
(28142, 0, 12, 13, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Stop Follow (Phase 1)'),
|
||||
(28142, 0, 13, 14, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Say Line 0 (Phase 1)'),
|
||||
(28142, 0, 14, 15, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 0, 28142, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Start Waypoint Path 28142 (Phase 1)'),
|
||||
(28142, 0, 15, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Lamoof - On Spellhit \'Quest Credit\' - Remove Npc Flags Gossip (Phase 1)');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28136);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28136, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Reset - Set Event Phase 1'),
|
||||
(28136, 0, 1, 2, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50665, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Just Summoned - Cast \'Bleeding Out\''),
|
||||
(28136, 0, 2, 3, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Just Summoned - Start Follow Invoker'),
|
||||
(28136, 0, 3, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Just Summoned - Remove FlagStandstate Sit Down'),
|
||||
(28136, 0, 4, 0, 23, 1, 100, 513, 50665, 0, 0, 0, 0, 0, 80, 2813600, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Aura \'Bleeding Out\' - Run Script (Phase 1) (No Repeat)'),
|
||||
(28136, 0, 5, 6, 40, 0, 100, 513, 5, 0, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Point 5 of Path Any Reached - Set Flag Standstate Sit Down (No Repeat)'),
|
||||
(28136, 0, 6, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 20000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Point 5 of Path Any Reached - Despawn In 20000 ms (No Repeat)'),
|
||||
(28136, 0, 7, 8, 8, 1, 100, 512, 50669, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Set Event Phase 2 (Phase 1)'),
|
||||
(28136, 0, 8, 9, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50671, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Cast \'Kill Credit Jonathan 01\' (Phase 1)'),
|
||||
(28136, 0, 9, 10, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50709, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Cast \'Strip Aura Jonathan 01\' (Phase 1)'),
|
||||
(28136, 0, 10, 11, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 86, 50680, 2, 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Cross Cast \'Jonathan Kill Credit\' (Phase 1)'),
|
||||
(28136, 0, 11, 12, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 86, 50710, 2, 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Cross Cast \'Strip Aura Jonanthan\' (Phase 1)'),
|
||||
(28136, 0, 12, 13, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Stop Follow (Phase 1)'),
|
||||
(28136, 0, 13, 14, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Say Line 0 (Phase 1)'),
|
||||
(28136, 0, 14, 15, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 53, 0, 28136, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Start Waypoint Path 28136 (Phase 1)'),
|
||||
(28136, 0, 15, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Crusader Jonathan - On Spellhit \'Quest Credit\' - Remove Npc Flags Gossip (Phase 1)');
|
||||
@@ -0,0 +1,5 @@
|
||||
-- DB update 2025_09_05_00 -> 2025_09_05_01
|
||||
DELETE FROM `creature_template_spell` WHERE `CreatureID` = 21750 AND `Index` IN (2, 3);
|
||||
INSERT INTO `creature_template_spell` (`CreatureID`, `Index`, `Spell`, `VerifiedBuild`) VALUES
|
||||
(21750, 2, 37463, 0),
|
||||
(21750, 3, 37469, 0);
|
||||
@@ -0,0 +1,9 @@
|
||||
-- DB update 2025_09_05_01 -> 2025_09_06_00
|
||||
--
|
||||
SET @CGUID:=12891;
|
||||
DELETE FROM `creature` WHERE (`id1` = 16786) AND (`guid` = (@CGUID));
|
||||
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `Comment`, `VerifiedBuild`) VALUES
|
||||
(@CGUID, 16786, 0, 0, 0, 0, 0, 1, 1, 0, -4926.95, -981.718, 501.55, 2.0071299076080322, 120, 0, 0, 1, 0, 0, 0, 0, 0, '', '', 0);
|
||||
|
||||
DELETE FROM `game_event_creature` WHERE `guid` = @CGUID;
|
||||
INSERT INTO `game_event_creature` (`eventEntry`, `guid`) VALUES(17, @CGUID);
|
||||
@@ -0,0 +1,3 @@
|
||||
-- DB update 2025_09_06_00 -> 2025_09_06_01
|
||||
--
|
||||
UPDATE `creature_template` SET `RegenHealth` = 0 WHERE (`entry` IN (16136, 16172));
|
||||
@@ -0,0 +1,80 @@
|
||||
-- DB update 2025_09_06_01 -> 2025_09_06_02
|
||||
--
|
||||
-- Changes Scorn's spawn from Event 17 (Scourge Invasion) to 120 (Scourge Invasion - Boss in instance activation)
|
||||
UPDATE `game_event_creature` SET `eventEntry` = 120 WHERE `guid` = 248652;
|
||||
|
||||
-- Adds "FORCE_GOSSIP" for Sever
|
||||
UPDATE `creature_template` SET `type_flags` = 134217728 WHERE `entry` = 14682;
|
||||
-- Adds "FORCE_GOSSIP" and changes from "Warrior" to "Paladin" for Balzaphon, Lady Falther'ess and Scorn
|
||||
UPDATE `creature_template` SET `unit_class` = 2, `type_flags` = 134217728 WHERE `entry` IN (14684, 14686, 14690, 14693);
|
||||
-- Makes Balzaphon and Revanchion immune to Charge
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = (`mechanic_immune_mask` | 2048) WHERE `entry` IN (14684, 14690);
|
||||
-- Scorn immune to root
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = (`mechanic_immune_mask` | 64) WHERE `entry` IN (14693);
|
||||
|
||||
-- Adds SAI to Sever, Balzaphon, Lady Falther'ess, Revanchion and Lord Blackwood
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (14682, 14684, 14686, 14695);
|
||||
|
||||
-- Adds Spirit Particles (purple) to Lord Blackwood
|
||||
UPDATE `creature_template_addon` SET `auras` = '28126' WHERE `entry` = 14695;
|
||||
|
||||
-- Adds Spirit Particles (purple) and Frost Armor to Revanchion
|
||||
UPDATE `creature_template_addon` SET `auras` = '28126 12556' WHERE `entry` = 14690 ;
|
||||
|
||||
-- Adds SAI to Holding Pen (157819)
|
||||
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 157819;
|
||||
|
||||
-- Adds Spirit Particles (purple) to Sever, Balzaphon, Revanchion and Scorn
|
||||
DELETE FROM `creature_template_addon` WHERE `entry` IN (14684, 14686, 14690, 14693, 14682);
|
||||
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
|
||||
(14682, 0, 0, 0, 1, 0, 0, '28126'), -- Sever
|
||||
(14684, 0, 0, 0, 1, 0, 0, '28126'), -- Balzaphon
|
||||
(14690, 0, 0, 0, 1, 0, 0, '28126'), -- Revanchion
|
||||
(14693, 0, 0, 0, 1, 0, 0, '28126'); -- Scorn
|
||||
|
||||
-- Adds Server and Lady Falther'ess texts.
|
||||
DELETE FROM `creature_text` WHERE `CreatureID` IN (14682, 14686);
|
||||
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(14682, 0, 0, '%s goes into a frenzy!', 16, 0, 100, 0, 0, 0, 1191, 0, '[Sever] Sever goes into a frenzy! / %s goes into a frenzy!'),
|
||||
(14686, 0, 0, 'Thank you for becoming my next victim!', 14, 0, 100, 0, 0, 0, 12429, 0, '[Lady Falther\'ess] Thank you for becoming my next victim!');
|
||||
|
||||
-- SmartGameObjectAI
|
||||
-- 157819 (Holding Pen), when the "holding pen" is opened, saves data variable and sends to lady father'ess so it can be used after as a initatior of encounter with the player.
|
||||
DELETE FROM `smart_scripts` WHERE `source_type` = 1 AND `entryorguid` = 157819;
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(157819, 1, 0, 1, 70, 0, 100, 0, 2, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Holding Pen - On Gameobject State Changed - Store Targetlist to Lady Falther\'ess'),
|
||||
(157819, 1, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 100, 1, 0, 0, 0, 0, 0, 19, 14686, 0, 0, 0, 0, 0, 0, 0, 'Holding Pen - On Gameobject State Changed - Send Target 1 to Lady Falther\'ess'),
|
||||
(157819, 1, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 19, 14686, 0, 0, 0, 0, 0, 0, 0, 'Holding Pen - On Gameobject State Changed - Set Data 1 1 to Lady Falther\'ess');
|
||||
|
||||
-- SmartAI
|
||||
-- Adds SAI logic to Sever, Balzaphon, Lady Falther'ess, Revanchion and Lord Blackwood
|
||||
DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryorguid` IN (14682, 14684, 14686, 14690, 14695);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
-- Sever
|
||||
(14682, 0, 0, 0, 0, 0, 100, 0, 12000, 31000, 8000, 30000, 0, 0, 11, 17745, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Sever - In Combat - Cast \'Diseased Spit\''),
|
||||
(14682, 0, 1, 2, 2, 0, 100, 0, 1, 50, 0, 0, 0, 0, 11, 8269, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Sever - Between 1-50% Health - Cast \'Frenzy\''),
|
||||
(14682, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Sever - Between 1-50% Health - Say Line 0 "Sever goes into a frenzy!"'),
|
||||
(14682, 0, 3, 0, 101, 0, 100, 0, 2, 10, 12500, 10000, 15000, 0, 11, 16508, 0, 0, 0, 0, 0, 17, 0, 10, 5, 0, 0, 0, 0, 0, 'Sever - On 2 or More Players in Range - Cast \'Intimidating Roar\''),
|
||||
-- Balzaphon
|
||||
(14684, 0, 0, 0, 0, 0, 100, 0, 2000, 7000, 2000, 5000, 0, 0, 11, 16799, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Balzaphon - In Combat - Cast \'Frostbolt\''),
|
||||
(14684, 0, 1, 0, 0, 0, 100, 0, 6000, 12000, 7000, 15000, 0, 0, 11, 15244, 0, 0, 0, 0, 0, 5, 10, 0, 2, 0, 0, 0, 0, 0, 'Balzaphon - In Combat - Cast \'Cone of Cold\''),
|
||||
(14684, 0, 2, 0, 0, 0, 100, 0, 10000, 20000, 12000, 20000, 0, 0, 11, 8398, 0, 0, 0, 0, 0, 5, 20, 0, 2, 0, 0, 0, 0, 0, 'Balzaphon - In Combat - Cast \'Frostbolt Volley\''),
|
||||
-- Lady Falther'ess
|
||||
(14686, 0, 0, 1, 37, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 28533, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Initialize - Cast \'Transform\' (Salma Saldean)'),
|
||||
(14686, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 2, 35, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Initialize - Set Faction 35 (Friendly)'),
|
||||
(14686, 0, 2, 3, 38, 0, 100, 0, 1, 1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Data Set 1 1 - Demorph'),
|
||||
(14686, 0, 3, 4, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Data Set 1 1 - Say Line 0 - Thank you for becoming my next victim! '),
|
||||
(14686, 0, 4, 5, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 2, 21, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Data Set 1 1 - Set Faction 21 (Undead, Scourge)'),
|
||||
(14686, 0, 5, 6, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 21, 30, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Data Set 1 1 - Start Attacking (Closest Player within 30 yards)'),
|
||||
(14686, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 75, 28126, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On Data Set 1 1 - Add Aura \'Spirit Particles (purple)\''),
|
||||
(14686, 0, 7, 0, 0, 0, 100, 0, 2500, 8000, 10000, 18000, 0, 0, 11, 22743, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Lady Falther\'ess - In Combat - Cast \'Ribbon of Souls\''),
|
||||
(14686, 0, 8, 0, 0, 0, 100, 0, 17500, 20000, 19000, 22000, 0, 0, 11, 17105, 0, 0, 0, 0, 0, 5, 30, 1, 2, 17105, 0, 0, 0, 0, 'Lady Falther\'ess - In Combat - Cast \'Banshee Curse\''),
|
||||
(14686, 0, 9, 0, 101, 0, 100, 0, 2, 10, 7500, 5000, 6000, 0, 11, 16838, 0, 0, 5, 0, 0, 17, 0, 5, 5, 0, 0, 0, 0, 0, 'Lady Falther\'ess - On 2 or More Players in Range - Cast \'Banshee Shriek\''),
|
||||
-- Revanchion
|
||||
(14690, 0, 0, 0, 0, 0, 100, 0, 10000, 15000, 12500, 14000, 0, 0, 11, 15245, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Revanchion - In Combat - Cast \'Shadow Bolt Volley\''),
|
||||
(14690, 0, 1, 0, 0, 0, 100, 0, 13000, 16000, 14000, 18000, 0, 0, 11, 14907, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Revanchion - In Combat - Cast \'Frost Nova\''),
|
||||
-- Lord Blackwood
|
||||
(14695, 0, 0, 0, 0, 0, 100, 0, 8000, 16000, 20000, 20000, 0, 0, 11, 7964, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Lord Blackwood - In Combat - Cast \'Smoke Bomb\''),
|
||||
(14695, 0, 1, 0, 105, 0, 100, 0, 10000, 12000, 10000, 12000, 0, 5, 11, 11972, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Lord Blackwood - On Hostile Casting in Range - Cast \'Shield Bash\''),
|
||||
(14695, 0, 2, 0, 110, 0, 100, 0, 2000, 20000, 20000, 20000, 0, 1, 11, 20733, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Lord Blackwood - On Melee Range Target - Cast \'Black Arrow\''),
|
||||
(14695, 0, 3, 0, 110, 0, 100, 0, 0, 0, 2400, 2400, 0, 1, 11, 16496, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Lord Blackwood - On Melee Range Target - Cast \'Shoot\'');
|
||||
@@ -0,0 +1,30 @@
|
||||
-- DB update 2025_09_06_02 -> 2025_09_06_03
|
||||
-- Remove heroic casts as it is already handled by spelldifficulty_dbc and add on aggro engage
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28729);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28729, 0, 0, 0, 0, 0, 100, 0, 2000, 6000, 15000, 20000, 0, 0, 11, 52524, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Narjil - In Combat - Cast \'Blinding Webs\''),
|
||||
(28729, 0, 2, 0, 0, 0, 100, 0, 6000, 15000, 20000, 25000, 0, 0, 11, 52086, 0, 0, 0, 0, 0, 5, 30, 0, 0, 0, 0, 0, 0, 0, 'Watcher Narjil - In Combat - Cast \'Web Wrap\''),
|
||||
(28729, 0, 3, 0, 0, 0, 100, 0, 4000, 12000, 9000, 15000, 0, 0, 11, 52469, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Narjil - In Combat - Cast \'Infected Bite\''),
|
||||
(28729, 0, 5, 0, 8, 0, 100, 0, 52343, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Narjil - On Spellhit \'Krik`Thir Subboss Aggro Trigger\' - Set In Combat With Zone'),
|
||||
(28729, 0, 6, 0, 0, 0, 100, 1, 500, 500, 0, 0, 0, 0, 39, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Narjil - In Combat - Call For Help (No Repeat)'),
|
||||
(28729, 0, 1, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 205, 0, 1, 0, 0, 0, 0, 0, 0, 'Watcher Narjil - On Aggro - Do Action ID 1');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28730);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28730, 0, 0, 0, 0, 0, 100, 0, 2000, 6000, 15000, 20000, 0, 0, 11, 52470, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Gashra - In Combat - Cast \'Enrage\''),
|
||||
(28730, 0, 1, 0, 0, 0, 100, 0, 6000, 15000, 20000, 25000, 0, 0, 11, 52086, 0, 0, 0, 0, 0, 5, 30, 0, 0, 0, 0, 0, 0, 0, 'Watcher Gashra - In Combat - Cast \'Web Wrap\''),
|
||||
(28730, 0, 2, 0, 0, 0, 100, 0, 4000, 12000, 9000, 15000, 0, 0, 11, 52469, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Gashra - In Combat - Cast \'Infected Bite\''),
|
||||
(28730, 0, 4, 0, 8, 0, 100, 0, 52343, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Gashra - On Spellhit \'Krik`Thir Subboss Aggro Trigger\' - Set In Combat With Zone'),
|
||||
(28730, 0, 5, 0, 0, 0, 100, 1, 500, 500, 0, 0, 0, 0, 39, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Gashra - In Combat - Call For Help (No Repeat)'),
|
||||
(28730, 0, 3, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 205, 0, 1, 0, 0, 0, 0, 0, 0, 'Watcher Gashra - On Aggro - Do Action ID 1');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28731);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(28731, 0, 0, 0, 0, 0, 100, 0, 2000, 6000, 15000, 20000, 0, 0, 11, 52493, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Silthik - In Combat - Cast \'Poison Spray\''),
|
||||
(28731, 0, 2, 0, 0, 0, 100, 0, 6000, 15000, 20000, 25000, 0, 0, 11, 52086, 0, 0, 0, 0, 0, 5, 30, 0, 0, 0, 0, 0, 0, 0, 'Watcher Silthik - In Combat - Cast \'Web Wrap\''),
|
||||
(28731, 0, 3, 0, 0, 0, 100, 0, 4000, 12000, 9000, 15000, 0, 0, 11, 52469, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Silthik - In Combat - Cast \'Infected Bite\''),
|
||||
(28731, 0, 5, 0, 8, 0, 100, 0, 52343, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Silthik - On Spellhit \'Krik`Thir Subboss Aggro Trigger\' - Set In Combat With Zone'),
|
||||
(28731, 0, 6, 0, 0, 0, 100, 1, 500, 500, 0, 0, 0, 0, 39, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Watcher Silthik - In Combat - Call For Help (No Repeat)'),
|
||||
(28731, 0, 1, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 205, 0, 1, 0, 0, 0, 0, 0, 0, 'Watcher Silthik - On Aggro - Do Action ID 1');
|
||||
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` &~ 33554432 WHERE `entry` IN (28684, 31612);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- DB update 2025_09_06_03 -> 2025_09_06_04
|
||||
|
||||
-- Arzeth the Merciless (Charm, Fear, Root, Snare, Banish, Horror)
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` |1|16|64|1024|131072|8388608 WHERE (`entry` = 19354);
|
||||
|
||||
-- Illidari Dreadlord (Charm, Fear, Snare)
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` |1|16|1024 WHERE (`entry` = 21166);
|
||||
|
||||
-- Wrath Master (Charm, Snare)
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` |1|1024 WHERE (`entry` = 19005);
|
||||
|
||||
-- Arazzius the Cruel (Charm, Fear, Root, Snare, Stun, Freeze, Polymorph, Banish)
|
||||
UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` |1|16|64|1024|2048|4096|65536|131072 WHERE (`entry` = 19191);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- DB update 2025_09_06_04 -> 2025_09_06_05
|
||||
-- Update gameobject 'Doodad_FrostGiantIceShard' with sniffed values
|
||||
-- updated spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (192193, 192194, 192195)) AND (`guid` IN (20924, 20925, 20926));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(20924, 192193, 571, 0, 0, 1, 4, 7325.5732421875, -2044.4727783203125, 760.7373046875, 5.478795528411865234, 0.056999683380126953, 0.307971954345703125, -0.35146713256835937, 0.882255733013153076, 120, 255, 1, "", 46158, NULL),
|
||||
(20925, 192194, 571, 0, 0, 1, 4, 7320.685546875, -2053.649169921875, 761.33929443359375, 5.478795528411865234, 0.056999683380126953, 0.307971954345703125, -0.35146713256835937, 0.882255733013153076, 120, 255, 1, "", 46158, NULL),
|
||||
(20926, 192195, 571, 0, 0, 1, 4, 7321.001953125, -2054.294677734375, 760.8995361328125, 4.88195037841796875, 0.128789901733398437, -0.01092052459716796, -0.64533519744873046, 0.752885341644287109, 120, 255, 1, "", 46158, NULL);
|
||||
|
||||
-- new spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (192186)) AND (`guid` IN (40));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(40, 192186, 571, 0, 0, 1, 4, 7299.98193359375, -2056.776123046875, 760.91754150390625, 3.129810810089111328, 0.336331367492675781, 0.04759979248046875, -0.9404611587524414, 0.012177699245512485, 120, 255, 1, "", 46158, NULL);
|
||||
@@ -0,0 +1,16 @@
|
||||
-- DB update 2025_09_06_05 -> 2025_09_07_00
|
||||
--
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 1) AND (`SourceEntry` = 27409) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 32) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 16) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(22, 1, 27409, 0, 0, 32, 0, 16, 0, 0, 0, 0, 0, '', 'Ducal\'s horse only run sai if boarding passenger is player');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2740900) AND (`source_type` = 9) AND (`id` IN (0));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(2740900, 9, 0, 0, 0, 0, 100, 512, 3000, 3000, 0, 0, 0, 0, 53, 1, 27409, 0, 12308, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Ducal\'s Horse - On Script - Start Waypoint');
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 27409) AND (`source_type` = 0) AND (`id` IN (1, 8, 9, 10));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(27409, 0, 1, 10, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Ducal\'s Horse - On Passenger Boarded - Set Reactstate Passive'),
|
||||
(27409, 0, 8, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 67, 1, 10000, 10000, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Ducal\'s Horse - On Reset - Create Timed Event'),
|
||||
(27409, 0, 9, 0, 59, 0, 100, 0, 1, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Ducal\'s Horse - On Timed Event 1 Triggered - Despawn Instant'),
|
||||
(27409, 0, 10, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Ducal\'s Horse - On Passenger Boarded - Remove Timed Event 1');
|
||||
@@ -0,0 +1,4 @@
|
||||
-- DB update 2025_09_07_00 -> 2025_09_09_00
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=45612;
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (45612, 'spell_necropolis_beam');
|
||||
@@ -0,0 +1,36 @@
|
||||
-- DB update 2025_09_09_00 -> 2025_09_09_01
|
||||
-- Update gameobject 'Meat Wagon' with sniffed values
|
||||
-- updated spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (193616, 193618, 193620)) AND (`guid` IN (62425, 62426, 62430, 62435, 62436, 62437));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(62425, 193616, 571, 0, 0, 1, 1, 6879.06787109375, 1607.7725830078125, 388.887359619140625, 3.612837791442871093, 0, 0, -0.97236919403076171, 0.233448356389999389, 120, 255, 1, "", 46368, NULL),
|
||||
(62426, 193616, 571, 0, 0, 1, 1, 6883.10888671875, 1600.4949951171875, 389.033172607421875, 0.506144583225250244, 0, 0, 0.250379562377929687, 0.968147754669189453, 120, 255, 1, "", 46368, NULL),
|
||||
(62430, 193618, 571, 0, 0, 1, 1, 6878.4189453125, 1602.437744140625, 389.033172607421875, 0.471238493919372558, 0, 0, 0.233445167541503906, 0.972369968891143798, 120, 255, 1, "", 46368, NULL),
|
||||
(62435, 193620, 571, 0, 0, 1, 1, 6881.7578125, 1604.779541015625, 388.380401611328125, 3.612837791442871093, 0, 0, -0.97236919403076171, 0.233448356389999389, 120, 255, 1, "", 46368, NULL),
|
||||
(62436, 193620, 571, 0, 0, 1, 1, 6896.3095703125, 1609.5350341796875, 388.3387451171875, 4.049167633056640625, 0, 0, -0.89879322052001953, 0.438372820615768432, 120, 255, 1, "", 46368, NULL),
|
||||
(62437, 193620, 571, 0, 0, 1, 1, 6886.94091796875, 1619.73095703125, 388.269287109375, 2.007128477096557617, 0, 0, 0.84339141845703125, 0.537299633026123046, 120, 255, 1, "", 46368, NULL);
|
||||
|
||||
-- new spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (193616, 193617, 193618, 193619, 193620)) AND (`guid` BETWEEN 2211 AND 2231);
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(2211, 193616, 571, 0, 0, 1, 1, 6876.56005859375, 1539.6214599609375, 389.033172607421875, 6.213373661041259765, 0, 0, -0.03489875793457031, 0.999390840530395507, 120, 255, 1, "", 46368, NULL),
|
||||
(2212, 193616, 571, 0, 0, 1, 1, 6880.126953125, 1540.478759765625, 389.033172607421875, 3.45575571060180664, 0, 0, -0.98768806457519531, 0.156436234712600708, 120, 255, 1, "", 46368, NULL),
|
||||
(2213, 193616, 571, 0, 0, 1, 1, 6883.654296875, 1540.2552490234375, 389.033172607421875, 1.134462952613830566, 0, 0, 0.537299156188964843, 0.843391716480255126, 120, 255, 1, "", 46368, NULL),
|
||||
(2214, 193616, 571, 0, 0, 1, 1, 6884.5859375, 1573.8497314453125, 389.033172607421875, 0.052358884364366531, 0, 0, 0.02617645263671875, 0.999657332897186279, 120, 255, 1, "", 46368, NULL),
|
||||
(2215, 193616, 571, 0, 0, 1, 1, 6884.59228515625, 1582.0037841796875, 389.033172607421875, 3.159062385559082031, 0, 0, -0.99996185302734375, 0.008734640665352344, 120, 255, 1, "", 46368, NULL),
|
||||
(2216, 193616, 571, 0, 0, 1, 1, 6888.81982421875, 1541.5426025390625, 389.033172607421875, 3.036838293075561523, 0, 0, 0.998628616333007812, 0.052353221923112869, 120, 255, 1, "", 46368, NULL),
|
||||
(2217, 193617, 571, 0, 0, 1, 1, 6875.7060546875, 1601.95068359375, 389.033172607421875, 3.612837791442871093, 0, 0, -0.97236919403076171, 0.233448356389999389, 120, 255, 1, "", 46368, NULL),
|
||||
(2218, 193617, 571, 0, 0, 1, 1, 6879.490234375, 1578.3424072265625, 389.033172607421875, 3.176533222198486328, 0, 0, -0.999847412109375, 0.017469281330704689, 120, 255, 1, "", 46368, NULL),
|
||||
(2219, 193617, 571, 0, 0, 1, 1, 6903.123046875, 1554.924072265625, 389.033172607421875, 2.286378860473632812, 0, 0, 0.909960746765136718, 0.414694398641586303, 120, 255, 1, "", 46368, NULL),
|
||||
(2220, 193617, 571, 0, 0, 1, 1, 6907.595703125, 1567.492919921875, 389.033172607421875, 6.161012649536132812, 0, 0, -0.06104850769042968, 0.998134791851043701, 120, 255, 1, "", 46368, NULL),
|
||||
(2221, 193617, 571, 0, 0, 1, 1, 6912.046875, 1560.1182861328125, 389.033203125, 1.291541695594787597, 0, 0, 0.60181427001953125, 0.798636078834533691, 120, 255, 1, "", 46368, NULL),
|
||||
(2222, 193618, 571, 0, 0, 1, 1, 6881.86181640625, 1578.113037109375, 389.033172607421875, 0.052358884364366531, 0, 0, 0.02617645263671875, 0.999657332897186279, 120, 255, 1, "", 46368, NULL),
|
||||
(2223, 193618, 571, 0, 0, 1, 1, 6906.19384765625, 1579.285400390625, 389.033172607421875, 0.610863447189331054, 0, 0, 0.3007049560546875, 0.953717231750488281, 120, 255, 1, "", 46368, NULL),
|
||||
(2224, 193618, 571, 0, 0, 1, 1, 6906.30126953125, 1589.4271240234375, 389.033172607421875, 1.151916384696960449, 0, 0, 0.544638633728027343, 0.838670849800109863, 120, 255, 1, "", 46368, NULL),
|
||||
(2225, 193619, 571, 0, 0, 1, 1, 6872.22021484375, 1602.7569580078125, 389.033172607421875, 3.682650327682495117, 0, 0, -0.96362972259521484, 0.26724100112915039, 120, 255, 1, "", 46368, NULL),
|
||||
(2226, 193619, 571, 0, 0, 1, 1, 6872.970703125, 1600.5621337890625, 389.033172607421875, 3.665196180343627929, 0, 0, -0.96592521667480468, 0.258821308612823486, 120, 255, 1, "", 46368, NULL),
|
||||
(2227, 193619, 571, 0, 0, 1, 1, 6874.19140625, 1598.2149658203125, 389.033172607421875, 3.665196180343627929, 0, 0, -0.96592521667480468, 0.258821308612823486, 120, 255, 1, "", 46368, NULL),
|
||||
(2228, 193619, 571, 0, 0, 1, 1, 6875.76220703125, 1577.950927734375, 389.033172607421875, 3.22885894775390625, 0, 0, -0.99904823303222656, 0.043619260191917419, 120, 255, 1, "", 46368, NULL),
|
||||
(2229, 193619, 571, 0, 0, 1, 1, 6875.81689453125, 1580.9786376953125, 389.033172607421875, 3.106652259826660156, 0, 0, 0.999847412109375, 0.017469281330704689, 120, 255, 1, "", 46368, NULL),
|
||||
(2230, 193619, 571, 0, 0, 1, 1, 6876.02099609375, 1575.36083984375, 389.033172607421875, 3.333590030670166015, 0, 0, -0.99539566040039062, 0.095851235091686248, 120, 255, 1, "", 46368, NULL),
|
||||
(2231, 193620, 571, 0, 0, 1, 1, 6885.62060546875, 1578.173583984375, 388.435943603515625, 3.176533222198486328, 0, 0, -0.999847412109375, 0.017469281330704689, 120, 255, 1, "", 46368, NULL);
|
||||
@@ -0,0 +1,8 @@
|
||||
-- DB update 2025_09_09_01 -> 2025_09_09_02
|
||||
-- Update gameobject 'Death's Gaze Orb' with sniffed values
|
||||
-- new spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (192917)) AND (`guid` IN (174, 175, 176));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(174, 192917, 571, 0, 0, 1, 1, 6475.67822265625, 3399.67529296875, 599.08349609375, 2.059488296508789062, 0, 0, 0.857167243957519531, 0.515038192272186279, 120, 255, 1, "", 46368, NULL),
|
||||
(175, 192917, 571, 0, 0, 1, 1, 6514.7314453125, 3273.22216796875, 667.54388427734375, 3.926995515823364257, 0, 0, -0.92387866973876953, 0.38268551230430603, 120, 255, 1, "", 46368, NULL),
|
||||
(176, 192917, 571, 0, 0, 1, 1, 6705.81982421875, 3528.986328125, 673.74957275390625, 0.715584874153137207, 0, 0, 0.350207328796386718, 0.936672210693359375, 120, 255, 1, "", 46368, NULL);
|
||||
@@ -0,0 +1,25 @@
|
||||
-- DB update 2025_09_09_02 -> 2025_09_09_03
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=48297;
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (48297, 'spell_handover_reins');
|
||||
|
||||
DELETE FROM `vehicle_seat_addon` WHERE `SeatEntry`=742;
|
||||
INSERT INTO `vehicle_seat_addon` (`SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue`) VALUES
|
||||
(742, 0, 0, -2, 0, 0, 1);
|
||||
|
||||
-- Set Phase from 5 to 1 for id 2
|
||||
-- Generate comments with Keira
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 27213);
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(27213, 0, 0, 1, 11, 0, 100, 512, 0, 0, 0, 0, 0, 0, 211, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Respawn - Flag reset 0'),
|
||||
(27213, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Respawn - Set Event Phase 1'),
|
||||
(27213, 0, 2, 3, 28, 1, 100, 512, 0, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Passenger Removed - Set Event Phase 2 (Phase 1)'),
|
||||
(27213, 0, 3, 4, 61, 2, 100, 512, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Passenger Removed - Set Home Position (Phase 1)'),
|
||||
(27213, 0, 4, 5, 61, 2, 100, 512, 0, 0, 0, 0, 0, 0, 2, 35, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Passenger Removed - Set Faction 35 (Phase 1)'),
|
||||
(27213, 0, 5, 6, 61, 2, 100, 512, 0, 0, 0, 0, 0, 0, 18, 131072, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Passenger Removed - Set Flags Pacified (Phase 1)'),
|
||||
(27213, 0, 6, 0, 61, 2, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2721300, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Passenger Removed - Run Script (Phase 1)'),
|
||||
(27213, 0, 7, 0, 59, 2, 100, 512, 1, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Timed Event 1 Triggered - Despawn Instant (Phase 2)'),
|
||||
(27213, 0, 8, 9, 23, 2, 100, 512, 48290, 1, 500, 500, 0, 0, 74, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Aura \'Onslaught Riding Crop\' - Remove Timed Event 1 (Phase 2)'),
|
||||
(27213, 0, 9, 0, 61, 2, 100, 512, 0, 0, 0, 0, 0, 0, 22, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Aura \'Onslaught Riding Crop\' - Set Event Phase 3 (Phase 2)'),
|
||||
(27213, 0, 10, 11, 31, 4, 100, 513, 48297, 0, 0, 0, 0, 0, 22, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Target Spellhit \'Hand Over Reins\' - Set Event Phase 4 (Phase 3) (No Repeat)'),
|
||||
(27213, 0, 11, 0, 61, 8, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2721301, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Onslaught Warhorse - On Target Spellhit \'Hand Over Reins\' - Run Script (Phase 3) (No Repeat)');
|
||||
@@ -0,0 +1,3 @@
|
||||
-- DB update 2025_09_09_03 -> 2025_09_09_04
|
||||
UPDATE `creature_template_addon` SET `auras` = '19818 34623' WHERE `entry` = 18733;
|
||||
UPDATE `creature_addon` SET `visibilityDistanceType` = 5, `auras` = '19818 34623' WHERE `guid` IN (67001, 203341);
|
||||
@@ -0,0 +1,7 @@
|
||||
-- DB update 2025_09_09_04 -> 2025_09_09_05
|
||||
--
|
||||
UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 29978;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29984) AND (`source_type` = 0) AND (`id` = 0);
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29978) AND (`source_type` = 0);
|
||||
@@ -0,0 +1,6 @@
|
||||
-- DB update 2025_09_09_05 -> 2025_09_10_00
|
||||
--
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 18) AND (`SourceGroup` = 25334) AND (`SourceEntry` IN (47917, 46598)) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 9) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 11652) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(18, 25334, 47917, 0, 0, 9, 0, 11652, 0, 0, 0, 0, 0, '', 'Horde Siege Tank requires player to be on quest The Plains of Nasam'),
|
||||
(18, 25334, 46598, 0, 0, 9, 0, 11652, 0, 0, 0, 0, 0, '', 'Horde Siege Tank requires player to be on quest The Plains of Nasam');
|
||||
@@ -0,0 +1,51 @@
|
||||
-- DB update 2025_09_10_00 -> 2025_09_10_01
|
||||
-- Update gameobject 'Weapon Rack' with sniffed values
|
||||
-- updated spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (181627, 183269, 183991, 105172, 105171, 105170, 105169, 188659)) AND (`guid` IN (11420, 24123, 24845, 24846, 45165, 45166, 45167, 45168, 61365, 61366, 61367, 61368, 61369, 61370, 61371, 61372, 61373, 61374, 61375, 61376, 61377, 61378, 61379, 61380, 61381, 61382, 61383, 61384, 61385, 61386));
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(11420, 181627, 0, 0, 0, 1, 1, -6335.33544921875, -3115.09375, 299.723052978515625, 0.907570242881774902, 0, 0, 0.438370704650878906, 0.898794233798980712, 120, 255, 1, "", 48120, NULL),
|
||||
(24123, 183269, 530, 0, 0, 1, 1, 2228.34716796875, 2312.203125, 89.11359405517578125, 2.321285009384155273, -0.00742387771606445, -0.15768909454345703, 0.902186393737792968, 0.401420950889587402, 120, 255, 1, "", 45704, NULL),
|
||||
(24845, 183991, 530, 0, 0, 1, 1, -596.56427001953125, 2914.64013671875, 59.21495437622070312, 3.543023586273193359, 0, 0, -0.97992420196533203, 0.199370384216308593, 120, 255, 1, "", 45854, NULL),
|
||||
(24846, 183991, 530, 0, 0, 1, 1, -584.88446044921875, 2896.530029296875, 59.20400619506835937, 3.700104713439941406, 0, 0, -0.96126079559326171, 0.275640487670898437, 120, 255, 1, "", 45854, NULL),
|
||||
(45165, 105172, 0, 0, 0, 1, 1, 3023.028564453125, 653.81402587890625, 75.34989166259765625, 1.553341388702392578, 0, 0, 0.700908660888671875, 0.713251054286956787, 120, 255, 1, "", 46779, NULL),
|
||||
(45166, 105171, 0, 0, 0, 1, 1, 3019.9033203125, 688.79742431640625, 66.45070648193359375, 4.747295856475830078, 0, 0, -0.69465827941894531, 0.719339847564697265, 120, 255, 1, "", 46779, NULL),
|
||||
(45167, 105170, 0, 0, 0, 1, 1, 3063.673583984375, 697.9215087890625, 66.45069122314453125, 3.211419343948364257, 0, 0, -0.9993906021118164, 0.034906134009361267, 120, 255, 1, "", 46779, NULL),
|
||||
(45168, 105169, 0, 0, 0, 1, 1, 3058.616455078125, 653.5849609375, 58.1085205078125, 3.996806621551513671, 0, 0, -0.90996074676513671, 0.414694398641586303, 120, 255, 1, "", 46779, NULL),
|
||||
(61365, 188659, 571, 0, 0, 1, 1, 2953.047119140625, -451.505218505859375, 140.7652130126953125, 5.794494152069091796, 0, 0, -0.24192142486572265, 0.970295846462249755, 120, 255, 1, "", 46158, NULL),
|
||||
(61366, 188659, 571, 0, 0, 1, 1, 2832.775390625, -279.4259033203125, 136.0123291015625, 2.426007747650146484, 0, 0, 0.936672210693359375, 0.350207358598709106, 120, 255, 1, "", 45942, NULL),
|
||||
(61367, 188659, 571, 0, 0, 1, 1, 2741.550537109375, -114.055442810058593, 115.7203216552734375, 6.195919513702392578, 0, 0, -0.04361915588378906, 0.999048233032226562, 120, 255, 1, "", 46158, NULL),
|
||||
(61368, 188659, 571, 0, 0, 1, 1, 2834.82958984375, -531.0296630859375, 121.3561477661132812, 4.48549652099609375, 0, 0, -0.7826080322265625, 0.622514784336090087, 120, 255, 1, "", 45942, NULL),
|
||||
(61369, 188659, 571, 0, 0, 1, 1, 2782.08203125, -188.334426879882812, 139.139404296875, 3.577930212020874023, 0, 0, -0.97629547119140625, 0.216442063450813293, 120, 255, 1, "", 46158, NULL),
|
||||
(61370, 188659, 571, 0, 0, 1, 1, 2809.780029296875, -324.545013427734375, 130.2048797607421875, 3.78736734390258789, 0, 0, -0.94832324981689453, 0.317305892705917358, 120, 255, 1, "", 46158, NULL),
|
||||
(61371, 188659, 571, 0, 0, 1, 1, 2928.7626953125, -353.397918701171875, 112.4615936279296875, 2.932138919830322265, 0, 0, 0.994521141052246093, 0.104535527527332305, 120, 255, 1, "", 45942, NULL),
|
||||
(61372, 188659, 571, 0, 0, 1, 1, 2878.55908203125, -431.913116455078125, 118.3675765991210937, 3.9793548583984375, 0, 0, -0.9135446548461914, 0.406738430261611938, 120, 255, 1, "", 45942, NULL),
|
||||
(61373, 188659, 571, 0, 0, 1, 1, 2883.435546875, -373.7969970703125, 112.4618301391601562, 3.9793548583984375, 0, 0, -0.9135446548461914, 0.406738430261611938, 120, 255, 1, "", 46158, NULL),
|
||||
(61374, 188659, 571, 0, 0, 1, 1, 2858.78125, -276.4066162109375, 114.0344467163085937, 1.553341388702392578, 0, 0, 0.700908660888671875, 0.713251054286956787, 120, 255, 1, "", 45942, NULL),
|
||||
(61375, 188659, 571, 0, 0, 1, 1, 2864.294189453125, -278.00445556640625, 122.8568801879882812, 1.570795774459838867, 0, 0, 0.707106590270996093, 0.707106947898864746, 120, 255, 1, "", 45942, NULL),
|
||||
(61376, 188659, 571, 0, 0, 1, 1, 2883.530029296875, -296.61376953125, 114.0345230102539062, 3.071766138076782226, 0, 0, 0.999390602111816406, 0.034906134009361267, 120, 255, 1, "", 46158, NULL),
|
||||
(61377, 188659, 571, 0, 0, 1, 1, 2891.976318359375, -294.088714599609375, 122.85626220703125, 3.106652259826660156, 0, 0, 0.999847412109375, 0.017469281330704689, 120, 255, 1, "", 45942, NULL),
|
||||
(61378, 188659, 571, 0, 0, 1, 1, 2889.322998046875, -290.53131103515625, 106.8801422119140625, 3.106652259826660156, 0, 0, 0.999847412109375, 0.017469281330704689, 120, 255, 1, "", 45942, NULL),
|
||||
(61379, 188659, 571, 0, 0, 1, 1, 2901.346923828125, -320.123565673828125, 114.0344924926757812, 1.535889506340026855, 0, 0, 0.694658279418945312, 0.719339847564697265, 120, 255, 1, "", 45942, NULL),
|
||||
(61380, 188659, 571, 0, 0, 1, 1, 2912.576416015625, -281.989471435546875, 138.0604248046875, 3.124123096466064453, 0, 0, 0.99996185302734375, 0.008734640665352344, 120, 255, 1, "", 45942, NULL),
|
||||
(61381, 188659, 571, 0, 0, 1, 1, 2968.82080078125, -444.152923583984375, 125.9091415405273437, 1.780233979225158691, 0, 0, 0.7771453857421875, 0.629321098327636718, 120, 255, 1, "", 45942, NULL),
|
||||
(61382, 188659, 571, 0, 0, 1, 1, 2942.835205078125, -348.2596435546875, 114.6573333740234375, 4.555310726165771484, 0, 0, -0.76040554046630859, 0.649448513984680175, 120, 255, 1, "", 45942, NULL),
|
||||
(61383, 188659, 571, 0, 0, 1, 1, 2929.404052734375, -332.448272705078125, 113.43121337890625, 4.572763919830322265, 0, 0, -0.75470924377441406, 0.656059443950653076, 120, 255, 1, "", 45942, NULL),
|
||||
(61384, 188659, 571, 0, 0, 1, 1, 2757.970458984375, -180.418655395507812, 138.998748779296875, 0.959929943084716796, 0, 0, 0.461748123168945312, 0.887011110782623291, 120, 255, 1, "", 46158, NULL),
|
||||
(61385, 188659, 571, 0, 0, 1, 1, 2697.780517578125, -200.24945068359375, 140.154632568359375, 1.570795774459838867, 0, 0, 0.707106590270996093, 0.707106947898864746, 120, 255, 1, "", 46158, NULL),
|
||||
(61386, 188659, 571, 0, 0, 1, 1, 2731.54833984375, -241.892257690429687, 141.5568389892578125, 2.199114561080932617, 0, 0, 0.8910064697265625, 0.453990638256072998, 120, 255, 1, "", 46158, NULL);
|
||||
|
||||
-- new spawns
|
||||
DELETE FROM `gameobject` WHERE (`id` IN (188426, 188659)) AND (`guid` BETWEEN 939 AND 947);
|
||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES
|
||||
(939, 188426, 571, 0, 0, 1, 1, 2608.928955078125, 5263.6396484375, 39.4164886474609375, 1.239183306694030761, 0, 0, 0.580702781677246093, 0.814115643501281738, 120, 255, 1, "", 49345, NULL),
|
||||
(940, 188426, 571, 0, 0, 1, 1, 2611.096923828125, 5260.75732421875, 39.40889358520507812, 2.164205789566040039, 0, 0, 0.882946968078613281, 0.469472706317901611, 120, 255, 1, "", 49345, NULL),
|
||||
(941, 188426, 571, 0, 0, 1, 1, 2614.411376953125, 5258.751953125, 39.40840911865234375, 3.665196180343627929, 0, 0, -0.96592521667480468, 0.258821308612823486, 120, 255, 1, "", 49345, NULL),
|
||||
(942, 188426, 571, 0, 0, 1, 1, 2615.94189453125, 5267.6845703125, 39.4207000732421875, 5.462882041931152343, 0, 0, -0.39874839782714843, 0.917060375213623046, 120, 255, 1, "", 49345, NULL),
|
||||
(943, 188426, 571, 0, 0, 1, 1, 2623.84375, 5255.21875, 38.28279876708984375, 0.750490784645080566, 0, 0, 0.3665008544921875, 0.93041771650314331, 120, 255, 1, "", 49345, NULL),
|
||||
(944, 188659, 571, 0, 0, 1, 1, 2444.703125, -394.670135498046875, 7.966825008392333984, 0.034906249493360519, 0, 0, 0.017452239990234375, 0.999847710132598876, 120, 255, 1, "", 46158, NULL),
|
||||
(945, 188659, 571, 0, 0, 1, 1, 2477.215576171875, -350.638916015625, 1.422237038612365722, 0.820303261280059814, 0, 0, 0.398748397827148437, 0.917060375213623046, 120, 255, 1, "", 46158, NULL),
|
||||
(946, 188659, 571, 0, 0, 1, 1, 2622.64111328125, -264.823455810546875, 2.252971887588500976, 4.066620349884033203, 0, 0, -0.89493370056152343, 0.44619917869567871, 120, 255, 1, "", 45854, NULL),
|
||||
(947, 188659, 571, 0, 0, 1, 1, 2684.013427734375, -485.452423095703125, 50.89562606811523437, 3.595378875732421875, 0, 0, -0.97437000274658203, 0.224951311945915222, 120, 255, 1, "", 45854, NULL);
|
||||
|
||||
-- remaining spawns (no sniffed values available)
|
||||
-- (`guid` IN (99937))
|
||||
@@ -0,0 +1,14 @@
|
||||
-- DB update 2025_09_10_01 -> 2025_09_10_02
|
||||
--
|
||||
DELETE FROM `creature_template_addon` WHERE `entry`=29854;
|
||||
INSERT INTO `creature_template_addon` (`entry`,`path_id`,`bytes1`,`mount`,`auras`) VALUES
|
||||
(29854,0,1,0, '');
|
||||
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 56393);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(13, 1, 56393, 0, 0, 31, 0, 3, 29854, 0, 0, 0, 0, '', 'Feed Stormcrest Eagle target Stormcrest Eagle'),
|
||||
(13, 1, 56393, 0, 0, 1, 0, 56393, 0, 0, 1, 0, 0, '', 'Feed Stormcrest Eagle target must not have Feed Stormcrest Eagle aura');
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` = 56393;
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(56393, 'spell_feed_stormcrest_eagle');
|
||||
Vendored
+19
-17
@@ -94,11 +94,11 @@ function Joiner:add_repo() (
|
||||
basedir="${4:-""}"
|
||||
|
||||
[[ -z $url ]] && hasReq=false || hasReq=true
|
||||
Joiner:_help $hasReq "$1" "Syntax: joiner.sh add-repo [-d] [-e] url name branch [basedir]"
|
||||
Joiner:_help "$hasReq" "$1" "Syntax: joiner.sh add-repo [-d] [-e] url name branch [basedir]"
|
||||
|
||||
# retrieving info from url if not set
|
||||
if [[ -z $name ]]; then
|
||||
basename=$(basename $url)
|
||||
basename=$(basename "$url")
|
||||
name=${basename%%.*}
|
||||
|
||||
if [[ -z "$basedir" ]]; then
|
||||
@@ -115,10 +115,12 @@ function Joiner:add_repo() (
|
||||
|
||||
if [ -e "$path/.git/" ]; then
|
||||
# if exists , update
|
||||
git --git-dir="$path/.git/" rev-parse && git --git-dir="$path/.git/" pull origin $branch | grep 'Already up-to-date.' && changed="no" || true
|
||||
echo "Updating $name on branch $branch..."
|
||||
git --git-dir="$path/.git/" --work-tree="$path" rev-parse && git --git-dir="$path/.git/" --work-tree="$path" pull origin "$branch" | grep 'Already up-to-date.' && changed="no" || true
|
||||
else
|
||||
# otherwise clone
|
||||
git clone $url -c advice.detachedHead=0 -b $branch "$path"
|
||||
echo "Cloning $name on branch $branch..."
|
||||
git clone "$url" -c advice.detachedHead=0 -b "$branch" "$path"
|
||||
fi
|
||||
|
||||
if [ "$?" -ne "0" ]; then
|
||||
@@ -140,16 +142,16 @@ function Joiner:add_git_submodule() (
|
||||
basedir=${4:-""}
|
||||
|
||||
[[ -z $url ]] && hasReq=false || hasReq=true
|
||||
Joiner:_help $hasReq "$1" "Syntax: joiner.sh add-git-submodule [-d] [-e] url name branch [basedir]"
|
||||
Joiner:_help "$hasReq" "$1" "Syntax: joiner.sh add-git-submodule [-d] [-e] url name branch [basedir]"
|
||||
|
||||
# retrieving info from url if not set
|
||||
if [[ -z $name ]]; then
|
||||
basename=$(basename $url)
|
||||
basename=$(basename "$url")
|
||||
name=${basename%%.*}
|
||||
|
||||
if [[ -z $basedir ]]; then
|
||||
dir=$(dirname $url)
|
||||
basedir=$(basename $dir)
|
||||
dir=$(dirname "$url")
|
||||
basedir=$(basename "$dir")
|
||||
fi
|
||||
|
||||
name="${name,,}" #to lowercase
|
||||
@@ -158,17 +160,17 @@ function Joiner:add_git_submodule() (
|
||||
|
||||
path="$J_PATH_MODULES/$basedir/$name"
|
||||
valid_path=`Joiner:_searchFirstValiPath "$path"`
|
||||
rel_path=${path#$valid_path}
|
||||
rel_path=${path#"$valid_path"}
|
||||
rel_path=${rel_path#/}
|
||||
|
||||
if [ -e $path/ ]; then
|
||||
if [ -e "$path/" ]; then
|
||||
# if exists , update
|
||||
(cd "$path" && git pull origin $branch)
|
||||
(cd "$valid_path" && git submodule update -f --init $rel_path)
|
||||
(cd "$path" && git pull origin "$branch")
|
||||
(cd "$valid_path" && git submodule update -f --init "$rel_path")
|
||||
else
|
||||
# otherwise add
|
||||
(cd "$valid_path" && git submodule add -f -b $branch $url $rel_path)
|
||||
(cd "$valid_path" && git submodule update -f --init $rel_path)
|
||||
(cd "$valid_path" && git submodule add -f -b "$branch" "$url" "$rel_path")
|
||||
(cd "$valid_path" && git submodule update -f --init "$rel_path")
|
||||
fi
|
||||
|
||||
if [ "$?" -ne "0" ]; then
|
||||
@@ -324,7 +326,7 @@ function Joiner:self_update() {
|
||||
if [ ! -z "$J_VER_REQ" ]; then
|
||||
# if J_VER_REQ is defined then update only if tag is different
|
||||
_cur_branch=`git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" rev-parse --abbrev-ref HEAD`
|
||||
_cur_ver=`git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" name-rev --tags --name-only $_cur_branch`
|
||||
_cur_ver=`git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" name-rev --tags --name-only "$_cur_branch"`
|
||||
if [ "$_cur_ver" != "$J_VER_REQ" ]; then
|
||||
git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" rev-parse && git --git-dir="$J_PATH/.git/" fetch --tags origin "$_cur_branch" --quiet
|
||||
git --git-dir="$J_PATH/.git/" --work-tree="$J_PATH/" checkout "tags/$J_VER_REQ" -b "$_cur_branch"
|
||||
@@ -416,8 +418,8 @@ function Joiner:menu() {
|
||||
while true
|
||||
do
|
||||
# run option directly if specified in argument
|
||||
[ ! -z $1 ] && _switch $@
|
||||
[ ! -z $1 ] && exit 0
|
||||
[ ! -z "$1" ] && _switch $@
|
||||
[ ! -z "$1" ] && exit 0
|
||||
|
||||
echo ""
|
||||
echo "==== JOINER MENU ===="
|
||||
|
||||
Vendored
+2
-1
@@ -31,7 +31,8 @@ else()
|
||||
set(BOOST_REQUIRED_VERSION 1.74)
|
||||
endif()
|
||||
|
||||
find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED system filesystem program_options iostreams regex thread)
|
||||
# Boost.System is header-only since 1.69; do not require it explicitly.
|
||||
find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED COMPONENTS filesystem program_options iostreams regex thread)
|
||||
|
||||
if(NOT Boost_FOUND)
|
||||
if(NOT DEFINED ENV{Boost_ROOT} AND NOT DEFINED Boost_DIR AND NOT DEFINED BOOST_ROOT AND NOT DEFINED BOOSTROOT)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "Dynamic/TypeList.h"
|
||||
#include "GridRefMgr.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
* @class ContainerMapList is a mulit-type container for map elements
|
||||
@@ -50,6 +51,24 @@ struct ContainerMapList<TypeList<H, T>>
|
||||
ContainerMapList<T> _TailElements;
|
||||
};
|
||||
|
||||
template<class OBJECT>
|
||||
struct ContainerVector
|
||||
{
|
||||
std::vector<OBJECT*> _element;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ContainerVector<TypeNull>
|
||||
{
|
||||
};
|
||||
|
||||
template<class H, class T>
|
||||
struct ContainerVector<TypeList<H, T>>
|
||||
{
|
||||
ContainerVector<H> _elements;
|
||||
ContainerVector<T> _TailElements;
|
||||
};
|
||||
|
||||
template<class OBJECT, class KEY_TYPE>
|
||||
struct ContainerUnorderedMap
|
||||
{
|
||||
@@ -123,6 +142,33 @@ private:
|
||||
ContainerMapList<OBJECT_TYPES> i_elements;
|
||||
};
|
||||
|
||||
template<class OBJECT_TYPES>
|
||||
class TypeVectorContainer
|
||||
{
|
||||
public:
|
||||
template<class SPECIFIC_TYPE> [[nodiscard]] std::size_t Count() const { return Acore::Count(i_elements, (SPECIFIC_TYPE*)nullptr); }
|
||||
|
||||
template<class SPECIFIC_TYPE>
|
||||
bool Insert(SPECIFIC_TYPE* obj)
|
||||
{
|
||||
SPECIFIC_TYPE* t = Acore::Insert(i_elements, obj);
|
||||
return (t != nullptr);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE>
|
||||
bool Remove(SPECIFIC_TYPE* obj)
|
||||
{
|
||||
SPECIFIC_TYPE* t = Acore::Remove(i_elements, obj);
|
||||
return (t != nullptr);
|
||||
}
|
||||
|
||||
ContainerVector<OBJECT_TYPES>& GetElements() { return i_elements; }
|
||||
[[nodiscard]] const ContainerVector<OBJECT_TYPES>& GetElements() const { return i_elements; }
|
||||
|
||||
private:
|
||||
ContainerVector<OBJECT_TYPES> i_elements;
|
||||
};
|
||||
|
||||
template<class OBJECT_TYPES, class KEY_TYPE>
|
||||
class TypeUnorderedMapContainer
|
||||
{
|
||||
|
||||
@@ -239,5 +239,101 @@ namespace Acore
|
||||
// SPECIFIC_TYPE* t = Remove(elements._elements, obj);
|
||||
// return ( t != nullptr ? t : Remove(elements._TailElements, obj));
|
||||
//}
|
||||
|
||||
/* ContainerVector Helpers */
|
||||
// count functions
|
||||
template<class SPECIFIC_TYPE>
|
||||
std::size_t Count(const ContainerVector<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE* /*fake*/)
|
||||
{
|
||||
return elements._element.getSize();
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE>
|
||||
std::size_t Count(const ContainerVector<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*fake*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE, class T>
|
||||
std::size_t Count(const ContainerVector<T>& /*elements*/, SPECIFIC_TYPE* /*fake*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE, class T>
|
||||
std::size_t Count(const ContainerVector<TypeList<SPECIFIC_TYPE, T>>& elements, SPECIFIC_TYPE* fake)
|
||||
{
|
||||
return Count(elements._elements, fake);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE, class H, class T>
|
||||
std::size_t Count(const ContainerVector<TypeList<H, T>>& elements, SPECIFIC_TYPE* fake)
|
||||
{
|
||||
return Count(elements._TailElements, fake);
|
||||
}
|
||||
|
||||
// non-const insert functions
|
||||
template<class SPECIFIC_TYPE>
|
||||
SPECIFIC_TYPE* Insert(ContainerVector<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE* obj)
|
||||
{
|
||||
elements._element.push_back(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE>
|
||||
SPECIFIC_TYPE* Insert(ContainerVector<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// this is a missed
|
||||
template<class SPECIFIC_TYPE, class T>
|
||||
SPECIFIC_TYPE* Insert(ContainerVector<T>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
|
||||
{
|
||||
return nullptr; // a missed
|
||||
}
|
||||
|
||||
// Recursion
|
||||
template<class SPECIFIC_TYPE, class H, class T>
|
||||
SPECIFIC_TYPE* Insert(ContainerVector<TypeList<H, T>>& elements, SPECIFIC_TYPE* obj)
|
||||
{
|
||||
SPECIFIC_TYPE* t = Insert(elements._elements, obj);
|
||||
return (t != nullptr ? t : Insert(elements._TailElements, obj));
|
||||
}
|
||||
|
||||
// non-const remove method
|
||||
template<class SPECIFIC_TYPE> SPECIFIC_TYPE* Remove(ContainerVector<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE *obj)
|
||||
{
|
||||
// Simple vector find/swap/pop, this container should be very lightly used
|
||||
// so I don't suspect the linear search complexity to be an issue
|
||||
auto itr = std::find(elements._element.begin(), elements._element.end(), obj);
|
||||
if (itr != elements._element.end())
|
||||
{
|
||||
// Swap the element to be removed with the last element
|
||||
std::swap(*itr, elements._element.back());
|
||||
|
||||
// Remove the last element (which is now the element we wanted to remove)
|
||||
elements._element.pop_back();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE> SPECIFIC_TYPE* Remove(ContainerVector<TypeNull> &/*elements*/, SPECIFIC_TYPE * /*obj*/)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// this is a missed
|
||||
template<class SPECIFIC_TYPE, class T> SPECIFIC_TYPE* Remove(ContainerVector<T> &/*elements*/, SPECIFIC_TYPE * /*obj*/)
|
||||
{
|
||||
return nullptr; // a missed
|
||||
}
|
||||
|
||||
template<class SPECIFIC_TYPE, class T, class H> SPECIFIC_TYPE* Remove(ContainerVector<TypeList<H, T> > &elements, SPECIFIC_TYPE *obj)
|
||||
{
|
||||
// The head element is bad
|
||||
SPECIFIC_TYPE* t = Remove(elements._elements, obj);
|
||||
return ( t != nullptr ? t : Remove(elements._TailElements, obj));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -56,6 +56,27 @@ template<class VISITOR, class OBJECT_TYPES> void VisitorHelper(VISITOR& v, TypeM
|
||||
VisitorHelper(v, c.GetElements());
|
||||
}
|
||||
|
||||
// VectorContainer
|
||||
template<class VISITOR> void VisitorHelper(VISITOR& /*v*/, ContainerVector<TypeNull>& /*c*/) {}
|
||||
|
||||
template<class VISITOR, class T> void VisitorHelper(VISITOR& v, ContainerVector<T>& c)
|
||||
{
|
||||
v.Visit(c._element);
|
||||
}
|
||||
|
||||
// recursion container map list
|
||||
template<class VISITOR, class H, class T> void VisitorHelper(VISITOR& v, ContainerVector<TypeList<H, T>>& c)
|
||||
{
|
||||
VisitorHelper(v, c._elements);
|
||||
VisitorHelper(v, c._TailElements);
|
||||
}
|
||||
|
||||
// for TypeMapContainer
|
||||
template<class VISITOR, class OBJECT_TYPES> void VisitorHelper(VISITOR& v, TypeVectorContainer<OBJECT_TYPES>& c)
|
||||
{
|
||||
VisitorHelper(v, c.GetElements());
|
||||
}
|
||||
|
||||
// TypeUnorderedMapContainer
|
||||
template<class VISITOR, class KEY_TYPE>
|
||||
void VisitorHelper(VISITOR& /*v*/, ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*c*/) { }
|
||||
|
||||
@@ -353,8 +353,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_ALL_AT_LOGIN_FLAGS, "UPDATE characters SET at_login = at_login | ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_BUG_REPORT, "INSERT INTO bugreport (type, content) VALUES(?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petitionguid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petitionguid, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petition_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petition_id, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHAR_OFFLINE, "UPDATE characters SET online = 0 WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_GROUP, "INSERT INTO `groups` (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raidDifficulty, masterLooterGuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
@@ -457,9 +457,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_INS_CHAR_GIFT, "INSERT INTO character_gifts (guid, item_guid, entry, flags) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_INSTANCE_BY_INSTANCE, "DELETE FROM instance WHERE id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_MAIL_ITEM_BY_ID, "DELETE FROM mail_items WHERE mail_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PETITION, "INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_BY_GUID, "DELETE FROM petition WHERE petitionguid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_GUID, "DELETE FROM petition_sign WHERE petitionguid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_PETITION, "INSERT INTO petition (petition_id, ownerguid, petitionguid, name, type) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_BY_ID, "DELETE FROM petition WHERE petition_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_ID, "DELETE FROM petition_sign WHERE petition_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_DECLINED_NAME, "DELETE FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_DECLINED_NAME, "INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHAR_RACE, "UPDATE characters SET race = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
@@ -382,8 +382,8 @@ enum CharacterDatabaseStatements : uint32
|
||||
CHAR_DEL_INSTANCE_BY_INSTANCE,
|
||||
CHAR_DEL_MAIL_ITEM_BY_ID,
|
||||
CHAR_INS_PETITION,
|
||||
CHAR_DEL_PETITION_BY_GUID,
|
||||
CHAR_DEL_PETITION_SIGNATURE_BY_GUID,
|
||||
CHAR_DEL_PETITION_BY_ID,
|
||||
CHAR_DEL_PETITION_SIGNATURE_BY_ID,
|
||||
CHAR_DEL_CHAR_DECLINED_NAME,
|
||||
CHAR_INS_CHAR_DECLINED_NAME,
|
||||
CHAR_UPD_CHAR_RACE,
|
||||
|
||||
@@ -660,6 +660,7 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
if (me->GetCharmerGUID().IsPlayer() || me->HasUnitFlag(UNIT_FLAG_POSSESSED))
|
||||
{
|
||||
me->AttackStop();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_IN_COMBAT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3834,19 +3834,20 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
{
|
||||
targets.clear();
|
||||
|
||||
if (owner->ToCreature())
|
||||
if (IsCreature(owner))
|
||||
{
|
||||
if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->ToCreature()->GetCharmerOrOwnerGUID()))
|
||||
{
|
||||
targets.push_back(base);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (IsGameObject(owner))
|
||||
{
|
||||
if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->ToGameObject()->GetOwnerGUID()))
|
||||
{
|
||||
targets.push_back(base);
|
||||
}
|
||||
}
|
||||
else if (IsPlayer(owner))
|
||||
{
|
||||
if (Unit* base = owner->ToPlayer()->GetCharmerOrOwner())
|
||||
targets.push_back(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,8 +361,9 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z, uint32 move_type)
|
||||
if (member == m_leader || !member->IsAlive() || member->GetVictim() || !pFormationInfo.HasGroupFlag(std::underlying_type_t<GroupAIFlags>(GroupAIFlags::GROUP_AI_FLAG_FOLLOW_LEADER)))
|
||||
continue;
|
||||
|
||||
// Xinef: If member is stunned / rooted etc don't allow to move him
|
||||
if (member->HasUnitState(UNIT_STATE_NOT_MOVE))
|
||||
// If member is stunned / rooted etc don't allow to move him
|
||||
// Or if charmed/controlled
|
||||
if (member->HasUnitState(UNIT_STATE_NOT_MOVE) || member->isPossessed() || member->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
|
||||
continue;
|
||||
|
||||
// Xinef: this should be automatized, if turn angle is greater than PI/2 (90�) we should swap formation angle
|
||||
|
||||
@@ -431,15 +431,11 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
||||
|
||||
// Check if GameObject is Large
|
||||
if (goinfo->IsLargeGameObject())
|
||||
{
|
||||
SetVisibilityDistanceOverride(VisibilityDistanceType::Large);
|
||||
}
|
||||
|
||||
// Check if GameObject is Infinite
|
||||
if (goinfo->IsInfiniteGameObject())
|
||||
{
|
||||
SetVisibilityDistanceOverride(VisibilityDistanceType::Infinite);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -629,6 +629,8 @@ struct GameObjectTemplate
|
||||
return true;
|
||||
case GAMEOBJECT_TYPE_TRAPDOOR:
|
||||
return true;
|
||||
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1037,7 +1037,7 @@ void MovementInfo::OutDebug()
|
||||
}
|
||||
|
||||
WorldObject::WorldObject() : WorldLocation(),
|
||||
LastUsedScriptID(0), m_name(""), m_isActive(false), m_visibilityDistanceOverride(), m_zoneScript(nullptr),
|
||||
LastUsedScriptID(0), m_name(""), m_isActive(false), _visibilityDistanceOverrideType(VisibilityDistanceType::Normal), m_zoneScript(nullptr),
|
||||
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
|
||||
m_currMap(nullptr), _heartbeatTimer(HEARTBEAT_INTERVAL), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true),
|
||||
m_notifyflags(0), m_executed_notifies(0), _objectVisibilityContainer(this)
|
||||
@@ -1082,15 +1082,36 @@ void WorldObject::setActive(bool on)
|
||||
map->AddObjectToPendingUpdateList(this);
|
||||
}
|
||||
|
||||
float WorldObject::GetVisibilityOverrideDistance() const
|
||||
{
|
||||
ASSERT(_visibilityDistanceOverrideType < VisibilityDistanceType::Max);
|
||||
return VisibilityDistances[AsUnderlyingType(_visibilityDistanceOverrideType)];
|
||||
}
|
||||
|
||||
void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type)
|
||||
{
|
||||
ASSERT(type < VisibilityDistanceType::Max);
|
||||
if (IsPlayer())
|
||||
{
|
||||
|
||||
if (type == GetVisibilityOverrideType())
|
||||
return;
|
||||
|
||||
if (IsPlayer())
|
||||
return;
|
||||
|
||||
if (IsVisibilityOverridden())
|
||||
{
|
||||
if (IsFarVisible())
|
||||
GetMap()->RemoveWorldObjectFromFarVisibleMap(this);
|
||||
else if (IsZoneWideVisible())
|
||||
GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(GetZoneId(), this);
|
||||
}
|
||||
|
||||
m_visibilityDistanceOverride = VisibilityDistances[AsUnderlyingType(type)];
|
||||
if (type == VisibilityDistanceType::Large || type == VisibilityDistanceType::Gigantic)
|
||||
GetMap()->AddWorldObjectToFarVisibleMap(this);
|
||||
else if (type == VisibilityDistanceType::Infinite)
|
||||
GetMap()->AddWorldObjectToZoneWideVisibleMap(GetZoneId(), this);
|
||||
|
||||
_visibilityDistanceOverrideType = type;
|
||||
}
|
||||
|
||||
void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
|
||||
@@ -1127,6 +1148,8 @@ void WorldObject::UpdatePositionData()
|
||||
|
||||
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||
{
|
||||
uint32 const oldZoneId = _zoneId;
|
||||
|
||||
_zoneId = _areaId = data.areaId;
|
||||
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(_areaId))
|
||||
@@ -1136,6 +1159,17 @@ void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& da
|
||||
_outdoors = data.outdoors;
|
||||
_floorZ = data.floorZ;
|
||||
_liquidData = data.liquidInfo;
|
||||
|
||||
// Has zone ID changed?
|
||||
if (oldZoneId != _zoneId)
|
||||
{
|
||||
// If so, check if we are far visibility overridden object and refresh maps if needed.
|
||||
if (IsZoneWideVisible())
|
||||
{
|
||||
GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(oldZoneId, this);
|
||||
GetMap()->AddWorldObjectToZoneWideVisibleMap(_zoneId, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldObject::AddToWorld()
|
||||
@@ -1150,6 +1184,9 @@ void WorldObject::RemoveFromWorld()
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
if (IsZoneWideVisible())
|
||||
GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(GetZoneId(), this);
|
||||
|
||||
DestroyForVisiblePlayers();
|
||||
|
||||
GetObjectVisibilityContainer().CleanVisibilityReferences();
|
||||
@@ -1612,26 +1649,16 @@ float WorldObject::GetGridActivationRange() const
|
||||
|
||||
float WorldObject::GetVisibilityRange() const
|
||||
{
|
||||
if (IsVisibilityOverridden() && IsCreature())
|
||||
{
|
||||
return *m_visibilityDistanceOverride;
|
||||
}
|
||||
if (IsCreature() && IsVisibilityOverridden())
|
||||
return GetVisibilityOverrideDistance();
|
||||
else if (IsGameObject())
|
||||
{
|
||||
{
|
||||
if (IsInWintergrasp())
|
||||
{
|
||||
return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
|
||||
}
|
||||
else if (IsVisibilityOverridden())
|
||||
{
|
||||
return *m_visibilityDistanceOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
|
||||
}
|
||||
}
|
||||
if (IsInWintergrasp())
|
||||
return VISIBILITY_DIST_WINTERGRASP;
|
||||
else if (IsVisibilityOverridden())
|
||||
return GetVisibilityOverrideDistance();
|
||||
else
|
||||
return GetMap()->GetVisibilityRange();
|
||||
}
|
||||
else
|
||||
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||
@@ -1645,28 +1672,18 @@ float WorldObject::GetSightRange(WorldObject const* target) const
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
if (target->IsVisibilityOverridden() && target->IsCreature())
|
||||
{
|
||||
return *target->m_visibilityDistanceOverride;
|
||||
}
|
||||
if (target->IsCreature() && target->IsVisibilityOverridden())
|
||||
return target->GetVisibilityOverrideDistance();
|
||||
else if (target->IsGameObject())
|
||||
{
|
||||
if (IsInWintergrasp() && target->IsInWintergrasp())
|
||||
{
|
||||
return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
|
||||
}
|
||||
return VISIBILITY_DIST_WINTERGRASP;
|
||||
else if (target->IsVisibilityOverridden())
|
||||
{
|
||||
return *target->m_visibilityDistanceOverride;
|
||||
}
|
||||
return target->GetVisibilityOverrideDistance();
|
||||
else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
|
||||
{
|
||||
return DEFAULT_VISIBILITY_INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
|
||||
}
|
||||
return GetMap()->GetVisibilityRange();
|
||||
}
|
||||
|
||||
return IsInWintergrasp() && target->IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||
@@ -1674,19 +1691,13 @@ float WorldObject::GetSightRange(WorldObject const* target) const
|
||||
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||
}
|
||||
else if (ToCreature())
|
||||
{
|
||||
return ToCreature()->m_SightDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SIGHT_RANGE_UNIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (ToDynObject() && isActiveObject())
|
||||
{
|
||||
return GetMap()->GetVisibilityRange();
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -1790,7 +1801,7 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
|
||||
}
|
||||
|
||||
// Xinef: check reversely obj vs viewpoint, object could be a gameObject which overrides _IsWithinDist function to include gameobject size
|
||||
if (!corpseCheck && !viewpoint->IsWithinDist(obj, GetSightRange(obj), true))
|
||||
if (!corpseCheck && !viewpoint->IsWithinDist(obj, GetSightRange(obj), false))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -358,9 +358,20 @@ template<class T>
|
||||
class GridObject
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] bool IsInGrid() const { return _gridRef.isValid(); }
|
||||
void AddToGrid(GridRefMgr<T>& m) { ASSERT(!IsInGrid()); _gridRef.link(&m, (T*)this); }
|
||||
void RemoveFromGrid() { ASSERT(IsInGrid()); _gridRef.unlink(); }
|
||||
bool IsInGrid() const
|
||||
{
|
||||
return _gridRef.isValid();
|
||||
}
|
||||
void AddToGrid(GridRefMgr<T>& m)
|
||||
{
|
||||
ASSERT(!IsInGrid());
|
||||
_gridRef.link(&m, (T*)this);
|
||||
}
|
||||
void RemoveFromGrid()
|
||||
{
|
||||
ASSERT(IsInGrid());
|
||||
_gridRef.unlink();
|
||||
}
|
||||
private:
|
||||
GridReference<T> _gridRef;
|
||||
};
|
||||
@@ -654,8 +665,11 @@ public:
|
||||
|
||||
[[nodiscard]] bool isActiveObject() const { return m_isActive; }
|
||||
void setActive(bool isActiveObject);
|
||||
[[nodiscard]] bool IsFarVisible() const { return m_isFarVisible; }
|
||||
[[nodiscard]] bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); }
|
||||
VisibilityDistanceType GetVisibilityOverrideType() const { return _visibilityDistanceOverrideType; }
|
||||
bool IsVisibilityOverridden() const { return _visibilityDistanceOverrideType > VisibilityDistanceType::Normal; }
|
||||
bool IsZoneWideVisible() const { return _visibilityDistanceOverrideType == VisibilityDistanceType::Infinite; }
|
||||
bool IsFarVisible() const { return _visibilityDistanceOverrideType == VisibilityDistanceType::Large || _visibilityDistanceOverrideType == VisibilityDistanceType::Gigantic; }
|
||||
float GetVisibilityOverrideDistance() const;
|
||||
void SetVisibilityDistanceOverride(VisibilityDistanceType type);
|
||||
|
||||
[[nodiscard]] bool IsInWintergrasp() const
|
||||
@@ -719,8 +733,7 @@ public:
|
||||
protected:
|
||||
std::string m_name;
|
||||
bool m_isActive;
|
||||
bool m_isFarVisible;
|
||||
Optional<float> m_visibilityDistanceOverride;
|
||||
VisibilityDistanceType _visibilityDistanceOverrideType;
|
||||
ZoneScript* m_zoneScript;
|
||||
|
||||
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#define ATTACK_DISTANCE 5.0f
|
||||
#define VISIBILITY_COMPENSATION 15.0f // increase searchers
|
||||
#define INSPECT_DISTANCE 28.0f
|
||||
#define VISIBILITY_INC_FOR_GOBJECTS 30.0f // pussywizard
|
||||
#define SPELL_SEARCHER_COMPENSATION 30.0f // increase searchers size in case we have large npc near cell border
|
||||
#define TRADE_DISTANCE 11.11f
|
||||
#define MAX_VISIBILITY_DISTANCE 250.0f // max distance for visible objects, experimental
|
||||
|
||||
@@ -7078,6 +7078,14 @@ void Player::ApplyItemObtainSpells(Item* item, bool apply)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateItemObtainSpells(Item* item, uint8 bag, uint8 slot)
|
||||
{
|
||||
if (IsBankPos(bag, slot))
|
||||
ApplyItemObtainSpells(item, false);
|
||||
else if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
|
||||
ApplyItemObtainSpells(item, true);
|
||||
}
|
||||
|
||||
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
|
||||
{
|
||||
if (Item const* weapon = GetWeaponForAttack(attackType, true))
|
||||
@@ -16314,13 +16322,25 @@ float Player::GetSightRange(WorldObject const* target) const
|
||||
{
|
||||
float sightRange = WorldObject::GetSightRange(target);
|
||||
if (_farSightDistance)
|
||||
{
|
||||
sightRange += *_farSightDistance;
|
||||
}
|
||||
|
||||
return sightRange;
|
||||
}
|
||||
|
||||
bool Player::IsWorldObjectOutOfSightRange(WorldObject const* target) const
|
||||
{
|
||||
// Special handling for Infinite visibility override objects -> they are zone wide visible
|
||||
if (target->GetVisibilityOverrideType() == VisibilityDistanceType::Infinite)
|
||||
{
|
||||
// Same zone, always visible
|
||||
if (target->GetZoneId() == GetZoneId())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if out of range
|
||||
return !m_seer->IsWithinDist(target, GetSightRange(target), false);
|
||||
}
|
||||
|
||||
std::string Player::GetPlayerName()
|
||||
{
|
||||
std::string name = GetName();
|
||||
|
||||
@@ -2199,6 +2199,7 @@ public:
|
||||
|
||||
void CastAllObtainSpells();
|
||||
void ApplyItemObtainSpells(Item* item, bool apply);
|
||||
void UpdateItemObtainSpells(Item* item, uint8 bag, uint8 slot);
|
||||
|
||||
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
|
||||
|
||||
@@ -2620,6 +2621,7 @@ public:
|
||||
[[nodiscard]] Optional<float> GetFarSightDistance() const;
|
||||
|
||||
float GetSightRange(WorldObject const* target = nullptr) const override;
|
||||
bool IsWorldObjectOutOfSightRange(WorldObject const* target) const;
|
||||
|
||||
std::string GetPlayerName();
|
||||
|
||||
|
||||
@@ -2654,9 +2654,7 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
|
||||
|
||||
AddEnchantmentDurations(pItem);
|
||||
AddItemDurations(pItem);
|
||||
|
||||
if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
|
||||
ApplyItemObtainSpells(pItem, true);
|
||||
UpdateItemObtainSpells(pItem, bag, slot);
|
||||
|
||||
return pItem;
|
||||
}
|
||||
@@ -2694,8 +2692,7 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
|
||||
|
||||
pItem2->SetState(ITEM_CHANGED, this);
|
||||
|
||||
if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
|
||||
ApplyItemObtainSpells(pItem2, true);
|
||||
UpdateItemObtainSpells(pItem2, bag, slot);
|
||||
|
||||
return pItem2;
|
||||
}
|
||||
|
||||
@@ -1595,21 +1595,12 @@ void Player::UpdateVisibilityForPlayer(bool mapChange)
|
||||
// After added to map seer must be a player - there is no possibility to
|
||||
// still have different seer (all charm auras must be already removed)
|
||||
if (mapChange && m_seer != this)
|
||||
{
|
||||
m_seer = this;
|
||||
}
|
||||
|
||||
Acore::VisibleNotifier notifierNoLarge(
|
||||
*this, mapChange,
|
||||
false); // visit only objects which are not large; default distance
|
||||
Cell::VisitObjects(m_seer, notifierNoLarge,
|
||||
GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
notifierNoLarge.SendToSelf();
|
||||
|
||||
Acore::VisibleNotifier notifierLarge(
|
||||
*this, mapChange, true); // visit only large objects; maximum distance
|
||||
Cell::VisitObjects(m_seer, notifierLarge, GetSightRange());
|
||||
notifierLarge.SendToSelf();
|
||||
Acore::VisibleNotifier notifier(*this, mapChange);
|
||||
Cell::VisitObjects(m_seer, notifier, GetSightRange());
|
||||
Cell::VisitFarVisibleObjects(m_seer, notifier, VISIBILITY_DISTANCE_GIGANTIC);
|
||||
notifier.SendToSelf();
|
||||
|
||||
if (mapChange)
|
||||
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||
|
||||
@@ -20315,12 +20315,10 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
||||
//active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ());
|
||||
}
|
||||
|
||||
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
|
||||
Cell::VisitObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
relocateNoLarge.SendToSelf();
|
||||
Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
|
||||
Cell::VisitObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
|
||||
relocateLarge.SendToSelf();
|
||||
Acore::PlayerRelocationNotifier notifier(*player);
|
||||
Cell::VisitObjects(viewPoint, notifier, player->GetSightRange());
|
||||
Cell::VisitFarVisibleObjects(viewPoint, notifier, VISIBILITY_DISTANCE_GIGANTIC);
|
||||
notifier.SendToSelf();
|
||||
}
|
||||
|
||||
if (Player* player = this->ToPlayer())
|
||||
@@ -20354,16 +20352,10 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
||||
|
||||
GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE);
|
||||
|
||||
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
|
||||
Cell::VisitObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
relocateNoLarge.SendToSelf();
|
||||
|
||||
if (!player->GetFarSightDistance())
|
||||
{
|
||||
Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
|
||||
Cell::VisitObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
|
||||
relocateLarge.SendToSelf();
|
||||
}
|
||||
Acore::PlayerRelocationNotifier notifier(*player);
|
||||
Cell::VisitObjects(viewPoint, notifier, player->GetSightRange());
|
||||
Cell::VisitFarVisibleObjects(viewPoint, notifier, VISIBILITY_DISTANCE_GIGANTIC);
|
||||
notifier.SendToSelf();
|
||||
|
||||
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
||||
}
|
||||
@@ -20383,7 +20375,7 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
||||
unit->m_last_notify_position.Relocate(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
|
||||
|
||||
Acore::CreatureRelocationNotifier relocate(*unit);
|
||||
Cell::VisitObjects(unit, relocate, unit->GetVisibilityRange() + VISIBILITY_COMPENSATION);
|
||||
Cell::VisitObjects(unit, relocate, unit->GetVisibilityRange());
|
||||
|
||||
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@ struct Cell
|
||||
template<class T> static void VisitObjects(WorldObject const* obj, T& visitor, float radius);
|
||||
template<class T> static void VisitObjects(float x, float y, Map* map, T& visitor, float radius);
|
||||
|
||||
template<class T> static void VisitFarVisibleObjects(WorldObject const* obj, T& visitor, float radius);
|
||||
|
||||
private:
|
||||
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER>&, Map&, CellCoord const&, CellCoord const&) const;
|
||||
};
|
||||
|
||||
@@ -181,4 +181,14 @@ inline void Cell::VisitObjects(float x, float y, Map* map, T& visitor, float rad
|
||||
cell.Visit(p, gnotifier, *map, x, y, radius);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Cell::VisitFarVisibleObjects(WorldObject const* center_obj, T& visitor, float radius)
|
||||
{
|
||||
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
|
||||
Cell cell(p);
|
||||
|
||||
TypeContainerVisitor<T, FarVisibleGridContainer> gnotifier(visitor);
|
||||
cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,16 +33,20 @@
|
||||
#include "TypeContainer.h"
|
||||
#include "TypeContainerVisitor.h"
|
||||
|
||||
class WorldObject;
|
||||
|
||||
template
|
||||
<
|
||||
class GRID_OBJECT_TYPES
|
||||
class GRID_OBJECT_TYPES,
|
||||
class FAR_VISIBLE_OBJECT_TYPES
|
||||
>
|
||||
class GridCell
|
||||
{
|
||||
public:
|
||||
~GridCell() = default;
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
|
||||
template<class SPECIFIC_OBJECT>
|
||||
void AddGridObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
_gridObjects.template insert<SPECIFIC_OBJECT>(obj);
|
||||
ASSERT(obj->IsInGrid());
|
||||
@@ -50,12 +54,32 @@ public:
|
||||
|
||||
// Visit grid objects
|
||||
template<class T>
|
||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
|
||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES>>& visitor)
|
||||
{
|
||||
visitor.Visit(_gridObjects);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT>
|
||||
void AddFarVisibleObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
_farVisibleObjects.template Insert<SPECIFIC_OBJECT>(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT>
|
||||
void RemoveFarVisibleObject(SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
_farVisibleObjects.template Remove<SPECIFIC_OBJECT>(obj);
|
||||
}
|
||||
|
||||
// Visit far objects
|
||||
template<class T>
|
||||
void Visit(TypeContainerVisitor<T, TypeVectorContainer<FAR_VISIBLE_OBJECT_TYPES>>& visitor)
|
||||
{
|
||||
visitor.Visit(_farVisibleObjects);
|
||||
}
|
||||
|
||||
private:
|
||||
TypeMapContainer<GRID_OBJECT_TYPES> _gridObjects;
|
||||
TypeVectorContainer<FAR_VISIBLE_OBJECT_TYPES> _farVisibleObjects;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -57,6 +57,9 @@ typedef TYPELIST_5(GameObject, Player, Creature, Corpse, DynamicObject) AllMapGr
|
||||
// List of object types stored on map level
|
||||
typedef TYPELIST_4(Creature, GameObject, DynamicObject, Corpse) AllMapStoredObjectTypes;
|
||||
|
||||
// List of object types that can have far visible range
|
||||
typedef TYPELIST_2(Creature, GameObject) AllFarVisibleObjectTypes;
|
||||
|
||||
typedef GridRefMgr<Corpse> CorpseMapType;
|
||||
typedef GridRefMgr<Creature> CreatureMapType;
|
||||
typedef GridRefMgr<DynamicObject> DynamicObjectMapType;
|
||||
@@ -73,10 +76,11 @@ enum GridMapTypeMask
|
||||
GRID_MAP_TYPE_MASK_ALL = 0x1F
|
||||
};
|
||||
|
||||
typedef GridCell<AllMapGridStoredObjectTypes> GridCellType;
|
||||
typedef MapGrid<AllMapGridStoredObjectTypes> MapGridType;
|
||||
typedef GridCell<AllMapGridStoredObjectTypes, AllFarVisibleObjectTypes> GridCellType;
|
||||
typedef MapGrid<AllMapGridStoredObjectTypes, AllFarVisibleObjectTypes> MapGridType;
|
||||
|
||||
typedef TypeMapContainer<AllMapGridStoredObjectTypes> GridTypeMapContainer;
|
||||
typedef TypeVectorContainer<AllFarVisibleObjectTypes> FarVisibleGridContainer;
|
||||
typedef TypeUnorderedMapContainer<AllMapStoredObjectTypes, ObjectGuid> MapStoredObjectTypesContainer;
|
||||
|
||||
template<uint32 LIMIT>
|
||||
|
||||
@@ -25,12 +25,13 @@ class GridTerrainData;
|
||||
|
||||
template
|
||||
<
|
||||
class GRID_OBJECT_TYPES
|
||||
class GRID_OBJECT_TYPES,
|
||||
class FAR_VISIBLE_OBJECT_TYPES
|
||||
>
|
||||
class MapGrid
|
||||
{
|
||||
public:
|
||||
typedef GridCell<GRID_OBJECT_TYPES> GridCellType;
|
||||
typedef GridCell<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES> GridCellType;
|
||||
|
||||
MapGrid(uint16 const x, uint16 const y)
|
||||
: _x(x), _y(y), _objectDataLoaded(false), _terrainData(nullptr) { }
|
||||
@@ -54,9 +55,19 @@ public:
|
||||
GetOrCreateCell(x, y).RemoveGridObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void AddFarVisibleObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
GetOrCreateCell(x, y).AddFarVisibleObject(obj);
|
||||
}
|
||||
|
||||
template<class SPECIFIC_OBJECT> void RemoveFarVisibleObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
|
||||
{
|
||||
GetOrCreateCell(x, y).RemoveFarVisibleObject(obj);
|
||||
}
|
||||
|
||||
// Visit all cells
|
||||
template<class T, class TT>
|
||||
void VisitAllCells(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
||||
void VisitAllCells(TypeContainerVisitor<T, TT>& visitor)
|
||||
{
|
||||
for (auto& cellX : _cells)
|
||||
{
|
||||
@@ -72,7 +83,7 @@ public:
|
||||
|
||||
// Visit single cell
|
||||
template<class T, class TT>
|
||||
void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
||||
void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor<T, TT>& visitor)
|
||||
{
|
||||
GridCellType* gridCell = GetCell(x, y);
|
||||
if (!gridCell)
|
||||
@@ -81,7 +92,7 @@ public:
|
||||
gridCell->Visit(visitor);
|
||||
}
|
||||
|
||||
void link(GridRefMgr<MapGrid<GRID_OBJECT_TYPES>>* pTo)
|
||||
void link(GridRefMgr<MapGrid<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES>>* pTo)
|
||||
{
|
||||
_gridReference.link(pTo, this);
|
||||
}
|
||||
@@ -134,7 +145,7 @@ private:
|
||||
|
||||
bool _objectDataLoaded;
|
||||
std::array<std::array<std::unique_ptr<GridCellType>, MAX_NUMBER_OF_CELLS>, MAX_NUMBER_OF_CELLS> _cells; // N * N array
|
||||
GridReference<MapGrid<GRID_OBJECT_TYPES>> _gridReference;
|
||||
GridReference<MapGrid<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES>> _gridReference;
|
||||
|
||||
// Instances will share a copy of the parent maps terrainData
|
||||
std::shared_ptr<GridTerrainData> _terrainData;
|
||||
|
||||
@@ -29,38 +29,31 @@ void VisibleNotifier::Visit(GameObjectMapType& m)
|
||||
for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
GameObject* go = iter->GetSource();
|
||||
if (i_largeOnly != go->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
i_player.UpdateVisibilityOf(go, i_data, i_visibleNow);
|
||||
}
|
||||
}
|
||||
|
||||
void VisibleNotifier::SendToSelf()
|
||||
{
|
||||
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
|
||||
// but exist one case when this possible and object not out of range: transports
|
||||
if (Transport* transport = i_player.GetTransport())
|
||||
// Update far visible objects
|
||||
ZoneWideVisibleWorldObjectsSet const* zoneWideVisibleObjects = i_player.GetMap()->GetZoneWideVisibleWorldObjectsForZone(i_player.GetZoneId());
|
||||
if (zoneWideVisibleObjects)
|
||||
{
|
||||
for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
|
||||
for (WorldObject* obj : *zoneWideVisibleObjects)
|
||||
{
|
||||
if (i_largeOnly != (*itr)->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
switch ((*itr)->GetTypeId())
|
||||
switch (obj->GetTypeId())
|
||||
{
|
||||
case TYPEID_GAMEOBJECT:
|
||||
i_player.UpdateVisibilityOf((*itr)->ToGameObject(), i_data, i_visibleNow);
|
||||
break;
|
||||
case TYPEID_PLAYER:
|
||||
i_player.UpdateVisibilityOf((*itr)->ToPlayer(), i_data, i_visibleNow);
|
||||
(*itr)->ToPlayer()->UpdateVisibilityOf(&i_player);
|
||||
break;
|
||||
case TYPEID_UNIT:
|
||||
i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case TYPEID_GAMEOBJECT:
|
||||
i_player.UpdateVisibilityOf(obj->ToGameObject(), i_data, i_visibleNow);
|
||||
break;
|
||||
case TYPEID_UNIT:
|
||||
i_player.UpdateVisibilityOf(obj->ToCreature(), i_data, i_visibleNow);
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
i_player.UpdateVisibilityOf(obj->ToDynObject(), i_data, i_visibleNow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,26 +62,8 @@ void VisibleNotifier::SendToSelf()
|
||||
for (VisibleWorldObjectsMap::iterator itr = visibleWorldObjects->begin(); itr != visibleWorldObjects->end();)
|
||||
{
|
||||
WorldObject* obj = itr->second;
|
||||
if (i_largeOnly != obj->IsVisibilityOverridden())
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
|
||||
// pussywizard: static transports are removed only in RemovePlayerFromMap and here if can no longer detect (eg. phase changed)
|
||||
if (itr->first.IsTransport())
|
||||
{
|
||||
if (GameObject* staticTrans = obj->ToGameObject())
|
||||
{
|
||||
if (i_player.CanSeeOrDetect(staticTrans, false, true))
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i_player.m_seer->IsWithinDist(obj, i_player.GetSightRange(obj), true))
|
||||
if (!i_player.IsWorldObjectOutOfSightRange(obj)
|
||||
|| i_player.CanSeeOrDetect(obj, false, true))
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
@@ -111,12 +86,7 @@ void VisibleNotifier::SendToSelf()
|
||||
i_player.GetSession()->SendPacket(&packet);
|
||||
|
||||
for (std::vector<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
|
||||
{
|
||||
if (i_largeOnly != (*it)->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
i_player.GetInitialVisiblePackets(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void VisibleChangesNotifier::Visit(PlayerMapType& m)
|
||||
|
||||
@@ -45,16 +45,16 @@ namespace Acore
|
||||
Player& i_player;
|
||||
std::vector<Unit*>& i_visibleNow;
|
||||
bool i_gobjOnly;
|
||||
bool i_largeOnly;
|
||||
UpdateData i_data;
|
||||
|
||||
VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) :
|
||||
i_player(player), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly)
|
||||
VisibleNotifier(Player& player, bool gobjOnly) :
|
||||
i_player(player), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly)
|
||||
{
|
||||
i_visibleNow.clear();
|
||||
}
|
||||
|
||||
void Visit(GameObjectMapType&);
|
||||
template<class T> void Visit(std::vector<T>& m);
|
||||
template<class T> void Visit(GridRefMgr<T>& m);
|
||||
void SendToSelf(void);
|
||||
};
|
||||
@@ -72,8 +72,9 @@ namespace Acore
|
||||
|
||||
struct PlayerRelocationNotifier : public VisibleNotifier
|
||||
{
|
||||
PlayerRelocationNotifier(Player& player, bool largeOnly): VisibleNotifier(player, false, largeOnly) { }
|
||||
PlayerRelocationNotifier(Player& player): VisibleNotifier(player, false) { }
|
||||
|
||||
template<class T> void Visit(std::vector<T>& m) { VisibleNotifier::Visit(m); }
|
||||
template<class T> void Visit(GridRefMgr<T>& m) { VisibleNotifier::Visit(m); }
|
||||
void Visit(PlayerMapType&);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
template<class T>
|
||||
inline void Acore::VisibleNotifier::Visit(std::vector<T>& m)
|
||||
{
|
||||
for (typename std::vector<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
i_player.UpdateVisibilityOf((*iter), i_data, i_visibleNow);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
@@ -33,12 +40,7 @@ inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
|
||||
return;
|
||||
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if (i_largeOnly != iter->GetSource()->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow);
|
||||
}
|
||||
}
|
||||
|
||||
// SEARCHERS & LIST SEARCHERS & WORKERS
|
||||
|
||||
@@ -29,91 +29,82 @@
|
||||
#include "WorldSession.h"
|
||||
#include <cmath>
|
||||
|
||||
void WorldSession::HandleSplitItemOpcode(WorldPacket& recvData)
|
||||
#include "ItemPackets.h"
|
||||
|
||||
void WorldSession::HandleSplitItemOpcode(WorldPackets::Item::SplitItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_SPLIT_ITEM");
|
||||
uint8 srcbag, srcslot, dstbag, dstslot;
|
||||
uint32 count;
|
||||
|
||||
recvData >> srcbag >> srcslot >> dstbag >> dstslot >> count;
|
||||
|
||||
uint16 src = ((srcbag << 8) | srcslot);
|
||||
uint16 dst = ((dstbag << 8) | dstslot);
|
||||
uint16 src = ((packet.SourceBag << 8) | packet.SourceSlot);
|
||||
uint16 dst = ((packet.DestinationBag << 8) | packet.DestinationSlot);
|
||||
|
||||
if (src == dst)
|
||||
return;
|
||||
|
||||
if (count == 0)
|
||||
return; //check count - if zero it's fake packet
|
||||
if (packet.Count == 0)
|
||||
return; //check count - if zero it's fake packet
|
||||
|
||||
if (!_player->IsValidPos(srcbag, srcslot, true))
|
||||
if (!_player->IsValidPos(packet.SourceBag, packet.SourceSlot, true))
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos
|
||||
if (!_player->IsValidPos(packet.DestinationBag, packet.DestinationSlot, false)) // can be autostore pos
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
_player->SplitItem(src, dst, count);
|
||||
_player->SplitItem(src, dst, packet.Count);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSwapInvItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleSwapInvItemOpcode(WorldPackets::Item::SwapInventoryItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_SWAP_INV_ITEM");
|
||||
uint8 srcslot, dstslot;
|
||||
|
||||
recvData >> dstslot >> srcslot;
|
||||
|
||||
// prevent attempt swap same item to current position generated by client at special checting sequence
|
||||
if (srcslot == dstslot)
|
||||
// prevent attempt swap same item to current position generated by client at special cheating sequence
|
||||
if (packet.SourceSlot == packet.DestinationSlot)
|
||||
return;
|
||||
|
||||
if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true))
|
||||
if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, packet.SourceSlot, true))
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true))
|
||||
if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, packet.DestinationSlot, true))
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, srcslot) && !CanUseBank())
|
||||
if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, packet.SourceSlot) && !CanUseBank())
|
||||
{
|
||||
//LOG_DEBUG("network", "WORLD: HandleSwapInvItemOpcode - Unit ({}) not found or you can't interact with him.", m_currentBankerGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, dstslot) && !CanUseBank())
|
||||
if (_player->IsBankPos(INVENTORY_SLOT_BAG_0, packet.DestinationSlot) && !CanUseBank())
|
||||
{
|
||||
//LOG_DEBUG("network", "WORLD: HandleSwapInvItemOpcode - Unit ({}) not found or you can't interact with him.", m_currentBankerGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
|
||||
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
|
||||
uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | packet.SourceSlot);
|
||||
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | packet.DestinationSlot);
|
||||
|
||||
_player->SwapItem(src, dst);
|
||||
}
|
||||
|
||||
void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPackets::Item::AutoEquipItemSlot& packet)
|
||||
{
|
||||
ObjectGuid itemguid;
|
||||
uint8 dstslot;
|
||||
recvData >> itemguid >> dstslot;
|
||||
|
||||
// cheating attempt, client should never send opcode in that case
|
||||
if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot))
|
||||
if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, packet.DestinationSlot))
|
||||
return;
|
||||
|
||||
Item* item = _player->GetItemByGuid(itemguid);
|
||||
uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8);
|
||||
Item* item = _player->GetItemByGuid(packet.ItemGuid);
|
||||
uint16 dstpos = packet.DestinationSlot | (INVENTORY_SLOT_BAG_0 << 8);
|
||||
|
||||
if (!item || item->GetPos() == dstpos)
|
||||
return;
|
||||
@@ -121,39 +112,36 @@ void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket& recvData)
|
||||
_player->SwapItem(item->GetPos(), dstpos);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSwapItem(WorldPacket& recvData)
|
||||
void WorldSession::HandleSwapItem(WorldPackets::Item::SwapItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_SWAP_ITEM");
|
||||
uint8 dstbag, dstslot, srcbag, srcslot;
|
||||
|
||||
recvData >> dstbag >> dstslot >> srcbag >> srcslot;
|
||||
uint16 src = ((packet.SourceBag << 8) | packet.SourceSlot);
|
||||
uint16 dst = ((packet.DestinationBag << 8) | packet.DestinationSlot);
|
||||
|
||||
uint16 src = ((srcbag << 8) | srcslot);
|
||||
uint16 dst = ((dstbag << 8) | dstslot);
|
||||
|
||||
// prevent attempt swap same item to current position generated by client at special checting sequence
|
||||
// prevent attempt swap same item to current position generated by client at special cheating sequence
|
||||
if (src == dst)
|
||||
return;
|
||||
|
||||
if (!_player->IsValidPos(srcbag, srcslot, true))
|
||||
if (!_player->IsValidPos(packet.SourceBag, packet.SourceSlot, true))
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_player->IsValidPos(dstbag, dstslot, true))
|
||||
if (!_player->IsValidPos(packet.DestinationBag, packet.DestinationSlot, true))
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->IsBankPos(srcbag, srcslot) && !CanUseBank())
|
||||
if (_player->IsBankPos(packet.SourceBag, packet.SourceSlot) && !CanUseBank())
|
||||
{
|
||||
//LOG_DEBUG("network", "WORLD: HandleSwapItem - Unit ({}) not found or you can't interact with him.", m_currentBankerGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player->IsBankPos(dstbag, dstslot) && !CanUseBank())
|
||||
if (_player->IsBankPos(packet.DestinationBag, packet.DestinationSlot) && !CanUseBank())
|
||||
{
|
||||
//LOG_DEBUG("network", "WORLD: HandleSwapItem - Unit ({}) not found or you can't interact with him.", m_currentBankerGUID.ToString());
|
||||
return;
|
||||
@@ -162,14 +150,11 @@ void WorldSession::HandleSwapItem(WorldPacket& recvData)
|
||||
_player->SwapItem(src, dst);
|
||||
}
|
||||
|
||||
void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_AUTOEQUIP_ITEM");
|
||||
uint8 srcbag, srcslot;
|
||||
|
||||
recvData >> srcbag >> srcslot;
|
||||
|
||||
Item* pSrcItem = _player->GetItemByPos(srcbag, srcslot);
|
||||
Item* pSrcItem = _player->GetItemByPos(packet.SourceBag, packet.SourceSlot);
|
||||
if (!pSrcItem)
|
||||
return; // only at cheat
|
||||
|
||||
@@ -219,7 +204,7 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData)
|
||||
|
||||
if (!pDstItem) // empty slot, simple case
|
||||
{
|
||||
_player->RemoveItem(srcbag, srcslot, true);
|
||||
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true);
|
||||
_player->EquipItem(dest, pSrcItem, true);
|
||||
_player->AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
@@ -243,23 +228,23 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData)
|
||||
uint16 eSrc = 0;
|
||||
if (_player->IsInventoryPos(src))
|
||||
{
|
||||
msg = _player->CanStoreItem(srcbag, srcslot, sSrc, pDstItem, true);
|
||||
msg = _player->CanStoreItem(packet.SourceBag, packet.SourceSlot, sSrc, pDstItem, true);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
msg = _player->CanStoreItem(srcbag, NULL_SLOT, sSrc, pDstItem, true);
|
||||
msg = _player->CanStoreItem(packet.SourceBag, NULL_SLOT, sSrc, pDstItem, true);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true);
|
||||
}
|
||||
else if (_player->IsBankPos(src))
|
||||
{
|
||||
msg = _player->CanBankItem(srcbag, srcslot, sSrc, pDstItem, true);
|
||||
msg = _player->CanBankItem(packet.SourceBag, packet.SourceSlot, sSrc, pDstItem, true);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
msg = _player->CanBankItem(srcbag, NULL_SLOT, sSrc, pDstItem, true);
|
||||
msg = _player->CanBankItem(packet.SourceBag, NULL_SLOT, sSrc, pDstItem, true);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true);
|
||||
}
|
||||
else if (_player->IsEquipmentPos(src))
|
||||
{
|
||||
msg = _player->CanEquipItem(srcslot, eSrc, pDstItem, true);
|
||||
msg = _player->CanEquipItem(packet.SourceSlot, eSrc, pDstItem, true);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
msg = _player->CanUnequipItem(eSrc, true);
|
||||
}
|
||||
@@ -272,7 +257,7 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData)
|
||||
|
||||
// now do moves, remove...
|
||||
_player->RemoveItem(dstbag, dstslot, true, true);
|
||||
_player->RemoveItem(srcbag, srcslot, true, true);
|
||||
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true, true);
|
||||
|
||||
// add to dest
|
||||
_player->EquipItem(dest, pSrcItem, true);
|
||||
@@ -292,14 +277,11 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket& recvData)
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleDestroyItemOpcode(WorldPackets::Item::DestroyItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_DESTROYITEM");
|
||||
uint8 bag, slot, count, data1, data2, data3;
|
||||
|
||||
recvData >> bag >> slot >> count >> data1 >> data2 >> data3;
|
||||
|
||||
uint16 pos = (bag << 8) | slot;
|
||||
uint16 pos = (packet.Bag << 8) | packet.Slot;
|
||||
|
||||
// prevent drop unequipable items (in combat, for example) and non-empty bags
|
||||
if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos))
|
||||
@@ -312,7 +294,7 @@ void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData)
|
||||
}
|
||||
}
|
||||
|
||||
Item* pItem = _player->GetItemByPos(bag, slot);
|
||||
Item* pItem = _player->GetItemByPos(packet.Bag, packet.Slot);
|
||||
if (!pItem)
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
|
||||
@@ -327,14 +309,14 @@ void WorldSession::HandleDestroyItemOpcode(WorldPacket& recvData)
|
||||
|
||||
recoveryItem(pItem);
|
||||
|
||||
if (count)
|
||||
if (packet.Count)
|
||||
{
|
||||
uint32 i_count = count;
|
||||
uint32 i_count = packet.Count;
|
||||
_player->DestroyItemCount(pItem, i_count, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_player->DestroyItem(bag, slot, true);
|
||||
_player->DestroyItem(packet.Bag, packet.Slot, true);
|
||||
}
|
||||
_player->SendQuestGiverStatusMultiple();
|
||||
}
|
||||
@@ -692,15 +674,12 @@ void WorldSession::HandleItemQuerySingleOpcode(WorldPacket& recvData)
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleReadItem(WorldPacket& recvData)
|
||||
void WorldSession::HandleReadItem(WorldPackets::Item::ReadItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_READ_ITEM");
|
||||
|
||||
uint8 bag, slot;
|
||||
recvData >> bag >> slot;
|
||||
|
||||
//LOG_DEBUG("network.opcode", "STORAGE: Read bag = {}, slot = {}", bag, slot);
|
||||
Item* pItem = _player->GetItemByPos(bag, slot);
|
||||
Item* pItem = _player->GetItemByPos(packet.Bag, packet.Slot);
|
||||
|
||||
if (pItem && pItem->GetTemplate()->PageText)
|
||||
{
|
||||
@@ -725,27 +704,22 @@ void WorldSession::HandleReadItem(WorldPacket& recvData)
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleSellItemOpcode(WorldPackets::Item::SellItem& packet)
|
||||
{
|
||||
ObjectGuid vendorguid, itemguid;
|
||||
uint32 count;
|
||||
|
||||
recvData >> vendorguid >> itemguid >> count;
|
||||
|
||||
if (!itemguid)
|
||||
if (!packet.ItemGuid)
|
||||
return;
|
||||
|
||||
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
|
||||
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.VendorGuid, UNIT_NPC_FLAG_VENDOR);
|
||||
if (!creature)
|
||||
{
|
||||
LOG_DEBUG("network", "WORLD: HandleSellItemOpcode - Unit ({}) not found or you can not interact with him.", vendorguid.ToString());
|
||||
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, nullptr, itemguid, 0);
|
||||
LOG_DEBUG("network", "WORLD: HandleSellItemOpcode - Unit ({}) not found or you can not interact with him.", packet.VendorGuid.ToString());
|
||||
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, nullptr, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (creature->HasFlagsExtra(CREATURE_FLAG_EXTRA_NO_SELL_VENDOR))
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_TO_THIS_MERCHANT, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_TO_THIS_MERCHANT, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -753,7 +727,7 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
Item* pItem = _player->GetItemByGuid(itemguid);
|
||||
Item* pItem = _player->GetItemByGuid(packet.ItemGuid);
|
||||
if (pItem)
|
||||
{
|
||||
if (!sScriptMgr->OnPlayerCanSellItem(_player, pItem, creature))
|
||||
@@ -762,21 +736,21 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
// prevent sell not owner item
|
||||
if (_player->GetGUID() != pItem->GetOwnerGUID())
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent sell non empty bag by drag-and-drop at vendor's item list
|
||||
if (pItem->IsNotEmptyBag())
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent sell currently looted item
|
||||
if (_player->GetLootGUID() == pItem->GetGUID())
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -787,16 +761,14 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
return; // Therefore, no feedback to client
|
||||
|
||||
// special case at auto sell (sell all)
|
||||
if (count == 0)
|
||||
{
|
||||
count = pItem->GetCount();
|
||||
}
|
||||
if (packet.Count == 0)
|
||||
packet.Count = pItem->GetCount();
|
||||
else
|
||||
{
|
||||
// prevent sell more items that exist in stack (possible only not from client)
|
||||
if (count > pItem->GetCount())
|
||||
if (packet.Count > pItem->GetCount())
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -806,11 +778,11 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
{
|
||||
if (pProto->SellPrice > 0)
|
||||
{
|
||||
uint32 money = pProto->SellPrice * count;
|
||||
uint32 money = pProto->SellPrice * packet.Count;
|
||||
if (_player->GetMoney() >= MAX_MONEY_AMOUNT - money) // prevent exceeding gold limit
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, nullptr, nullptr);
|
||||
_player->SendSellError(SELL_ERR_UNK, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_UNK, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -828,8 +800,8 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
DurabilityCostsEntry const* dcost = sDurabilityCostsStore.LookupEntry(pProto->ItemLevel);
|
||||
if (!dcost)
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
LOG_ERROR("network.opcode", "WORLD: HandleSellItemOpcode - Wrong item lvl {} for item {} count = {}", pProto->ItemLevel, pItem->GetEntry(), count);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
LOG_ERROR("network.opcode", "WORLD: HandleSellItemOpcode - Wrong item lvl {} for item {} count = {}", pProto->ItemLevel, pItem->GetEntry(), packet.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -837,8 +809,8 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
DurabilityQualityEntry const* dQualitymodEntry = sDurabilityQualityStore.LookupEntry(dQualitymodEntryId);
|
||||
if (!dQualitymodEntry)
|
||||
{
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
LOG_ERROR("network.opcode", "WORLD: HandleSellItemOpcode - Wrong dQualityModEntry {} for item {} count = {}", dQualitymodEntryId, pItem->GetEntry(), count);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
LOG_ERROR("network.opcode", "WORLD: HandleSellItemOpcode - Wrong dQualityModEntry {} for item {} count = {}", dQualitymodEntryId, pItem->GetEntry(), packet.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -846,36 +818,30 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
uint32 refund = uint32(std::ceil(LostDurability * dmultiplier * double(dQualitymodEntry->quality_mod)));
|
||||
|
||||
if (!refund)
|
||||
{
|
||||
refund = 1;
|
||||
}
|
||||
|
||||
//starter items can cost more to refund than vendorprice
|
||||
if (refund > money)
|
||||
{
|
||||
money = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
money -= refund;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count < pItem->GetCount()) // need split items
|
||||
if (packet.Count < pItem->GetCount()) // need split items
|
||||
{
|
||||
Item* pNewItem = pItem->CloneItem(count, _player);
|
||||
Item* pNewItem = pItem->CloneItem(packet.Count, _player);
|
||||
if (!pNewItem)
|
||||
{
|
||||
LOG_ERROR("network.opcode", "WORLD: HandleSellItemOpcode - could not create clone of item {}; count = {}", pItem->GetEntry(), count);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
LOG_ERROR("network.opcode", "WORLD: HandleSellItemOpcode - could not create clone of item {}; count = {}", pItem->GetEntry(), packet.Count);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pNewItem->SetUInt32Value(ITEM_FIELD_DURABILITY, pItem->GetUInt32Value(ITEM_FIELD_DURABILITY));
|
||||
|
||||
pItem->SetCount(pItem->GetCount() - count);
|
||||
_player->ItemRemovedQuestCheck(pItem->GetEntry(), count);
|
||||
pItem->SetCount(pItem->GetCount() - packet.Count);
|
||||
_player->ItemRemovedQuestCheck(pItem->GetEntry(), packet.Count);
|
||||
if (_player->IsInWorld())
|
||||
pItem->SendUpdateToPlayer(_player);
|
||||
pItem->SetState(ITEM_CHANGED, _player);
|
||||
@@ -897,25 +863,20 @@ void WorldSession::HandleSellItemOpcode(WorldPacket& recvData)
|
||||
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money);
|
||||
}
|
||||
else
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, itemguid, 0);
|
||||
_player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, packet.ItemGuid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void WorldSession::HandleBuybackItem(WorldPacket& recvData)
|
||||
void WorldSession::HandleBuybackItem(WorldPackets::Item::BuybackItem& packet)
|
||||
{
|
||||
ObjectGuid vendorguid;
|
||||
uint32 slot;
|
||||
|
||||
recvData >> vendorguid >> slot;
|
||||
|
||||
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
|
||||
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.VendorGuid, UNIT_NPC_FLAG_VENDOR);
|
||||
if (!creature)
|
||||
{
|
||||
LOG_DEBUG("network", "WORLD: HandleBuybackItem - Unit ({}) not found or you can not interact with him.", vendorguid.ToString());
|
||||
LOG_DEBUG("network", "WORLD: HandleBuybackItem - Unit ({}) not found or you can not interact with him.", packet.VendorGuid.ToString());
|
||||
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, nullptr, ObjectGuid::Empty, 0);
|
||||
return;
|
||||
}
|
||||
@@ -924,10 +885,10 @@ void WorldSession::HandleBuybackItem(WorldPacket& recvData)
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
Item* pItem = _player->GetItemFromBuyBackSlot(slot);
|
||||
Item* pItem = _player->GetItemFromBuyBackSlot(packet.Slot);
|
||||
if (pItem)
|
||||
{
|
||||
uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START);
|
||||
uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + packet.Slot - BUYBACK_SLOT_START);
|
||||
if (!_player->HasEnoughMoney(price))
|
||||
{
|
||||
_player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, pItem->GetEntry(), 0);
|
||||
@@ -948,7 +909,7 @@ void WorldSession::HandleBuybackItem(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
_player->ModifyMoney(-(int32)price);
|
||||
_player->RemoveItemFromBuyBackSlot(slot, false);
|
||||
_player->RemoveItemFromBuyBackSlot(packet.Slot, false);
|
||||
_player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount());
|
||||
_player->StoreItem(dest, pItem, true);
|
||||
}
|
||||
@@ -960,24 +921,18 @@ void WorldSession::HandleBuybackItem(WorldPacket& recvData)
|
||||
_player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, 0, 0);
|
||||
}
|
||||
|
||||
void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleBuyItemInSlotOpcode(WorldPackets::Item::BuyItemInSlot& packet)
|
||||
{
|
||||
ObjectGuid vendorguid, bagguid;
|
||||
uint32 item, slot, count;
|
||||
uint8 bagslot;
|
||||
|
||||
recvData >> vendorguid >> item >> slot >> bagguid >> bagslot >> count;
|
||||
|
||||
// client expects count starting at 1, and we send vendorslot+1 to client already
|
||||
if (slot > 0)
|
||||
--slot;
|
||||
if (packet.Slot > 0)
|
||||
--packet.Slot;
|
||||
else
|
||||
return; // cheating
|
||||
return; // cheating
|
||||
|
||||
uint8 bag = NULL_BAG; // init for case invalid bagGUID
|
||||
uint8 bag = NULL_BAG; // init for case invalid bagGUID
|
||||
|
||||
// find bag slot by bag guid
|
||||
if (bagguid == _player->GetGUID())
|
||||
if (packet.BagGuid == _player->GetGUID())
|
||||
bag = INVENTORY_SLOT_BAG_0;
|
||||
else
|
||||
{
|
||||
@@ -985,7 +940,7 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData)
|
||||
{
|
||||
if (Bag* pBag = _player->GetBagByPos(i))
|
||||
{
|
||||
if (bagguid == pBag->GetGUID())
|
||||
if (packet.BagGuid == pBag->GetGUID())
|
||||
{
|
||||
bag = i;
|
||||
break;
|
||||
@@ -998,38 +953,28 @@ void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData)
|
||||
if (bag == NULL_BAG)
|
||||
return;
|
||||
|
||||
GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, bag, bagslot);
|
||||
GetPlayer()->BuyItemFromVendorSlot(packet.VendorGuid, packet.Slot, packet.Item, packet.Count, bag, packet.BagSlot);
|
||||
}
|
||||
|
||||
void WorldSession::HandleBuyItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleBuyItemOpcode(WorldPackets::Item::BuyItem& packet)
|
||||
{
|
||||
ObjectGuid vendorguid;
|
||||
uint32 item, slot, count;
|
||||
uint8 unk1;
|
||||
|
||||
recvData >> vendorguid >> item >> slot >> count >> unk1;
|
||||
|
||||
// client expects count starting at 1, and we send vendorslot+1 to client already
|
||||
if (slot > 0)
|
||||
--slot;
|
||||
if (packet.Slot > 0)
|
||||
--packet.Slot;
|
||||
else
|
||||
return; // cheating
|
||||
|
||||
GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, NULL_BAG, NULL_SLOT);
|
||||
GetPlayer()->BuyItemFromVendorSlot(packet.VendorGuid, packet.Slot, packet.Item, packet.Count, NULL_BAG, NULL_SLOT);
|
||||
}
|
||||
|
||||
void WorldSession::HandleListInventoryOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleListInventoryOpcode(WorldPackets::Item::ListInventory& packet)
|
||||
{
|
||||
ObjectGuid guid;
|
||||
|
||||
recvData >> guid;
|
||||
|
||||
if (!GetPlayer()->IsAlive())
|
||||
return;
|
||||
|
||||
LOG_DEBUG("network", "WORLD: Recvd CMSG_LIST_INVENTORY");
|
||||
|
||||
SendListInventory(guid);
|
||||
SendListInventory(packet.VendorGuid);
|
||||
}
|
||||
|
||||
void WorldSession::SendListInventory(ObjectGuid vendorGuid, uint32 vendorEntry)
|
||||
@@ -1143,18 +1088,14 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid, uint32 vendorEntry)
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleAutoStoreBagItemOpcode(WorldPackets::Item::AutoStoreBagItem& packet)
|
||||
{
|
||||
//LOG_DEBUG("network.opcode", "WORLD: CMSG_AUTOSTORE_BAG_ITEM");
|
||||
uint8 srcbag, srcslot, dstbag;
|
||||
|
||||
recvData >> srcbag >> srcslot >> dstbag;
|
||||
|
||||
Item* pItem = _player->GetItemByPos(srcbag, srcslot);
|
||||
Item* pItem = _player->GetItemByPos(packet.SourceBag, packet.SourceSlot);
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
if (!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos
|
||||
if (!_player->IsValidPos(packet.DestinationBag, NULL_SLOT, false)) // can be autostore pos
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, nullptr, nullptr);
|
||||
return;
|
||||
@@ -1174,7 +1115,7 @@ void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
ItemPosCountVec dest;
|
||||
InventoryResult msg = _player->CanStoreItem(dstbag, NULL_SLOT, dest, pItem, false);
|
||||
InventoryResult msg = _player->CanStoreItem(packet.DestinationBag, NULL_SLOT, dest, pItem, false);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
{
|
||||
_player->SendEquipError(msg, pItem, nullptr);
|
||||
@@ -1189,7 +1130,7 @@ void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
_player->RemoveItem(srcbag, srcslot, true);
|
||||
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true);
|
||||
_player->StoreItem(dest, pItem, true);
|
||||
_player->UpdateTitansGrip();
|
||||
}
|
||||
@@ -1223,23 +1164,22 @@ void WorldSession::HandleSetAmmoOpcode(WorldPacket& recvData)
|
||||
|
||||
void WorldSession::SendEnchantmentLog(ObjectGuid target, ObjectGuid caster, uint32 itemId, uint32 enchantId)
|
||||
{
|
||||
WorldPacket data(SMSG_ENCHANTMENTLOG, (8 + 8 + 4 + 4)); // last check 2.0.10
|
||||
data << target.WriteAsPacked();
|
||||
data << caster.WriteAsPacked();
|
||||
data << uint32(itemId);
|
||||
data << uint32(enchantId);
|
||||
GetPlayer()->SendMessageToSet(&data, true);
|
||||
WorldPackets::Item::EnchantmentLog enchantmentLog;
|
||||
enchantmentLog.Target = target.WriteAsPacked();
|
||||
enchantmentLog.Caster = caster.WriteAsPacked();
|
||||
enchantmentLog.ItemId = itemId;
|
||||
enchantmentLog.EnchantId = enchantId;
|
||||
GetPlayer()->SendMessageToSet(enchantmentLog.Write(), true);
|
||||
}
|
||||
|
||||
void WorldSession::SendItemEnchantTimeUpdate(ObjectGuid Playerguid, ObjectGuid Itemguid, uint32 slot, uint32 Duration)
|
||||
{
|
||||
// last check 2.0.10
|
||||
WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8 + 4 + 4 + 8));
|
||||
data << Itemguid;
|
||||
data << uint32(slot);
|
||||
data << uint32(Duration);
|
||||
data << Playerguid;
|
||||
SendPacket(&data);
|
||||
WorldPackets::Item::ItemEnchantTimeUpdate itemEnchantTimeUpdate;
|
||||
itemEnchantTimeUpdate.ItemGuid = Itemguid;
|
||||
itemEnchantTimeUpdate.Slot = slot;
|
||||
itemEnchantTimeUpdate.Duration = Duration;
|
||||
itemEnchantTimeUpdate.PlayerGuid = Playerguid;
|
||||
SendPacket(itemEnchantTimeUpdate.Write());
|
||||
}
|
||||
|
||||
void WorldSession::HandleItemNameQueryOpcode(WorldPacket& recvData)
|
||||
@@ -1266,18 +1206,13 @@ void WorldSession::HandleItemNameQueryOpcode(WorldPacket& recvData)
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleWrapItemOpcode(WorldPackets::Item::WrapItem& packet)
|
||||
{
|
||||
LOG_DEBUG("network", "Received opcode CMSG_WRAP_ITEM");
|
||||
|
||||
uint8 gift_bag, gift_slot, item_bag, item_slot;
|
||||
LOG_DEBUG("network", "WRAP: receive GiftBag = {}, GiftSlot = {}, ItemBag = {}, ItemSlot = {}", packet.GiftBag, packet.GiftSlot, packet.ItemBag, packet.ItemSlot);
|
||||
|
||||
recvData >> gift_bag >> gift_slot; // paper
|
||||
recvData >> item_bag >> item_slot; // item
|
||||
|
||||
LOG_DEBUG("network", "WRAP: receive gift_bag = {}, gift_slot = {}, item_bag = {}, item_slot = {}", gift_bag, gift_slot, item_bag, item_slot);
|
||||
|
||||
Item* gift = _player->GetItemByPos(gift_bag, gift_slot);
|
||||
Item* gift = _player->GetItemByPos(packet.GiftBag, packet.GiftSlot);
|
||||
if (!gift)
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, nullptr);
|
||||
@@ -1290,7 +1225,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
Item* item = _player->GetItemByPos(item_bag, item_slot);
|
||||
Item* item = _player->GetItemByPos(packet.ItemBag, packet.ItemSlot);
|
||||
|
||||
if (!item)
|
||||
{
|
||||
@@ -1305,7 +1240,7 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
if (item == gift) // not possable with pacjket from real client
|
||||
if (item == gift) // not possible with packet from real client
|
||||
{
|
||||
_player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, nullptr);
|
||||
return;
|
||||
@@ -1399,26 +1334,19 @@ void WorldSession::HandleWrapItemOpcode(WorldPacket& recvData)
|
||||
_player->DestroyItemCount(gift, count, true);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleSocketOpcode(WorldPackets::Item::SocketGems& packet)
|
||||
{
|
||||
LOG_DEBUG("network", "WORLD: CMSG_SOCKET_GEMS");
|
||||
|
||||
ObjectGuid item_guid;
|
||||
ObjectGuid gem_guids[MAX_GEM_SOCKETS];
|
||||
|
||||
recvData >> item_guid;
|
||||
if (!item_guid)
|
||||
if (!packet.ItemGuid)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
|
||||
recvData >> gem_guids[i];
|
||||
|
||||
//cheat -> tried to socket same gem multiple times
|
||||
if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) ||
|
||||
(gem_guids[1] && (gem_guids[1] == gem_guids[2])))
|
||||
if ((packet.GemGuids[0] && (packet.GemGuids[0] == packet.GemGuids[1] || packet.GemGuids[0] == packet.GemGuids[2])) ||
|
||||
(packet.GemGuids[1] && (packet.GemGuids[1] == packet.GemGuids[2])))
|
||||
return;
|
||||
|
||||
Item* itemTarget = _player->GetItemByGuid(item_guid);
|
||||
Item* itemTarget = _player->GetItemByGuid(packet.ItemGuid);
|
||||
if (!itemTarget) //missing item to socket
|
||||
return;
|
||||
|
||||
@@ -1431,7 +1359,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
|
||||
Item* Gems[MAX_GEM_SOCKETS];
|
||||
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
|
||||
Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : nullptr;
|
||||
Gems[i] = packet.GemGuids[i] ? _player->GetItemByGuid(packet.GemGuids[i]) : nullptr;
|
||||
|
||||
GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS];
|
||||
for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage
|
||||
@@ -1572,7 +1500,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
if (GemEnchants[i])
|
||||
{
|
||||
itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), GemEnchants[i], 0, 0, _player->GetGUID());
|
||||
if (Item* guidItem = _player->GetItemByGuid(gem_guids[i]))
|
||||
if (Item* guidItem = _player->GetItemByGuid(packet.GemGuids[i]))
|
||||
_player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true);
|
||||
}
|
||||
}
|
||||
@@ -1597,19 +1525,15 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData)
|
||||
itemTarget->SendUpdateSockets();
|
||||
}
|
||||
|
||||
void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPackets::Item::CancelTempEnchantment& packet)
|
||||
{
|
||||
LOG_DEBUG("network", "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT");
|
||||
|
||||
uint32 eslot;
|
||||
|
||||
recvData >> eslot;
|
||||
|
||||
// apply only to equipped item
|
||||
if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot))
|
||||
if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, packet.EquipmentSlot))
|
||||
return;
|
||||
|
||||
Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot);
|
||||
Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, packet.EquipmentSlot);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
@@ -1621,14 +1545,11 @@ void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recvData)
|
||||
item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT);
|
||||
}
|
||||
|
||||
void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recvData)
|
||||
void WorldSession::HandleItemRefundInfoRequest(WorldPackets::Item::ItemRefundInfo& packet)
|
||||
{
|
||||
LOG_DEBUG("network", "WORLD: CMSG_ITEM_REFUND_INFO");
|
||||
|
||||
ObjectGuid guid;
|
||||
recvData >> guid; // item guid
|
||||
|
||||
Item* item = _player->GetItemByGuid(guid);
|
||||
Item* item = _player->GetItemByGuid(packet.ItemGuid);
|
||||
if (!item)
|
||||
{
|
||||
LOG_DEBUG("network", "Item refund: item not found!");
|
||||
@@ -1638,13 +1559,11 @@ void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recvData)
|
||||
GetPlayer()->SendRefundInfo(item);
|
||||
}
|
||||
|
||||
void WorldSession::HandleItemRefund(WorldPacket& recvData)
|
||||
void WorldSession::HandleItemRefund(WorldPackets::Item::ItemRefund& packet)
|
||||
{
|
||||
LOG_DEBUG("network", "WORLD: CMSG_ITEM_REFUND");
|
||||
ObjectGuid guid;
|
||||
recvData >> guid; // item guid
|
||||
|
||||
Item* item = _player->GetItemByGuid(guid);
|
||||
Item* item = _player->GetItemByGuid(packet.ItemGuid);
|
||||
if (!item)
|
||||
{
|
||||
LOG_DEBUG("network", "Item refund: item not found!");
|
||||
@@ -1652,7 +1571,7 @@ void WorldSession::HandleItemRefund(WorldPacket& recvData)
|
||||
}
|
||||
|
||||
// Don't try to refund item currently being disenchanted
|
||||
if (_player->GetLootGUID() == guid)
|
||||
if (_player->GetLootGUID() == packet.ItemGuid)
|
||||
return;
|
||||
|
||||
GetPlayer()->RefundItem(item);
|
||||
|
||||
@@ -183,7 +183,9 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
|
||||
if (!charter)
|
||||
return;
|
||||
|
||||
charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUID().GetCounter());
|
||||
// Use a 31-bit safe petition id instead of the raw item guid
|
||||
uint32 petitionId = sPetitionMgr->GeneratePetitionId();
|
||||
charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, petitionId);
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id
|
||||
// ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item)
|
||||
charter->SetState(ITEM_CHANGED, _player);
|
||||
@@ -211,16 +213,18 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
|
||||
// xinef: petition pointer is invalid from now on
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION);
|
||||
stmt->SetData(0, _player->GetGUID().GetCounter());
|
||||
stmt->SetData(1, charter->GetGUID().GetCounter());
|
||||
stmt->SetData(2, name);
|
||||
stmt->SetData(3, uint8(type));
|
||||
// petition_id, ownerguid, petitionguid(item guid), name, type
|
||||
stmt->SetData(0, petitionId);
|
||||
stmt->SetData(1, _player->GetGUID().GetCounter());
|
||||
stmt->SetData(2, charter->GetGUID().GetCounter());
|
||||
stmt->SetData(3, name);
|
||||
stmt->SetData(4, uint8(type));
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
// xinef: fill petition store
|
||||
sPetitionMgr->AddPetition(charter->GetGUID(), _player->GetGUID(), name, uint8(type));
|
||||
// xinef: fill petition store (include petitionId)
|
||||
sPetitionMgr->AddPetition(charter->GetGUID(), _player->GetGUID(), name, uint8(type), petitionId);
|
||||
}
|
||||
|
||||
void WorldSession::HandlePetitionShowSignOpcode(WorldPacket& recvData)
|
||||
@@ -249,7 +253,7 @@ void WorldSession::HandlePetitionShowSignOpcode(WorldPacket& recvData)
|
||||
WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8 + 8 + 4 + 1 + signs * 12));
|
||||
data << petitionguid; // petition guid
|
||||
data << _player->GetGUID(); // owner guid
|
||||
data << uint32(petitionguid.GetCounter()); // guild guid
|
||||
data << uint32(petition->petitionId); // guild/team id (31-bit safe)
|
||||
data << uint8(signs); // sign's count
|
||||
|
||||
if (signs)
|
||||
@@ -286,7 +290,7 @@ void WorldSession::SendPetitionQueryOpcode(ObjectGuid petitionguid)
|
||||
|
||||
uint8 type = petition->petitionType;
|
||||
WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4 + 8 + petition->petitionName.size() + 1 + 1 + 4 * 12 + 2 + 10));
|
||||
data << uint32(petitionguid.GetCounter()); // guild/team guid (in Trinity always same as petition low guid
|
||||
data << uint32(petition->petitionId); // guild/team id (was item low guid)
|
||||
data << petition->ownerGuid; // charter owner guid
|
||||
data << petition->petitionName; // name (guild/arena team)
|
||||
data << uint8(0); // some string
|
||||
@@ -373,7 +377,7 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket& recvData)
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME);
|
||||
|
||||
stmt->SetData(0, newName);
|
||||
stmt->SetData(1, petitionGuid.GetCounter());
|
||||
stmt->SetData(1, petition->petitionId);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
@@ -499,7 +503,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData)
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION_SIGNATURE);
|
||||
|
||||
stmt->SetData(0, petition->ownerGuid.GetCounter());
|
||||
stmt->SetData(1, petitionGuid.GetCounter());
|
||||
stmt->SetData(1, petition->petitionId);
|
||||
stmt->SetData(2, playerGuid.GetCounter());
|
||||
stmt->SetData(3, GetAccountId());
|
||||
|
||||
@@ -627,7 +631,7 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket& recvData)
|
||||
WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8 + 8 + 4 + signs + signs * 12));
|
||||
data << petitionguid; // petition guid
|
||||
data << _player->GetGUID(); // owner guid
|
||||
data << uint32(petitionguid.GetCounter()); // guild guid
|
||||
data << uint32(petition->petitionId); // guild/team id (31-bit safe)
|
||||
data << uint8(signs); // sign's count
|
||||
|
||||
if (signs)
|
||||
@@ -792,12 +796,12 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData)
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_BY_GUID);
|
||||
stmt->SetData(0, petitionGuid.GetCounter());
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_BY_ID);
|
||||
stmt->SetData(0, petition->petitionId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_SIGNATURE_BY_GUID);
|
||||
stmt->SetData(0, petitionGuid.GetCounter());
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_SIGNATURE_BY_ID);
|
||||
stmt->SetData(0, petition->petitionId);
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
@@ -73,6 +73,8 @@ Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
|
||||
|
||||
//lets initialize visibility distance for map
|
||||
Map::InitVisibilityDistance();
|
||||
|
||||
_corpseUpdateTimer.SetInterval(20 * MINUTE * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
// Hook called after map is created AND after added to map list
|
||||
@@ -116,6 +118,8 @@ void Map::AddToGrid(Creature* obj, Cell const& cell)
|
||||
{
|
||||
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
|
||||
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
|
||||
if (obj->IsFarVisible())
|
||||
grid->AddFarVisibleObject(cell.CellX(), cell.CellY(), obj);
|
||||
|
||||
obj->SetCurrentCell(cell);
|
||||
}
|
||||
@@ -125,6 +129,8 @@ void Map::AddToGrid(GameObject* obj, Cell const& cell)
|
||||
{
|
||||
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
|
||||
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
|
||||
if (obj->IsFarVisible())
|
||||
grid->AddFarVisibleObject(cell.CellX(), cell.CellY(), obj);
|
||||
|
||||
obj->SetCurrentCell(cell);
|
||||
}
|
||||
@@ -494,6 +500,8 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
||||
|
||||
HandleDelayedVisibility();
|
||||
|
||||
UpdateExpiredCorpses(t_diff);
|
||||
|
||||
sScriptMgr->OnMapUpdate(this, t_diff);
|
||||
|
||||
METRIC_VALUE("map_creatures", uint64(GetObjectsStore().Size<Creature>()),
|
||||
@@ -600,6 +608,69 @@ void Map::RemoveObjectFromMapUpdateList(WorldObject* obj)
|
||||
_RemoveObjectFromUpdateList(obj);
|
||||
}
|
||||
|
||||
// Used in VisibilityDistanceType::Large and VisibilityDistanceType::Gigantic
|
||||
void Map::AddWorldObjectToFarVisibleMap(WorldObject* obj)
|
||||
{
|
||||
if (Creature* creature = obj->ToCreature())
|
||||
{
|
||||
if (!creature->IsInGrid())
|
||||
return;
|
||||
|
||||
Cell curr_cell = creature->GetCurrentCell();
|
||||
MapGridType* grid = GetMapGrid(curr_cell.GridX(), curr_cell.GridY());
|
||||
grid->AddFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), creature);
|
||||
}
|
||||
else if (GameObject* go = obj->ToGameObject())
|
||||
{
|
||||
if (!go->IsInGrid())
|
||||
return;
|
||||
|
||||
Cell curr_cell = go->GetCurrentCell();
|
||||
MapGridType* grid = GetMapGrid(curr_cell.GridX(), curr_cell.GridY());
|
||||
grid->AddFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), go);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::RemoveWorldObjectFromFarVisibleMap(WorldObject* obj)
|
||||
{
|
||||
if (Creature* creature = obj->ToCreature())
|
||||
{
|
||||
Cell curr_cell = creature->GetCurrentCell();
|
||||
MapGridType* grid = GetMapGrid(curr_cell.GridX(), curr_cell.GridY());
|
||||
grid->RemoveFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), creature);
|
||||
}
|
||||
else if (GameObject* go = obj->ToGameObject())
|
||||
{
|
||||
Cell curr_cell = go->GetCurrentCell();
|
||||
MapGridType* grid = GetMapGrid(curr_cell.GridX(), curr_cell.GridY());
|
||||
grid->RemoveFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), go);
|
||||
}
|
||||
}
|
||||
|
||||
// Used in VisibilityDistanceType::Infinite
|
||||
void Map::AddWorldObjectToZoneWideVisibleMap(uint32 zoneId, WorldObject* obj)
|
||||
{
|
||||
_zoneWideVisibleWorldObjectsMap[zoneId].insert(obj);
|
||||
}
|
||||
|
||||
void Map::RemoveWorldObjectFromZoneWideVisibleMap(uint32 zoneId, WorldObject* obj)
|
||||
{
|
||||
ZoneWideVisibleWorldObjectsMap::iterator itr = _zoneWideVisibleWorldObjectsMap.find(zoneId);
|
||||
if (itr == _zoneWideVisibleWorldObjectsMap.end())
|
||||
return;
|
||||
|
||||
itr->second.erase(obj);
|
||||
}
|
||||
|
||||
ZoneWideVisibleWorldObjectsSet const* Map::GetZoneWideVisibleWorldObjectsForZone(uint32 zoneId) const
|
||||
{
|
||||
ZoneWideVisibleWorldObjectsMap::const_iterator itr = _zoneWideVisibleWorldObjectsMap.find(zoneId);
|
||||
if (itr == _zoneWideVisibleWorldObjectsMap.end())
|
||||
return nullptr;
|
||||
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
void Map::HandleDelayedVisibility()
|
||||
{
|
||||
if (i_objectsForDelayedVisibility.empty())
|
||||
@@ -652,6 +723,8 @@ void Map::RemoveFromMap(T* obj, bool remove)
|
||||
obj->RemoveFromWorld();
|
||||
|
||||
obj->RemoveFromGrid();
|
||||
if (obj->IsFarVisible())
|
||||
RemoveWorldObjectFromFarVisibleMap(obj);
|
||||
|
||||
obj->ResetMap();
|
||||
|
||||
@@ -848,6 +921,11 @@ void Map::MoveAllCreaturesInMoveList()
|
||||
|
||||
Cell const& old_cell = c->GetCurrentCell();
|
||||
Cell new_cell(c->GetPositionX(), c->GetPositionY());
|
||||
if (c->IsFarVisible())
|
||||
{
|
||||
// Removes via GetCurrentCell, added back in AddToGrid
|
||||
RemoveWorldObjectFromFarVisibleMap(c);
|
||||
}
|
||||
|
||||
c->RemoveFromGrid();
|
||||
if (old_cell.DiffGrid(new_cell))
|
||||
@@ -878,6 +956,12 @@ void Map::MoveAllGameObjectsInMoveList()
|
||||
Cell const& old_cell = go->GetCurrentCell();
|
||||
Cell new_cell(go->GetPositionX(), go->GetPositionY());
|
||||
|
||||
if (go->IsFarVisible())
|
||||
{
|
||||
// Removes via GetCurrentCell, added back in AddToGrid
|
||||
RemoveWorldObjectFromFarVisibleMap(go);
|
||||
}
|
||||
|
||||
go->RemoveFromGrid();
|
||||
if (old_cell.DiffGrid(new_cell))
|
||||
EnsureGridLoaded(new_cell);
|
||||
@@ -1580,6 +1664,17 @@ void Map::SendInitSelf(Player* player)
|
||||
player->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Map::UpdateExpiredCorpses(uint32 const diff)
|
||||
{
|
||||
_corpseUpdateTimer.Update(diff);
|
||||
if (!_corpseUpdateTimer.Passed())
|
||||
return;
|
||||
|
||||
RemoveOldCorpses();
|
||||
|
||||
_corpseUpdateTimer.Reset();
|
||||
}
|
||||
|
||||
void Map::SendInitTransports(Player* player)
|
||||
{
|
||||
if (_transports.empty())
|
||||
|
||||
@@ -147,6 +147,8 @@ struct ZoneDynamicInfo
|
||||
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
|
||||
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
|
||||
typedef std::unordered_set<Transport*> TransportsContainer;
|
||||
typedef std::unordered_set<WorldObject*> ZoneWideVisibleWorldObjectsSet;
|
||||
typedef std::unordered_map<uint32 /*ZoneId*/, ZoneWideVisibleWorldObjectsSet> ZoneWideVisibleWorldObjectsMap;
|
||||
|
||||
enum EncounterCreditType : uint8
|
||||
{
|
||||
@@ -443,6 +445,8 @@ public:
|
||||
void SendZoneDynamicInfo(Player* player);
|
||||
void SendInitSelf(Player* player);
|
||||
|
||||
void UpdateExpiredCorpses(uint32 const diff);
|
||||
|
||||
void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0);
|
||||
void SetZoneMusic(uint32 zoneId, uint32 musicId);
|
||||
void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade);
|
||||
@@ -494,6 +498,12 @@ public:
|
||||
typedef std::vector<WorldObject*> UpdatableObjectList;
|
||||
typedef std::unordered_set<WorldObject*> PendingAddUpdatableObjectList;
|
||||
|
||||
void AddWorldObjectToFarVisibleMap(WorldObject* obj);
|
||||
void RemoveWorldObjectFromFarVisibleMap(WorldObject* obj);
|
||||
void AddWorldObjectToZoneWideVisibleMap(uint32 zoneId, WorldObject* obj);
|
||||
void RemoveWorldObjectFromZoneWideVisibleMap(uint32 zoneId, WorldObject* obj);
|
||||
ZoneWideVisibleWorldObjectsSet const* GetZoneWideVisibleWorldObjectsForZone(uint32 zoneId) const;
|
||||
|
||||
private:
|
||||
|
||||
template<class T> void InitializeObject(T* obj);
|
||||
@@ -576,6 +586,8 @@ private:
|
||||
ZoneDynamicInfoMap _zoneDynamicInfo;
|
||||
uint32 _defaultLight;
|
||||
|
||||
IntervalTimer _corpseUpdateTimer;
|
||||
|
||||
template<HighGuid high>
|
||||
inline ObjectGuidGeneratorBase& GetGuidSequenceGenerator()
|
||||
{
|
||||
@@ -599,6 +611,7 @@ private:
|
||||
UpdatableObjectList _updatableObjectList;
|
||||
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
|
||||
IntervalTimer _updatableObjectListRecheckTimer;
|
||||
ZoneWideVisibleWorldObjectsMap _zoneWideVisibleWorldObjectsMap;
|
||||
};
|
||||
|
||||
enum InstanceResetMethod
|
||||
|
||||
@@ -41,8 +41,9 @@ void PetitionMgr::LoadPetitions()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
PetitionStore.clear();
|
||||
PetitionIdToItemGuid.clear();
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT ownerguid, petitionguid, name, type FROM petition");
|
||||
QueryResult result = CharacterDatabase.Query("SELECT ownerguid, petitionguid, name, type, petition_id FROM petition");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Petitions!");
|
||||
@@ -51,13 +52,24 @@ void PetitionMgr::LoadPetitions()
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
uint32 maxId = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
AddPetition(ObjectGuid::Create<HighGuid::Item>(fields[1].Get<uint32>()), ObjectGuid::Create<HighGuid::Player>(fields[0].Get<uint32>()), fields[2].Get<std::string>(), fields[3].Get<uint8>());
|
||||
uint32 itemLow = fields[1].Get<uint32>();
|
||||
uint32 petitionId = fields[4].Get<uint32>();
|
||||
ObjectGuid itemGuid = ObjectGuid::Create<HighGuid::Item>(itemLow);
|
||||
ObjectGuid ownerGuid = ObjectGuid::Create<HighGuid::Player>(fields[0].Get<uint32>());
|
||||
AddPetition(itemGuid, ownerGuid, fields[2].Get<std::string>(), fields[3].Get<uint8>(), petitionId);
|
||||
PetitionIdToItemGuid[petitionId] = itemGuid;
|
||||
if (petitionId > maxId)
|
||||
maxId = petitionId;
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
// initialize next id (keep within 31-bit safe range)
|
||||
_nextPetitionId = std::min<uint32>(std::max<uint32>(maxId + 1, 1), 0x7FFFFFFFu);
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Petitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
@@ -67,7 +79,7 @@ void PetitionMgr::LoadSignatures()
|
||||
uint32 oldMSTime = getMSTime();
|
||||
SignatureStore.clear();
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT petitionguid, playerguid, player_account FROM petition_sign");
|
||||
QueryResult result = CharacterDatabase.Query("SELECT petition_id, playerguid, player_account FROM petition_sign");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 Petition signs!");
|
||||
@@ -79,7 +91,11 @@ void PetitionMgr::LoadSignatures()
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
AddSignature(ObjectGuid::Create<HighGuid::Item>(fields[0].Get<uint32>()), fields[2].Get<uint32>(), ObjectGuid::Create<HighGuid::Player>(fields[1].Get<uint32>()));
|
||||
uint32 petitionId = fields[0].Get<uint32>();
|
||||
auto it = PetitionIdToItemGuid.find(petitionId);
|
||||
if (it == PetitionIdToItemGuid.end())
|
||||
continue; // orphan signature, skip
|
||||
AddSignature(it->second, fields[2].Get<uint32>(), ObjectGuid::Create<HighGuid::Player>(fields[1].Get<uint32>()));
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
@@ -87,10 +103,11 @@ void PetitionMgr::LoadSignatures()
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void PetitionMgr::AddPetition(ObjectGuid petitionGUID, ObjectGuid ownerGuid, std::string const& name, uint8 type)
|
||||
void PetitionMgr::AddPetition(ObjectGuid petitionGUID, ObjectGuid ownerGuid, std::string const& name, uint8 type, uint32 petitionId)
|
||||
{
|
||||
Petition& p = PetitionStore[petitionGUID];
|
||||
p.petitionGuid = petitionGUID;
|
||||
p.petitionId = petitionId;
|
||||
p.ownerGuid = ownerGuid;
|
||||
p.petitionName = name;
|
||||
p.petitionType = type;
|
||||
@@ -102,7 +119,12 @@ void PetitionMgr::AddPetition(ObjectGuid petitionGUID, ObjectGuid ownerGuid, std
|
||||
|
||||
void PetitionMgr::RemovePetition(ObjectGuid petitionGUID)
|
||||
{
|
||||
PetitionStore.erase(petitionGUID);
|
||||
auto it = PetitionStore.find(petitionGUID);
|
||||
if (it != PetitionStore.end())
|
||||
{
|
||||
PetitionIdToItemGuid.erase(it->second.petitionId);
|
||||
PetitionStore.erase(it);
|
||||
}
|
||||
|
||||
// remove signatures
|
||||
SignatureStore.erase(petitionGUID);
|
||||
@@ -143,6 +165,15 @@ Petition const* PetitionMgr::GetPetition(ObjectGuid petitionGUID) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Petition const* PetitionMgr::GetPetitionById(uint32 petitionId) const
|
||||
{
|
||||
auto it = PetitionIdToItemGuid.find(petitionId);
|
||||
if (it == PetitionIdToItemGuid.end())
|
||||
return nullptr;
|
||||
|
||||
return GetPetition(it->second);
|
||||
}
|
||||
|
||||
Petition const* PetitionMgr::GetPetitionByOwnerWithType(ObjectGuid ownerGuid, uint8 type) const
|
||||
{
|
||||
for (PetitionContainer::const_iterator itr = PetitionStore.begin(); itr != PetitionStore.end(); ++itr)
|
||||
@@ -189,3 +220,37 @@ void PetitionMgr::RemoveSignaturesByPlayerAndType(ObjectGuid playerGuid, uint8 t
|
||||
itr->second.signatureMap.erase(signItr);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 PetitionMgr::GeneratePetitionId()
|
||||
{
|
||||
// ensure 31-bit range and avoid collisions with already loaded petitions
|
||||
if (_nextPetitionId == 0 || _nextPetitionId >= 0x7FFFFFFF)
|
||||
_nextPetitionId = 1;
|
||||
|
||||
// find first free id
|
||||
while (PetitionIdToItemGuid.count(_nextPetitionId))
|
||||
{
|
||||
++_nextPetitionId;
|
||||
if (_nextPetitionId >= 0x7FFFFFFF)
|
||||
_nextPetitionId = 1;
|
||||
}
|
||||
|
||||
uint32 id = _nextPetitionId++;
|
||||
if (_nextPetitionId >= 0x7FFFFFFF)
|
||||
_nextPetitionId = 1;
|
||||
return id;
|
||||
}
|
||||
|
||||
uint32 PetitionMgr::GetPetitionIdByItemGuid(ObjectGuid petitionItemGuid) const
|
||||
{
|
||||
Petition const* p = GetPetition(petitionItemGuid);
|
||||
return p ? p->petitionId : 0;
|
||||
}
|
||||
|
||||
ObjectGuid PetitionMgr::GetItemGuidByPetitionId(uint32 petitionId) const
|
||||
{
|
||||
auto it = PetitionIdToItemGuid.find(petitionId);
|
||||
if (it == PetitionIdToItemGuid.end())
|
||||
return ObjectGuid::Empty;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "ObjectGuid.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
#define CHARTER_DISPLAY_ID 16161
|
||||
@@ -37,14 +38,21 @@ typedef std::map<ObjectGuid, uint32> SignatureMap;
|
||||
|
||||
struct Petition
|
||||
{
|
||||
// Item GUID of the charter item (used to find the item in inventory)
|
||||
ObjectGuid petitionGuid;
|
||||
// New 31-bit safe petition identifier used in packets/DB relations
|
||||
uint32 petitionId;
|
||||
// Owner character GUID
|
||||
ObjectGuid ownerGuid;
|
||||
// Petition type (guild / arena)
|
||||
uint8 petitionType;
|
||||
// Name associated with the petition (guild/arena name)
|
||||
std::string petitionName;
|
||||
};
|
||||
|
||||
struct Signatures
|
||||
{
|
||||
// Keep keying by item-guid for backward compatibility in code paths
|
||||
ObjectGuid petitionGuid;
|
||||
SignatureMap signatureMap;
|
||||
};
|
||||
@@ -65,10 +73,11 @@ public:
|
||||
void LoadSignatures();
|
||||
|
||||
// Petitions
|
||||
void AddPetition(ObjectGuid petitionGUID, ObjectGuid ownerGuid, std::string const& name, uint8 type);
|
||||
void AddPetition(ObjectGuid petitionGUID, ObjectGuid ownerGuid, std::string const& name, uint8 type, uint32 petitionId);
|
||||
void RemovePetition(ObjectGuid petitionGUID);
|
||||
void RemovePetitionByOwnerAndType(ObjectGuid ownerGuid, uint8 type);
|
||||
Petition const* GetPetition(ObjectGuid petitionGUID) const;
|
||||
Petition const* GetPetitionById(uint32 petitionId) const;
|
||||
Petition const* GetPetitionByOwnerWithType(ObjectGuid ownerGuid, uint8 type) const;
|
||||
PetitionContainer* GetPetitionStore() { return &PetitionStore; }
|
||||
|
||||
@@ -79,9 +88,17 @@ public:
|
||||
Signatures const* GetSignature(ObjectGuid petitionGUID) const;
|
||||
SignatureContainer* GetSignatureStore() { return &SignatureStore; }
|
||||
|
||||
uint32 GeneratePetitionId();
|
||||
uint32 GetPetitionIdByItemGuid(ObjectGuid petitionItemGuid) const;
|
||||
ObjectGuid GetItemGuidByPetitionId(uint32 petitionId) const;
|
||||
|
||||
protected:
|
||||
PetitionContainer PetitionStore;
|
||||
SignatureContainer SignatureStore;
|
||||
// Mapping id -> item-guid to support DB-id lookups
|
||||
std::unordered_map<uint32, ObjectGuid> PetitionIdToItemGuid;
|
||||
// Next petition id (kept < 2^31)
|
||||
uint32 _nextPetitionId = 1;
|
||||
};
|
||||
|
||||
#define sPetitionMgr PetitionMgr::instance()
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "CombatLogPackets.h"
|
||||
#include "CombatPackets.h"
|
||||
#include "GuildPackets.h"
|
||||
#include "ItemPackets.h"
|
||||
#include "LFGPackets.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "PetPackets.h"
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ItemPackets.h"
|
||||
|
||||
void WorldPackets::Item::SplitItem::Read()
|
||||
{
|
||||
_worldPacket >> SourceBag;
|
||||
_worldPacket >> SourceSlot;
|
||||
_worldPacket >> DestinationBag;
|
||||
_worldPacket >> DestinationSlot;
|
||||
_worldPacket >> Count;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::SwapInventoryItem::Read()
|
||||
{
|
||||
_worldPacket >> DestinationSlot;
|
||||
_worldPacket >> SourceSlot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::AutoEquipItemSlot::Read()
|
||||
{
|
||||
_worldPacket >> ItemGuid;
|
||||
_worldPacket >> DestinationSlot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::SwapItem::Read()
|
||||
{
|
||||
_worldPacket >> DestinationBag;
|
||||
_worldPacket >> DestinationSlot;
|
||||
_worldPacket >> SourceBag;
|
||||
_worldPacket >> SourceSlot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::AutoEquipItem::Read()
|
||||
{
|
||||
_worldPacket >> SourceBag;
|
||||
_worldPacket >> SourceSlot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::DestroyItem::Read()
|
||||
{
|
||||
_worldPacket >> Bag;
|
||||
_worldPacket >> Slot;
|
||||
_worldPacket >> Count;
|
||||
_worldPacket >> Data1;
|
||||
_worldPacket >> Data2;
|
||||
_worldPacket >> Data3;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::ReadItem::Read()
|
||||
{
|
||||
_worldPacket >> Bag;
|
||||
_worldPacket >> Slot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::SellItem::Read()
|
||||
{
|
||||
_worldPacket >> VendorGuid;
|
||||
_worldPacket >> ItemGuid;
|
||||
_worldPacket >> Count;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::BuybackItem::Read()
|
||||
{
|
||||
_worldPacket >> VendorGuid;
|
||||
_worldPacket >> Slot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::BuyItemInSlot::Read()
|
||||
{
|
||||
_worldPacket >> VendorGuid;
|
||||
_worldPacket >> Item;
|
||||
_worldPacket >> Slot;
|
||||
_worldPacket >> BagGuid;
|
||||
_worldPacket >> BagSlot;
|
||||
_worldPacket >> Count;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::BuyItem::Read()
|
||||
{
|
||||
_worldPacket >> VendorGuid;
|
||||
_worldPacket >> Item;
|
||||
_worldPacket >> Slot;
|
||||
_worldPacket >> Count;
|
||||
_worldPacket >> Unk;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::ListInventory::Read()
|
||||
{
|
||||
_worldPacket >> VendorGuid;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::AutoStoreBagItem::Read()
|
||||
{
|
||||
_worldPacket >> SourceBag;
|
||||
_worldPacket >> SourceSlot;
|
||||
_worldPacket >> DestinationBag;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Item::EnchantmentLog::Write()
|
||||
{
|
||||
_worldPacket << Target;
|
||||
_worldPacket << Caster;
|
||||
_worldPacket << ItemId;
|
||||
_worldPacket << EnchantId;
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Item::ItemEnchantTimeUpdate::Write()
|
||||
{
|
||||
_worldPacket << ItemGuid;
|
||||
_worldPacket << Slot;
|
||||
_worldPacket << Duration;
|
||||
_worldPacket << PlayerGuid;
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::WrapItem::Read()
|
||||
{
|
||||
_worldPacket >> GiftBag;
|
||||
_worldPacket >> GiftSlot;
|
||||
_worldPacket >> ItemBag;
|
||||
_worldPacket >> ItemSlot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::SocketGems::Read()
|
||||
{
|
||||
_worldPacket >> ItemGuid;
|
||||
for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
|
||||
_worldPacket >> GemGuids[i];
|
||||
}
|
||||
|
||||
void WorldPackets::Item::CancelTempEnchantment::Read()
|
||||
{
|
||||
_worldPacket >> EquipmentSlot;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::ItemRefundInfo::Read()
|
||||
{
|
||||
_worldPacket >> ItemGuid;
|
||||
}
|
||||
|
||||
void WorldPackets::Item::ItemRefund::Read()
|
||||
{
|
||||
_worldPacket >> ItemGuid;
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ItemPackets_h__
|
||||
#define ItemPackets_h__
|
||||
|
||||
#include "Item.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Packet.h"
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
namespace Item
|
||||
{
|
||||
class SplitItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
SplitItem(WorldPacket&& packet) : ClientPacket(CMSG_SPLIT_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 SourceBag = 0;
|
||||
uint8 SourceSlot = 0;
|
||||
uint8 DestinationBag = 0;
|
||||
uint8 DestinationSlot = 0;
|
||||
uint32 Count = 0;
|
||||
};
|
||||
|
||||
class SwapInventoryItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
SwapInventoryItem(WorldPacket&& packet) : ClientPacket(CMSG_SWAP_INV_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 DestinationSlot = 0;
|
||||
uint8 SourceSlot = 0;
|
||||
};
|
||||
|
||||
class AutoEquipItemSlot final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
AutoEquipItemSlot(WorldPacket&& packet) : ClientPacket(CMSG_AUTOEQUIP_ITEM_SLOT, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid ItemGuid;
|
||||
uint8 DestinationSlot = 0;
|
||||
};
|
||||
|
||||
class SwapItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
SwapItem(WorldPacket&& packet) : ClientPacket(CMSG_SWAP_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 DestinationBag = 0;
|
||||
uint8 DestinationSlot = 0;
|
||||
uint8 SourceBag = 0;
|
||||
uint8 SourceSlot = 0;
|
||||
};
|
||||
|
||||
class AutoEquipItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
AutoEquipItem(WorldPacket&& packet) : ClientPacket(CMSG_AUTOEQUIP_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 SourceBag = 0;
|
||||
uint8 SourceSlot = 0;
|
||||
};
|
||||
|
||||
class DestroyItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
DestroyItem(WorldPacket&& packet) : ClientPacket(CMSG_DESTROYITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 Bag = 0;
|
||||
uint8 Slot = 0;
|
||||
uint8 Count = 0;
|
||||
uint8 Data1 = 0;
|
||||
uint8 Data2 = 0;
|
||||
uint8 Data3 = 0;
|
||||
};
|
||||
|
||||
class ReadItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
ReadItem(WorldPacket&& packet) : ClientPacket(CMSG_READ_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 Bag = 0;
|
||||
uint8 Slot = 0;
|
||||
};
|
||||
|
||||
class SellItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
SellItem(WorldPacket&& packet) : ClientPacket(CMSG_SELL_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid VendorGuid;
|
||||
ObjectGuid ItemGuid;
|
||||
uint32 Count = 0;
|
||||
};
|
||||
|
||||
class BuybackItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
BuybackItem(WorldPacket&& packet) : ClientPacket(CMSG_BUYBACK_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid VendorGuid;
|
||||
uint32 Slot = 0;
|
||||
};
|
||||
|
||||
class BuyItemInSlot final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
BuyItemInSlot(WorldPacket&& packet) : ClientPacket(CMSG_BUY_ITEM_IN_SLOT, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid VendorGuid;
|
||||
uint32 Item = 0;
|
||||
uint32 Slot = 0;
|
||||
ObjectGuid BagGuid;
|
||||
uint8 BagSlot = 0;
|
||||
uint32 Count = 0;
|
||||
};
|
||||
|
||||
class BuyItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
BuyItem(WorldPacket&& packet) : ClientPacket(CMSG_BUY_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid VendorGuid;
|
||||
uint32 Item = 0;
|
||||
uint32 Slot = 0;
|
||||
uint32 Count = 0;
|
||||
uint8 Unk = 0;
|
||||
};
|
||||
|
||||
class ListInventory final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
ListInventory(WorldPacket&& packet) : ClientPacket(CMSG_LIST_INVENTORY, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid VendorGuid;
|
||||
};
|
||||
|
||||
class AutoStoreBagItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
AutoStoreBagItem(WorldPacket&& packet) : ClientPacket(CMSG_AUTOSTORE_BAG_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 SourceBag = 0;
|
||||
uint8 SourceSlot = 0;
|
||||
uint8 DestinationBag = 0;
|
||||
};
|
||||
|
||||
class EnchantmentLog final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
EnchantmentLog() : ServerPacket(SMSG_ENCHANTMENTLOG, 8 + 8 + 4 + 4) {}
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
PackedGuid Target;
|
||||
PackedGuid Caster;
|
||||
uint32 ItemId = 0;
|
||||
uint32 EnchantId = 0;
|
||||
};
|
||||
|
||||
class ItemEnchantTimeUpdate final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
ItemEnchantTimeUpdate() : ServerPacket(SMSG_ITEM_ENCHANT_TIME_UPDATE, 8 + 4 + 4 + 8) {}
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
// last check 2.0.10
|
||||
ObjectGuid ItemGuid;
|
||||
uint32 Slot = 0;
|
||||
uint32 Duration = 0;
|
||||
ObjectGuid PlayerGuid;
|
||||
};
|
||||
|
||||
class WrapItem final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
WrapItem(WorldPacket&& packet) : ClientPacket(CMSG_WRAP_ITEM, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint8 GiftBag = 0;
|
||||
uint8 GiftSlot = 0;
|
||||
uint8 ItemBag = 0;
|
||||
uint8 ItemSlot = 0;
|
||||
};
|
||||
|
||||
class SocketGems final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
SocketGems(WorldPacket&& packet) : ClientPacket(CMSG_SOCKET_GEMS, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid ItemGuid;
|
||||
ObjectGuid GemGuids[MAX_GEM_SOCKETS];
|
||||
};
|
||||
|
||||
class CancelTempEnchantment final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
CancelTempEnchantment(WorldPacket&& packet) : ClientPacket(CMSG_CANCEL_TEMP_ENCHANTMENT, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint32 EquipmentSlot = 0;
|
||||
};
|
||||
|
||||
class ItemRefundInfo final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
ItemRefundInfo(WorldPacket&& packet) : ClientPacket(CMSG_ITEM_REFUND_INFO, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid ItemGuid;
|
||||
};
|
||||
|
||||
class ItemRefund final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
ItemRefund(WorldPacket&& packet) : ClientPacket(CMSG_ITEM_REFUND, std::move(packet)) {}
|
||||
|
||||
void Read() override;
|
||||
|
||||
ObjectGuid ItemGuid;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ItemPackets_h__
|
||||
@@ -167,6 +167,28 @@ namespace WorldPackets
|
||||
class TimeQuery;
|
||||
class CorpseMapPositionQuery;
|
||||
}
|
||||
|
||||
namespace Item
|
||||
{
|
||||
class SplitItem;
|
||||
class SwapInventoryItem;
|
||||
class AutoEquipItemSlot;
|
||||
class SwapItem;
|
||||
class AutoEquipItem;
|
||||
class DestroyItem;
|
||||
class ReadItem;
|
||||
class SellItem;
|
||||
class BuybackItem;
|
||||
class BuyItemInSlot;
|
||||
class BuyItem;
|
||||
class ListInventory;
|
||||
class AutoStoreBagItem;
|
||||
class WrapItem;
|
||||
class SocketGems;
|
||||
class CancelTempEnchantment;
|
||||
class ItemRefundInfo;
|
||||
class ItemRefund;
|
||||
}
|
||||
}
|
||||
|
||||
enum AccountDataType
|
||||
@@ -830,21 +852,21 @@ public: // opcodes handlers
|
||||
void HandleQueryNextMailTime(WorldPacket& recvData);
|
||||
void HandleCancelChanneling(WorldPacket& recvData);
|
||||
|
||||
void HandleSplitItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleSwapInvItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleDestroyItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleAutoEquipItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleSplitItemOpcode(WorldPackets::Item::SplitItem& packet);
|
||||
void HandleSwapInvItemOpcode(WorldPackets::Item::SwapInventoryItem& packet);
|
||||
void HandleDestroyItemOpcode(WorldPackets::Item::DestroyItem& packet);
|
||||
void HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& packet);
|
||||
void HandleItemQuerySingleOpcode(WorldPacket& recvPacket);
|
||||
void HandleSellItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket);
|
||||
void HandleBuyItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleListInventoryOpcode(WorldPacket& recvPacket);
|
||||
void HandleAutoStoreBagItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleReadItem(WorldPacket& recvPacket);
|
||||
void HandleAutoEquipItemSlotOpcode(WorldPacket& recvPacket);
|
||||
void HandleSwapItem(WorldPacket& recvPacket);
|
||||
void HandleBuybackItem(WorldPacket& recvPacket);
|
||||
void HandleWrapItemOpcode(WorldPacket& recvPacket);
|
||||
void HandleSellItemOpcode(WorldPackets::Item::SellItem& packet);
|
||||
void HandleBuyItemInSlotOpcode(WorldPackets::Item::BuyItemInSlot& packet);
|
||||
void HandleBuyItemOpcode(WorldPackets::Item::BuyItem& packet);
|
||||
void HandleListInventoryOpcode(WorldPackets::Item::ListInventory& packet);
|
||||
void HandleAutoStoreBagItemOpcode(WorldPackets::Item::AutoStoreBagItem& packet);
|
||||
void HandleReadItem(WorldPackets::Item::ReadItem& packet);
|
||||
void HandleAutoEquipItemSlotOpcode(WorldPackets::Item::AutoEquipItemSlot& packet);
|
||||
void HandleSwapItem(WorldPackets::Item::SwapItem& packet);
|
||||
void HandleBuybackItem(WorldPackets::Item::BuybackItem& packet);
|
||||
void HandleWrapItemOpcode(WorldPackets::Item::WrapItem& packet);
|
||||
|
||||
void HandleAttackSwingOpcode(WorldPacket& recvPacket);
|
||||
void HandleAttackStopOpcode(WorldPacket& recvPacket);
|
||||
@@ -1034,12 +1056,12 @@ public: // opcodes handlers
|
||||
void HandleRequestPetInfo(WorldPackets::Pet::RequestPetInfo& packet);
|
||||
|
||||
// Socket gem
|
||||
void HandleSocketOpcode(WorldPacket& recvData);
|
||||
void HandleSocketOpcode(WorldPackets::Item::SocketGems& packet);
|
||||
|
||||
void HandleCancelTempEnchantmentOpcode(WorldPacket& recvData);
|
||||
void HandleCancelTempEnchantmentOpcode(WorldPackets::Item::CancelTempEnchantment& packet);
|
||||
|
||||
void HandleItemRefundInfoRequest(WorldPacket& recvData);
|
||||
void HandleItemRefund(WorldPacket& recvData);
|
||||
void HandleItemRefundInfoRequest(WorldPackets::Item::ItemRefundInfo& packet);
|
||||
void HandleItemRefund(WorldPackets::Item::ItemRefund& packet);
|
||||
|
||||
void HandleChannelVoiceOnOpcode(WorldPacket& recvData);
|
||||
void HandleVoiceSessionEnableOpcode(WorldPacket& recvData);
|
||||
|
||||
@@ -5143,6 +5143,14 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21); // -1
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
28032, // Zap Crystal
|
||||
28056, // Zap Crystal Corpse
|
||||
}, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_ALWAYS_HIT;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -114,7 +114,6 @@ public:
|
||||
virtual void ResetEventSeasonalQuests(uint16 event_id) = 0;
|
||||
[[nodiscard]] virtual std::string const& GetRealmName() const = 0;
|
||||
virtual void SetRealmName(std::string name) = 0;
|
||||
virtual void RemoveOldCorpses() = 0;
|
||||
virtual SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -889,8 +889,6 @@ void World::SetInitialWorldSettings()
|
||||
_timers[WUPDATE_UPTIME].SetInterval(getIntConfig(CONFIG_UPTIME_UPDATE)*MINUTE * IN_MILLISECONDS);
|
||||
//Update "uptime" table based on configuration entry in minutes.
|
||||
|
||||
_timers[WUPDATE_CORPSES].SetInterval(20 * MINUTE * IN_MILLISECONDS);
|
||||
//erase corpses every 20 minutes
|
||||
_timers[WUPDATE_CLEANDB].SetInterval(getIntConfig(CONFIG_LOGDB_CLEARINTERVAL)*MINUTE * IN_MILLISECONDS);
|
||||
// clean logs table every 14 days by default
|
||||
_timers[WUPDATE_AUTOBROADCAST].SetInterval(getIntConfig(CONFIG_AUTOBROADCAST_INTERVAL));
|
||||
@@ -1281,18 +1279,6 @@ void World::Update(uint32 diff)
|
||||
LoginDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
///- Erase corpses once every 20 minutes
|
||||
if (_timers[WUPDATE_CORPSES].Passed())
|
||||
{
|
||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Remove old corpses"));
|
||||
_timers[WUPDATE_CORPSES].Reset();
|
||||
|
||||
sMapMgr->DoForAllMaps([](Map* map)
|
||||
{
|
||||
map->RemoveOldCorpses();
|
||||
});
|
||||
}
|
||||
|
||||
///- Process Game events when necessary
|
||||
if (_timers[WUPDATE_EVENTS].Passed())
|
||||
{
|
||||
@@ -1835,11 +1821,6 @@ SQLQueryHolderCallback& World::AddQueryHolderCallback(SQLQueryHolderCallback&& c
|
||||
return _queryHolderProcessor.AddCallback(std::move(callback));
|
||||
}
|
||||
|
||||
void World::RemoveOldCorpses()
|
||||
{
|
||||
_timers[WUPDATE_CORPSES].SetCurrent(_timers[WUPDATE_CORPSES].GetInterval());
|
||||
}
|
||||
|
||||
bool World::IsPvPRealm() const
|
||||
{
|
||||
return getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP || getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_FFA_PVP;
|
||||
|
||||
@@ -60,7 +60,6 @@ enum WorldTimers
|
||||
{
|
||||
WUPDATE_WEATHERS,
|
||||
WUPDATE_UPTIME,
|
||||
WUPDATE_CORPSES,
|
||||
WUPDATE_EVENTS,
|
||||
WUPDATE_CLEANDB,
|
||||
WUPDATE_AUTOBROADCAST,
|
||||
@@ -244,8 +243,6 @@ public:
|
||||
[[nodiscard]] std::string const& GetRealmName() const override { return _realmName; } // pussywizard
|
||||
void SetRealmName(std::string name) override { _realmName = name; } // pussywizard
|
||||
|
||||
void RemoveOldCorpses() override;
|
||||
|
||||
protected:
|
||||
void _UpdateGameTime();
|
||||
// callback for UpdateRealmCharacters
|
||||
|
||||
@@ -1072,8 +1072,8 @@ std::string WorldState::GetScourgeInvasionPrintout()
|
||||
{
|
||||
TimePoint tp = m_siData.m_timers[timerId];
|
||||
std::string timerStr;
|
||||
if (tp.time_since_epoch().count() == 0)
|
||||
timerStr = "0 (not set)";
|
||||
if (tp == TimePoint())
|
||||
timerStr = "Not set";
|
||||
else if (tp <= now)
|
||||
timerStr = "Elapsed";
|
||||
else
|
||||
@@ -1420,10 +1420,15 @@ void ScourgeInvasionData::Reset()
|
||||
std::string ScourgeInvasionData::GetData()
|
||||
{
|
||||
std::string output = std::to_string(m_state) + " ";
|
||||
for (auto& timer : m_timers)
|
||||
output += std::to_string(timer.time_since_epoch().count()) + " ";
|
||||
for (TimePoint& timer : m_timers)
|
||||
{
|
||||
if (timer == TimePoint())
|
||||
output += "0 ";
|
||||
else
|
||||
output += std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(timer.time_since_epoch()).count()) + " ";
|
||||
}
|
||||
output += std::to_string(m_battlesWon) + " " + std::to_string(m_lastAttackZone) + " ";
|
||||
for (auto& remaining : m_remaining)
|
||||
for (uint32& remaining : m_remaining)
|
||||
output += std::to_string(remaining) + " ";
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ public:
|
||||
{ "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "boundary", HandleDebugBoundaryCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
{ "boundary", HandleDebugBoundaryCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "visibilitydata", HandleDebugVisibilityDataCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
@@ -1403,6 +1404,36 @@ public:
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebugVisibilityDataCommand(ChatHandler* handler)
|
||||
{
|
||||
Player* player = handler->GetPlayer();
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
std::array<uint32, NUM_CLIENT_OBJECT_TYPES> objectByTypeCount = {};
|
||||
|
||||
ObjectVisibilityContainer const& objectVisibilityContainer = player->GetObjectVisibilityContainer();
|
||||
for (auto const& kvPair : *objectVisibilityContainer.GetVisibleWorldObjectsMap())
|
||||
{
|
||||
WorldObject const* obj = kvPair.second;
|
||||
++objectByTypeCount[obj->GetTypeId()];
|
||||
}
|
||||
|
||||
uint32 zoneWideVisibleObjectsInZone = 0;
|
||||
if (ZoneWideVisibleWorldObjectsSet const* farVisibleSet = player->GetMap()->GetZoneWideVisibleWorldObjectsForZone(player->GetZoneId()))
|
||||
zoneWideVisibleObjectsInZone = farVisibleSet->size();
|
||||
|
||||
handler->PSendSysMessage("Visibility Range: {}", player->GetVisibilityRange());
|
||||
handler->PSendSysMessage("Visible Creatures: {}", objectByTypeCount[TYPEID_UNIT]);
|
||||
handler->PSendSysMessage("Visible Players: {}", objectByTypeCount[TYPEID_PLAYER]);
|
||||
handler->PSendSysMessage("Visible GameObjects: {}", objectByTypeCount[TYPEID_GAMEOBJECT]);
|
||||
handler->PSendSysMessage("Visible DynamicObjects: {}", objectByTypeCount[TYPEID_DYNAMICOBJECT]);
|
||||
handler->PSendSysMessage("Visible Corpses: {}", objectByTypeCount[TYPEID_CORPSE]);
|
||||
handler->PSendSysMessage("Players we are visible to: {}", objectVisibilityContainer.GetVisiblePlayersMap().size());
|
||||
handler->PSendSysMessage("Zone wide visible objects in zone: {}", zoneWideVisibleObjectsInZone);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_debug_commandscript()
|
||||
|
||||
@@ -71,8 +71,6 @@ public:
|
||||
if (counter == 0)
|
||||
handler->SendSysMessage(LANG_NOEVENTFOUND);
|
||||
|
||||
handler->SetSentErrorMessage(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "GameTime.h"
|
||||
#include "GitRevision.h"
|
||||
#include "Log.h"
|
||||
#include "MapMgr.h"
|
||||
#include "ModuleMgr.h"
|
||||
#include "MotdMgr.h"
|
||||
#include "MySQLThreading.h"
|
||||
@@ -101,7 +102,10 @@ public:
|
||||
// Triggering corpses expire check in world
|
||||
static bool HandleServerCorpsesCommand(ChatHandler* /*handler*/)
|
||||
{
|
||||
sWorld->RemoveOldCorpses();
|
||||
sMapMgr->DoForAllMaps([](Map* map)
|
||||
{
|
||||
map->RemoveOldCorpses();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1001,20 +1001,25 @@ class spell_chapter2_persuasive_strike : public SpellScript
|
||||
creature->AI()->Talk(SAY_PERSUADED3, 24s);
|
||||
creature->AI()->Talk(SAY_PERSUADED4, 32s);
|
||||
|
||||
creature->m_Events.AddEventAtOffset([creature, player]
|
||||
ObjectGuid playerGuid = player->GetGUID();
|
||||
|
||||
creature->m_Events.AddEventAtOffset([creature, playerGuid]
|
||||
{
|
||||
if (player)
|
||||
sCreatureTextMgr->SendChat(creature, SAY_PERSUADED5, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
|
||||
if (Player* caster = ObjectAccessor::GetPlayer(*creature, playerGuid))
|
||||
sCreatureTextMgr->SendChat(creature, SAY_PERSUADED5, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, caster);
|
||||
}, 40s);
|
||||
|
||||
creature->m_Events.AddEventAtOffset([creature, player]
|
||||
creature->m_Events.AddEventAtOffset([creature, playerGuid]
|
||||
{
|
||||
creature->AI()->Talk(SAY_PERSUADED6);
|
||||
if (player)
|
||||
|
||||
if (Player* caster = ObjectAccessor::GetPlayer(*creature, playerGuid))
|
||||
{
|
||||
Unit::Kill(player, creature);
|
||||
player->GroupEventHappens(QUEST_HOW_TO_WIN_FRIENDS, creature);
|
||||
Unit::Kill(caster, creature);
|
||||
caster->GroupEventHappens(QUEST_HOW_TO_WIN_FRIENDS, creature);
|
||||
}
|
||||
else
|
||||
creature->KillSelf();
|
||||
}, 48s);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -26,14 +26,17 @@
|
||||
|
||||
enum ANData
|
||||
{
|
||||
DATA_KRIKTHIR_THE_GATEWATCHER_EVENT = 0,
|
||||
DATA_HADRONOX_EVENT = 1,
|
||||
DATA_KRIKTHIR = 0,
|
||||
DATA_HADRONOX = 1,
|
||||
DATA_ANUBARAK_EVENT = 2,
|
||||
MAX_ENCOUNTERS = 3
|
||||
};
|
||||
|
||||
enum ANIds
|
||||
{
|
||||
NPC_WATCHER_NARJIL = 28729,
|
||||
NPC_WATCHER_GASHRA = 28730,
|
||||
NPC_WATCHER_SILTHIK = 28731,
|
||||
NPC_SKITTERING_SWARMER = 28735,
|
||||
NPC_SKITTERING_INFECTIOR = 28736,
|
||||
NPC_KRIKTHIR_THE_GATEWATCHER = 28684,
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
|
||||
struct boss_hadronoxAI : public BossAI
|
||||
{
|
||||
boss_hadronoxAI(Creature* creature) : BossAI(creature, DATA_HADRONOX_EVENT)
|
||||
boss_hadronoxAI(Creature* creature) : BossAI(creature, DATA_HADRONOX)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
{
|
||||
if (param == ACTION_START_EVENT)
|
||||
{
|
||||
instance->SetBossState(DATA_HADRONOX_EVENT, IN_PROGRESS);
|
||||
instance->SetBossState(DATA_HADRONOX, IN_PROGRESS);
|
||||
me->setActive(true);
|
||||
events.ScheduleEvent(EVENT_HADRONOX_MOVE1, 20s);
|
||||
events.ScheduleEvent(EVENT_HADRONOX_MOVE2, 40s);
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
PreventDefaultAction();
|
||||
Unit* owner = GetUnitOwner();
|
||||
if (InstanceScript* instance = owner->GetInstanceScript())
|
||||
if (instance->GetBossState(DATA_HADRONOX_EVENT) != DONE)
|
||||
if (!instance->IsBossDone(DATA_HADRONOX))
|
||||
{
|
||||
if (!owner->HasAura(SPELL_WEB_FRONT_DOORS))
|
||||
owner->CastSpell(owner, _spellEntry, true);
|
||||
|
||||
+79
-96
@@ -29,24 +29,8 @@ enum Spells
|
||||
SPELL_FRENZY = 28747
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_KRIK_START_WAVE = 1,
|
||||
EVENT_KRIK_SUMMON = 2,
|
||||
EVENT_KRIK_MIND_FLAY = 3,
|
||||
EVENT_KRIK_CURSE = 4,
|
||||
EVENT_KRIK_HEALTH_CHECK = 5,
|
||||
EVENT_KRIK_ENTER_COMBAT = 6,
|
||||
EVENT_KILL_TALK = 7,
|
||||
EVENT_CALL_ADDS = 8,
|
||||
EVENT_KRIK_CHECK_EVADE = 9
|
||||
};
|
||||
|
||||
enum Npcs
|
||||
{
|
||||
NPC_WATCHER_NARJIL = 28729,
|
||||
NPC_WATCHER_GASHRA = 28730,
|
||||
NPC_WATCHER_SILTHIK = 28731,
|
||||
NPC_WARRIOR = 28732,
|
||||
NPC_SKIRMISHER = 28734,
|
||||
NPC_SHADOWCASTER = 28733
|
||||
@@ -62,6 +46,12 @@ enum Yells
|
||||
SAY_SEND_GROUP = 5
|
||||
};
|
||||
|
||||
enum MiscActions
|
||||
{
|
||||
ACTION_MINION_ENGAGED = 1,
|
||||
GROUP_SWARM = 1
|
||||
};
|
||||
|
||||
class boss_krik_thir : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -69,18 +59,21 @@ public:
|
||||
|
||||
struct boss_krik_thirAI : public BossAI
|
||||
{
|
||||
boss_krik_thirAI(Creature* creature) : BossAI(creature, DATA_KRIKTHIR_THE_GATEWATCHER_EVENT)
|
||||
boss_krik_thirAI(Creature* creature) : BossAI(creature, DATA_KRIKTHIR)
|
||||
{
|
||||
_initTalk = false;
|
||||
}
|
||||
_canTalk = true;
|
||||
_minionInCombat = false;
|
||||
|
||||
EventMap events2;
|
||||
bool _initTalk;
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
events2.Reset();
|
||||
|
||||
me->SummonCreature(NPC_WATCHER_NARJIL, 511.8f, 666.493f, 776.278f, 0.977f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
|
||||
me->SummonCreature(NPC_SHADOWCASTER, 511.63f, 672.44f, 775.71f, 0.90f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
|
||||
@@ -91,6 +84,22 @@ public:
|
||||
me->SummonCreature(NPC_WATCHER_SILTHIK, 543.826f, 665.123f, 776.245f, 1.55f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
|
||||
me->SummonCreature(NPC_SKIRMISHER, 547.5f, 669.96f, 776.1f, 2.3f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
|
||||
me->SummonCreature(NPC_SHADOWCASTER, 548.64f, 664.27f, 776.74f, 1.77f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
|
||||
|
||||
ScheduleHealthCheckEvent(25, [&] {
|
||||
DoCastSelf(SPELL_FRENZY, true);
|
||||
|
||||
scheduler.CancelGroup(GROUP_SWARM);
|
||||
|
||||
scheduler.Schedule(7s, 17s, GROUP_SWARM, [&](TaskContext context)
|
||||
{
|
||||
Talk(SAY_SWARM);
|
||||
DoCastAOE(SPELL_SWARM);
|
||||
context.Repeat(20s);
|
||||
});
|
||||
});
|
||||
|
||||
_canTalk = true;
|
||||
_minionInCombat = false;
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
@@ -103,21 +112,25 @@ public:
|
||||
_initTalk = true;
|
||||
Talk(SAY_PREFIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
if (events.Empty() && who->GetPositionZ() < 785.0f)
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
if (actionId == ACTION_MINION_ENGAGED && !_minionInCombat)
|
||||
{
|
||||
events2.ScheduleEvent(EVENT_KRIK_START_WAVE, 10s);
|
||||
events2.ScheduleEvent(EVENT_KRIK_START_WAVE, 40s);
|
||||
events2.ScheduleEvent(EVENT_KRIK_START_WAVE, 70s);
|
||||
events2.ScheduleEvent(EVENT_KRIK_ENTER_COMBAT, 100s);
|
||||
events2.ScheduleEvent(EVENT_KRIK_CHECK_EVADE, 5s);
|
||||
_minionInCombat = true;
|
||||
|
||||
events.ScheduleEvent(EVENT_KRIK_HEALTH_CHECK, 1s);
|
||||
events.ScheduleEvent(EVENT_KRIK_MIND_FLAY, 13s);
|
||||
events.ScheduleEvent(EVENT_KRIK_SUMMON, 17s);
|
||||
events.ScheduleEvent(EVENT_KRIK_CURSE, 8s);
|
||||
events.ScheduleEvent(EVENT_CALL_ADDS, 1s);
|
||||
me->setActive(true);
|
||||
for (Seconds const& timer : { 10s, 40s, 70s })
|
||||
{
|
||||
me->m_Events.AddEventAtOffset([this] {
|
||||
me->CastCustomSpell(SPELL_SUBBOSS_AGGRO_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, me, true);
|
||||
Talk(SAY_SEND_GROUP);
|
||||
}, timer);
|
||||
}
|
||||
|
||||
me->m_Events.AddEventAtOffset([this] {
|
||||
me->SetInCombatWithZone();
|
||||
}, 100s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +145,28 @@ public:
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_AGGRO);
|
||||
events2.Reset();
|
||||
|
||||
me->m_Events.KillAllEvents(false);
|
||||
|
||||
scheduler.Schedule(8s, 14s, [&](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_MIND_FLAY);
|
||||
if (!IsInFrenzy())
|
||||
context.Repeat(8s, 14s);
|
||||
else
|
||||
context.Repeat(5s, 9s);
|
||||
}).Schedule(10s, 13s, GROUP_SWARM, [&](TaskContext context)
|
||||
{
|
||||
Talk(SAY_SWARM);
|
||||
DoCastAOE(SPELL_SWARM);
|
||||
context.Repeat(26s, 30s);
|
||||
});
|
||||
|
||||
ScheduleTimedEvent(27s, 35s, [&] {
|
||||
DoCastRandomTarget(SPELL_CURSE_OF_FATIGUE);
|
||||
}, 27s, 35s);
|
||||
|
||||
summons.DoZoneInCombat();
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
@@ -141,12 +175,15 @@ public:
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* ) override
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
if (_canTalk)
|
||||
{
|
||||
_canTalk = false;
|
||||
Talk(SAY_SLAY);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
|
||||
me->m_Events.AddEventAtOffset([&] {
|
||||
_canTalk = true;
|
||||
}, 6s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,66 +198,12 @@ public:
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_KRIK_START_WAVE:
|
||||
me->CastCustomSpell(SPELL_SUBBOSS_AGGRO_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, me, true);
|
||||
Talk(SAY_SEND_GROUP);
|
||||
break;
|
||||
case EVENT_KRIK_ENTER_COMBAT:
|
||||
me->SetInCombatWithZone();
|
||||
break;
|
||||
case EVENT_KRIK_CHECK_EVADE:
|
||||
if (!SelectTargetFromPlayerList(100.0f))
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
events2.ScheduleEvent(EVENT_KRIK_CHECK_EVADE, 5s);
|
||||
break;
|
||||
}
|
||||
private:
|
||||
bool _initTalk;
|
||||
bool _canTalk;
|
||||
bool _minionInCombat;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_KRIK_HEALTH_CHECK:
|
||||
if (HealthBelowPct(10))
|
||||
{
|
||||
me->CastSpell(me, SPELL_FRENZY, true);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_KRIK_HEALTH_CHECK, 1s);
|
||||
break;
|
||||
case EVENT_KRIK_SUMMON:
|
||||
Talk(SAY_SWARM);
|
||||
me->CastSpell(me, SPELL_SWARM, false);
|
||||
events.ScheduleEvent(EVENT_KRIK_SUMMON, 20s);
|
||||
break;
|
||||
case EVENT_KRIK_MIND_FLAY:
|
||||
me->CastSpell(me->GetVictim(), SPELL_MIND_FLAY, false);
|
||||
events.ScheduleEvent(EVENT_KRIK_MIND_FLAY, 15s);
|
||||
break;
|
||||
case EVENT_KRIK_CURSE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
|
||||
me->CastSpell(target, SPELL_CURSE_OF_FATIGUE, true);
|
||||
events.ScheduleEvent(EVENT_KRIK_CURSE, 10s);
|
||||
break;
|
||||
case EVENT_CALL_ADDS:
|
||||
summons.DoZoneInCombat();
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
[[nodiscard]] bool IsInFrenzy() const { return me->HasAura(SPELL_FRENZY); }
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_KRIKTHIR_DOORS, DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, DOOR_TYPE_PASSAGE },
|
||||
{ GO_KRIKTHIR_DOORS, DATA_KRIKTHIR, DOOR_TYPE_PASSAGE },
|
||||
{ GO_ANUBARAK_DOORS1, DATA_ANUBARAK_EVENT, DOOR_TYPE_ROOM },
|
||||
{ GO_ANUBARAK_DOORS2, DATA_ANUBARAK_EVENT, DOOR_TYPE_ROOM },
|
||||
{ GO_ANUBARAK_DOORS3, DATA_ANUBARAK_EVENT, DOOR_TYPE_ROOM },
|
||||
@@ -34,15 +34,25 @@ DoorData const doorData[] =
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_KRIKTHIR_THE_GATEWATCHER, DATA_KRIKTHIR_THE_GATEWATCHER_EVENT },
|
||||
{ NPC_HADRONOX, DATA_HADRONOX_EVENT },
|
||||
{ 0, 0 }
|
||||
{ NPC_KRIKTHIR_THE_GATEWATCHER, DATA_KRIKTHIR },
|
||||
{ NPC_HADRONOX, DATA_HADRONOX },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
ObjectData const summonData[] =
|
||||
{
|
||||
{ NPC_SKITTERING_SWARMER, DATA_KRIKTHIR },
|
||||
{ NPC_SKITTERING_INFECTIOR, DATA_KRIKTHIR },
|
||||
{ NPC_ANUB_AR_CHAMPION, DATA_HADRONOX },
|
||||
{ NPC_ANUB_AR_NECROMANCER, DATA_HADRONOX },
|
||||
{ NPC_ANUB_AR_CRYPTFIEND, DATA_HADRONOX },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, new RectangleBoundary(400.0f, 580.0f, 623.5f, 810.0f) },
|
||||
{ DATA_HADRONOX_EVENT, new ZRangeBoundary(666.0f, 776.0f) },
|
||||
{ DATA_KRIKTHIR, new RectangleBoundary(400.0f, 580.0f, 623.5f, 810.0f) },
|
||||
{ DATA_HADRONOX, new ZRangeBoundary(666.0f, 776.0f) },
|
||||
{ DATA_ANUBARAK_EVENT, new CircleBoundary(Position(550.6178f, 253.5917f), 26.0f) }
|
||||
};
|
||||
|
||||
@@ -60,52 +70,14 @@ public:
|
||||
LoadBossBoundaries(boundaries);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
LoadSummonData(summonData);
|
||||
};
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
void OnCreatureEvade(Creature* creature) override
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_SKITTERING_SWARMER:
|
||||
case NPC_SKITTERING_INFECTIOR:
|
||||
if (Creature* krikthir = GetCreature((DATA_KRIKTHIR_THE_GATEWATCHER_EVENT)))
|
||||
krikthir->AI()->JustSummoned(creature);
|
||||
break;
|
||||
case NPC_ANUB_AR_CHAMPION:
|
||||
case NPC_ANUB_AR_NECROMANCER:
|
||||
case NPC_ANUB_AR_CRYPTFIEND:
|
||||
if (Creature* hadronox = GetCreature(DATA_HADRONOX_EVENT))
|
||||
hadronox->AI()->JustSummoned(creature);
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_KRIKTHIR_DOORS:
|
||||
case GO_ANUBARAK_DOORS1:
|
||||
case GO_ANUBARAK_DOORS2:
|
||||
case GO_ANUBARAK_DOORS3:
|
||||
AddDoor(go);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectRemove(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_KRIKTHIR_DOORS:
|
||||
case GO_ANUBARAK_DOORS1:
|
||||
case GO_ANUBARAK_DOORS2:
|
||||
case GO_ANUBARAK_DOORS3:
|
||||
RemoveDoor(go);
|
||||
break;
|
||||
}
|
||||
if (creature->EntryEquals(NPC_WATCHER_NARJIL, NPC_WATCHER_GASHRA, NPC_WATCHER_SILTHIK))
|
||||
if (Creature* krikthir = GetCreature(DATA_KRIKTHIR))
|
||||
krikthir->AI()->EnterEvadeMode();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -75,8 +75,6 @@ enum DrakeGiverTexts
|
||||
class npc_oculus_drakegiver : public CreatureScript
|
||||
{
|
||||
public:
|
||||
std::unordered_map<ObjectGuid, bool>openedMenu;
|
||||
|
||||
npc_oculus_drakegiver() : CreatureScript("npc_oculus_drakegiver") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -193,20 +191,8 @@ public:
|
||||
SendGossipMenuFor(player, GOSSIP_TEXTID_VERDISA1, creature->GetGUID());
|
||||
break;
|
||||
case NPC_BELGARISTRASZ:
|
||||
if (HAS_ESSENCE(player))
|
||||
{
|
||||
openedMenu[player->GetGUID()] = true;
|
||||
}
|
||||
|
||||
if (!openedMenu[player->GetGUID()])
|
||||
{
|
||||
AddGossipItemFor(player, 9708, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
SendGossipMenuFor(player, GOSSIP_TEXTID_DRAKES, creature->GetGUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
OnGossipSelect(player, creature, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
}
|
||||
AddGossipItemFor(player, 9708, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
SendGossipMenuFor(player, GOSSIP_TEXTID_DRAKES, creature->GetGUID());
|
||||
break;
|
||||
case NPC_ETERNOS:
|
||||
AddGossipItemFor(player, 9574, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
@@ -277,7 +263,6 @@ public:
|
||||
switch (uiAction)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF:
|
||||
openedMenu[player->GetGUID()] = true;
|
||||
if (player->HasItemCount(ITEM_AMBER_ESSENCE))
|
||||
{
|
||||
AddGossipItemFor(player, 9575, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
|
||||
@@ -2124,6 +2124,25 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 45612 - Necropolis Beam
|
||||
class spell_necropolis_beam: public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_necropolis_beam);
|
||||
|
||||
void SetDest(SpellDestination& dest)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
float floorZ = caster->GetMapHeight(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ());
|
||||
if (floorZ > INVALID_HEIGHT)
|
||||
dest._position.m_positionZ = floorZ;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_necropolis_beam::SetDest, EFFECT_0, TARGET_DEST_CASTER);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_borean_tundra()
|
||||
{
|
||||
RegisterSpellScript(spell_q11919_q11940_drake_hunt_aura);
|
||||
@@ -2148,4 +2167,5 @@ void AddSC_borean_tundra()
|
||||
RegisterSpellScript(spell_q11719_bloodspore_ruination_45997);
|
||||
new npc_bloodmage_laurith();
|
||||
RegisterCreatureAI(npc_jenny);
|
||||
RegisterSpellScript(spell_necropolis_beam);
|
||||
}
|
||||
|
||||
@@ -2240,6 +2240,27 @@ class spell_dragonblight_corrosive_spit : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 48297 - Hand Over Reins
|
||||
enum HandOverReins
|
||||
{
|
||||
SPELL_ONSLAUGHT_RIDING_CROP = 48290
|
||||
};
|
||||
|
||||
class spell_handover_reins : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_handover_reins);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->RemoveAura(SPELL_ONSLAUGHT_RIDING_CROP);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_handover_reins::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_dragonblight()
|
||||
{
|
||||
new npc_conversing_with_the_depths_trigger();
|
||||
@@ -2267,4 +2288,5 @@ void AddSC_dragonblight()
|
||||
RegisterSpellScript(spell_q12096_q12092_bark);
|
||||
new npc_torturer_lecraft();
|
||||
RegisterSpellScript(spell_dragonblight_corrosive_spit);
|
||||
RegisterSpellScript(spell_handover_reins);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
class npc_attracted_reef_bull : public CreatureScript
|
||||
{
|
||||
@@ -393,6 +394,36 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum HawkHunting
|
||||
{
|
||||
SPELL_HAWK_HUNTING_ITEM = 44408
|
||||
};
|
||||
|
||||
// 44407 - Spell hawk Hunting
|
||||
class spell_hawk_hunting : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hawk_hunting);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_HAWK_HUNTING_ITEM });
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (!GetCaster())
|
||||
return;
|
||||
|
||||
GetCaster()->CastSpell(GetCaster(), SPELL_HAWK_HUNTING_ITEM, true);
|
||||
GetHitUnit()->ToCreature()->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_hawk_hunting::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_howling_fjord()
|
||||
{
|
||||
new npc_attracted_reef_bull();
|
||||
@@ -400,4 +431,5 @@ void AddSC_howling_fjord()
|
||||
new npc_apothecary_hanes();
|
||||
new npc_plaguehound_tracker();
|
||||
new npc_razael_and_lyana();
|
||||
RegisterSpellScript(spell_hawk_hunting);
|
||||
}
|
||||
|
||||
@@ -1167,6 +1167,31 @@ public:
|
||||
return new npc_vehicle_d16_propelled_deliveryAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
enum StormcrestEagle
|
||||
{
|
||||
NPC_STORMCREST_EAGLE = 29854
|
||||
};
|
||||
|
||||
// 56393 - Feed Stormcrest Eagle
|
||||
class spell_feed_stormcrest_eagle : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_feed_stormcrest_eagle);
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (GetCaster()->FindNearestCreature(NPC_STORMCREST_EAGLE, 15.0f, true))
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_feed_stormcrest_eagle::CheckCast);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_storm_peaks()
|
||||
{
|
||||
new npc_frosthound();
|
||||
@@ -1183,4 +1208,5 @@ void AddSC_storm_peaks()
|
||||
RegisterSpellScript(spell_close_rift_aura);
|
||||
new npc_vehicle_d16_propelled_delivery();
|
||||
RegisterSpellScript(spell_q12823_remove_collapsing_cave_aura);
|
||||
RegisterSpellScript(spell_feed_stormcrest_eagle);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user