diff --git a/.dockerignore b/.dockerignore index e0f14b384..6945dbad0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,15 +6,6 @@ /env/dist/* !/env/dist/.gitkeep /env/user/* -/env/docker/* -!/env/docker/bin/.gitkeep -!/env/docker/data/.gitkeep -!/env/docker/etc/ -/env/docker/etc/* -!/env/docker/etc/authserver.conf.dockerdist -!/env/docker/etc/worldserver.conf.dockerdist -!/env/docker/etc/dbimport.conf.dockerdist -!/env/docker/logs/.gitkeep /.env* .idea !.gitkeep diff --git a/.github/README.md b/.github/README.md index f19331912..948a86f9a 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,166 +1,76 @@ # ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore [![CodeFactor](https://www.codefactor.io/repository/github/azerothcore/azerothcore-wotlk/badge)](https://www.codefactor.io/repository/github/azerothcore/azerothcore-wotlk) -[![core-build](https://github.com/azerothcore/azerothcore-wotlk/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/azerothcore-wotlk/actions?query=workflow%3Acore-build+branch%3Amaster+event%3Apush) +[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=40032087)](https://www.bountysource.com/teams/azerothcore/bounties "Put money on issues or get paid for fixing them") +[![StackOverflow](http://img.shields.io/badge/stackoverflow-azerothcore-blue.svg?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/azerothcore?sort=newest "Ask / browse questions here") +[![Discord](https://img.shields.io/discord/217589275766685707?logo=discord&logoColor=white)](https://discord.gg/gkt4y2x "Our community hub on Discord") + +## Build Status + +[![core](https://github.com/azerothcore/azerothcore-wotlk/actions/workflows/core_matrix_build.yml/badge.svg?branch=master&event=push)](https://github.com/azerothcore/azerothcore-wotlk/actions/workflows/core_matrix_build.yml) [![core-modules-build](https://github.com/azerothcore/azerothcore-wotlk/workflows/core-modules-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/azerothcore-wotlk/actions?query=workflow%3Acore-modules-build+branch%3Amaster+event%3Apush) [![windows-build](https://github.com/azerothcore/azerothcore-wotlk/workflows/windows-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/azerothcore-wotlk/actions?query=workflow%3Awindows-build+branch%3Amaster+event%3Apush) [![macos-build](https://github.com/azerothcore/azerothcore-wotlk/workflows/macos-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/azerothcore-wotlk/actions?query=workflow%3Amacos-build+branch%3Amaster+event%3Apush) [![docker-build](https://github.com/azerothcore/azerothcore-wotlk/workflows/docker-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/azerothcore-wotlk/actions?query=workflow%3Adocker-build+branch%3Amaster+event%3Apush) -[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=40032087)](https://www.bountysource.com/teams/azerothcore/bounties "Put money on issues or get paid for fixing them") -[![StackOverflow](http://img.shields.io/badge/stackoverflow-azerothcore-blue.svg)](https://stackoverflow.com/questions/tagged/azerothcore?sort=newest "Ask / browse questions here") -[![Discord](https://img.shields.io/discord/217589275766685707.svg)](https://discord.gg/gkt4y2x "Our community hub on Discord") - ## Introduction -AzerothCore (AC) is an open-source game-server application for World of Warcraft, currently supporting the 3.3.5a game version. - -It is written in C++ and is based on MaNGOS, TrinityCore and SunwellCore. - - -## Why AzerothCore? - -1. Stability -1. The authenticity of the content -1. [Modularity](https://en.wikipedia.org/wiki/Modular_programming) -1. A lot of modules to choose from -1. Better configuration files system -1. Compatibility with other emulators -1. Friendly and helpful community - -### Stability - -As players and administrators ourselves, we take great care into the stability of our core. Other projects focus on the development side of things and tend to forget that users want stability above everything else. - -Hence why nobody is allowed to push commits directly to the core. All changes are reviewed and tested before they get to the `master` branch which means we need as many testers as possible to avoid stalling issues. - -### Authenticity - -Fixing and implementing missing blizzlike content is one of our priorities, and we can boast to offer the most content-complete open-source emulator. - - - -### Modules - -Modules are essential to AzerothCore's success. Modules allow users to plug them in and out easily, and do not require to modify the core files. It also means users can keep pulling the git changes from the main repository and only develop their modules. - -We have a lot of modules already made, some of them are very important and will ease your work: - -* [Transmogrification](https://github.com/azerothcore/mod-transmog) -* [Eluna (lua engine) support](https://github.com/azerothcore/mod-eluna/ "Creator of Eluna is part of our core team") -* Full list available in the AzerothCore catalogue (link at the end) - -### Configuration files - -Our configuration file system allows the user to use a tiny configuration file for better readability and maintenance. - -### Compatibility with other emulators - -Not very far from its ancestor TrinityCore, most scripts can be adapted quite easily. For MaNGOS compatibility, it might require more knowledge but it shares a common base. +AzerothCore is an open-source game server application and framework designed for hosting massively multiplayer online role-playing games (MMORPGs). It is based on the popular MMORPG World of Warcraft (WoW) and seeks to recreate the gameplay experience of the original game from patch 3.3.5a. +The original code is based on MaNGOS, TrinityCore, and SunwellCore and has since then had extensive development to improve stability, in-game mechanics, and modularity to the game. AC has also grown into a community-driven project with a significant number of contributors and developers. It is written in C++ and provides a solid foundation for creating private servers that mimic the mechanics and behavior of the official WoW servers. ## Philosophy -Our main goal is to create a playable game server, offering a fully working game experience. +Our main goal is to create a playable game server, offering a fully working in-game experience. Here are the main points we focus on: * Stability -* Ease of use / Practicability -* Playability (in-game content) + * We make sure all changes pass the CIs before being merged into the master branch. + +* Blizzlike content + * We strive to make all in-game content to be blizzlike. Therefore we have a high standard for fixes being made. + * Customization -* Community-driven software (check our discord) + * It is easy to customize your experience using [modules](#modules). -We also welcome new users (even non-English speaking users!) and help them learn/improve their skills (C++, SQL, Git, software collaboration, tutoring/wiki, etc...). +* Community driven + * AzerothCore has an active community of developers, contributors, and users who collaborate, share knowledge, and provide support through forums, Discord channels, and other communication platforms. -Unlike other projects which focus more on the developer's side of things, we want users to be able to run their server with as few troubles as possible. All of our contributors run their private servers (local or public). +### Modules -That's why AzerothCore is easier to use, to maintain, to understand, to develop on, and to customize to suit your needs, than other emulators. - -In short, we focus on the **user experience (UX)**, whether it be the **player's experience**, the **developer's experience**, or the **administrator's experience**. - - -## How to Thank us - -Being an open-source project, we rely on volunteers to pursue development. Here are ways to help us if you use AzerothCore: - -### Github Star - -Click on the "star this repository" button to help us gain more visibility on Github! - -### By contributing - -Check the **CONTRIBUTING** section below. - -### Financially :moneybag: - -You can support the AzerothCore by [donating](https://www.paypal.com/donate/?hosted_button_id=L69ANPSR8BJDU). -The money will be used to pay freelance developers for more open-source fixes. - -### Advertising - -By talking about us on different platforms or to people who would like to get involved. - - -## Contributing - -AzerothCore is a learning project, and there are lots of different ways to contribute to the project: - -* By [testing our fixes](http://www.azerothcore.org/wiki/How-to-test-a-PR) (we can teach you how to correctly use Git to help us but that will also help you out tremendously) -* By developing directly to the core or the modules -* By reporting bugs within the project -* By [creating new modules](http://www.azerothcore.org/wiki/Create-a-Module) -* By improving our wiki -* By providing direct support to our community (on Discord, StackOverflow or specialized forums) -* By making extra content (video tutorial for example) -* By putting bounties on issues - - -If you want to contribute to the project, you will find a lot of resources that will guide you in our wiki. - -Feel free to join us on [our Discord chat server](https://discord.gg/gkt4y2x) where we teach a lot of new people how to get started and who are now important contributors! - - - +AzerothCore is designed to be highly modular, allowing developers to extend and customize the game to suit their preferences or create unique gameplay experiences. This flexibility enables the addition of custom features, content, and modifications. +We have a lot of modules already made by the community, many of which can be found in the [Module Catalogue](https://www.azerothcore.org/catalogue.html#/). ## Installation -Installation instructions are available [here](http://www.azerothcore.org/wiki/Installation). +Detailed installation instructions are available [here](http://www.azerothcore.org/wiki/installation). -We also have an auto-installation bash script [here](/apps/installer/main.sh) (*Warning: try it/analyze it before running it*). +## Contributing -Dockerization of AzerothCore is fully supported, and we have various community-made tutorials (eg: AWS / Digital Ocean installation). +AzerothCore can also serve as a learning resource for aspiring developers who want to understand how WoW servers work, how MMORPGs are structured, how game server emulators are created, or to improve their C++ and SQL knowledge. +If you want to contribute to the project, you will find a lot of resources that will guide you in our [wiki](https://www.azerothcore.org/wiki/contribute). -## Support +We also recommend you read our [Contributor Covenant Code of Conduct](https://github.com/azerothcore/azerothcore-wotlk/blob/master/.github/CODE_OF_CONDUCT.md). -Our self-made wiki probably has a lot of answers for you. - -For help requests, it is recommended to ask your question on [StackOverflow](https://stackoverflow.com/questions/tagged/azerothcore) and link it in [our chat](https://discordapp.com/channels/217589275766685707/284406375495368704). +Feel free to join our [Discord server](https://discord.gg/gkt4y2x). +Click on the "⭐ Star" button to help us gain more visibility on Github! ## Authors & Contributors -This project exists thanks to: - -- **The [AzerothCore developers and contributors](https://github.com/AzerothCore/azerothcore-wotlk/graphs/contributors)** -- The [SunwellCore developers xinef and pussywizard](http://www.azerothcore.org/pages/sunwell.pl/) -- All the [TrinityCore developers and contributors](https://github.com/TrinityCore/TrinityCore/blob/3.3.5/AUTHORS) -- All the [MaNGOS, ScriptDev2 and UDB developers and contributors](https://github.com/cmangos/mangos-wotlk/blob/master/AUTHORS.md) - +This project exists thanks to the [authors](https://github.com/azerothcore/azerothcore-wotlk/blob/master/AUTHORS). ## Important Links -- [Doxygen Documentation](https://www.azerothcore.org/pages/doxygen/index.html) - -- [Code of Conduct](https://github.com/azerothcore/azerothcore-wotlk/blob/master/.github/CODE_OF_CONDUCT.md) +- [Doxygen documentation](https://www.azerothcore.org/pages/doxygen/index.html) - [Website](http://www.azerothcore.org/) - [AzerothCore catalogue](http://www.azerothcore.org/catalogue.html "Modules, tools, and other stuff for AzerothCore") (modules, tools, etc...) -- [Module template / Module skeleton](https://github.com/azerothcore/skeleton-module/) -- [Our community hub (Discord)](https://discord.gg/gkt4y2x) +- [Our Discord server](https://discord.gg/gkt4y2x) - [Our wiki](http://www.azerothcore.org/wiki "Easy to use and developed by AzerothCore founder") -- [Our Forum](https://github.com/azerothcore/azerothcore-wotlk/discussions/) +- [Our forum](https://github.com/azerothcore/azerothcore-wotlk/discussions/) - [Our Facebook page](https://www.facebook.com/AzerothCore/) - [Our LinkedIn page](https://www.linkedin.com/company/azerothcore/) @@ -169,10 +79,10 @@ This project exists thanks to: - The new AzerothCore source components are released under the [GNU AGPL v3](https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3) - The old sources based on MaNGOS/TrinityCore are released under the [GNU GPL v2](https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-GPL2) +It's important to note that AzerothCore is not an official Blizzard Entertainment product, and it is not affiliated with or endorsed by World of Warcraft or Blizzard Entertainment. AzerothCore does not in any case sponsor nor support illegal public servers. If you use this project to run an illegal public server and not for testing and learning it is your own personal choice. ## Special thanks [JetBrains](https://www.jetbrains.com/?from=AzerothCore) is providing free [open-source licenses](https://www.jetbrains.com/community/opensource/) to the AzerothCore developers. [![JetBrains](https://user-images.githubusercontent.com/75517/51205146-7f225c80-1905-11e9-82e0-835627be170d.png)](https://www.jetbrains.com/?from=AzerothCore) - diff --git a/.gitignore b/.gitignore index 8feb99e8d..a6673353c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,13 +17,6 @@ /env/dist/* !/env/dist/.gitkeep /env/user/* -/env/docker/* -!/env/docker/bin/.gitkeep -!/env/docker/data/.gitkeep -!/env/docker/etc/ -/env/docker/etc/* -!/env/docker/etc/*.conf.dockerdist -!/env/docker/logs/.gitkeep /.env* /apps/joiner /deps/deno diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index fe59e61e0..000000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "deps/git-subrepo"] - path = deps/git-subrepo - url = https://github.com/ingydotnet/git-subrepo.git -[submodule "modules/mod-playerbots"] - path = modules/mod-playerbots - url = https://github.com/liyunfan1223/mod-playerbots.git diff --git a/apps/ci/ci-error-check.sh b/apps/ci/ci-error-check.sh index d446e904b..1862fa712 100755 --- a/apps/ci/ci-error-check.sh +++ b/apps/ci/ci-error-check.sh @@ -1,17 +1,18 @@ #!/usr/bin/env bash -DB_ERRORS_FILE="./env/dist/bin/DBErrors.log"; +ERRORS_FILE="./env/dist/bin/Errors.log"; -if [[ ! -f ${DB_ERRORS_FILE} ]]; then - echo "File ${DB_ERRORS_FILE} not found!"; - exit 1 -fi +echo "Checking Startup Errors" +echo -if [[ -s ${DB_ERRORS_FILE} ]]; then - printf "The DBErrors.log file contains startup errors:\n\n"; - cat ${DB_ERRORS_FILE}; +if [[ -s ${ERRORS_FILE} ]]; then + printf "The Errors.log file contains startup errors:\n\n"; + cat ${ERRORS_FILE}; printf "\nPlease solve the startup errors listed above!\n"; exit 1; else - echo "No startup errors found in DBErrors.log, good job!"; + echo "> No startup errors found in Errors.log"; fi + +echo +echo "Done" diff --git a/apps/compiler/includes/functions.sh b/apps/compiler/includes/functions.sh index 5b26e065a..7435e655e 100644 --- a/apps/compiler/includes/functions.sh +++ b/apps/compiler/includes/functions.sh @@ -143,32 +143,6 @@ function comp_compile() { find "$AC_BINPATH_FULL" -mindepth 1 -maxdepth 1 -type f -exec sudo chown root:root -- {} + find "$AC_BINPATH_FULL" -mindepth 1 -maxdepth 1 -type f -exec sudo chmod u+s -- {} + - DOCKER_ETC_FOLDER=${DOCKER_ETC_FOLDER:-"env/dist/etc"} - - if [[ $DOCKER = 1 && $DISABLE_DOCKER_CONF != 1 ]]; then - echo "Generating confs..." - - # Search for all configs under DOCKER_ETC_FOLDER - for dockerdist in "$DOCKER_ETC_FOLDER"/*.dockerdist; do - # Grab "base" conf. turns foo.conf.dockerdist into foo.conf - baseConf="$(echo "$dockerdist" | rev | cut -f1 -d. --complement | rev)" - # env/dist/etc/foo.conf becomes foo.conf - filename="$(basename "$baseConf")" - # the dist files should be always found inside $confDir - # which may not be the same as DOCKER_ETC_FOLDER - distPath="$confDir/$filename.dist" - # if dist file doesn't exist, skip this iteration - [ ! -f "$distPath" ] && continue - - # replace params in foo.conf.dist with params in foo.conf.dockerdist - conf_layer "$dockerdist" "$distPath" " # Copied from dockerdist" - - # Copy modified dist file to $confDir/$filename - # Don't overwrite foo.conf if it already exists. - cp --no-clobber --verbose "$distPath" "$confDir/$filename" - done - fi - echo "Done" ;; esac @@ -185,36 +159,3 @@ function comp_all() { comp_clean comp_build } - -# conf_layer FILENAME FILENAME -# Layer the configuration parameters from the first argument onto the second argument -function conf_layer() { - LAYER="$1" - BASE="$2" - COMMENT="$3" - - # Loop over all defined params in conf file - grep -E "^[a-zA-Z\.0-9]+\s*=.*$" "$LAYER" \ - | while read -r param - do - # remove spaces from param - # foo = bar becomes foo=bar - NOSPACE="$(tr -d '[:space:]' <<< "$param")" - - # split into key and value - KEY="$(cut -f1 -d= <<< "$NOSPACE")" - VAL="$(cut -f2 -d= <<< "$NOSPACE")" - # if key in base and val not in line - if grep -qE "^$KEY" "$BASE" && ! grep -qE "^$KEY.*=.*$VAL" "$BASE"; then - # Replace line - # Prevent issues with shell quoting - sed -i \ - 's,^'"$KEY"'.*,'"$KEY = $VAL$COMMENT"',g' \ - "$BASE" - else - # insert line - echo "$KEY = $VAL$COMMENT" >> "$BASE" - fi - done - echo "Layered $LAYER onto $BASE" -} diff --git a/apps/db_assembler/.gitignore b/apps/db_assembler/.gitignore deleted file mode 100644 index 0c63e20d7..000000000 --- a/apps/db_assembler/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/output/ -/backup/ -config.sh diff --git a/apps/db_assembler/README.md b/apps/db_assembler/README.md deleted file mode 100644 index 46ee0075e..000000000 --- a/apps/db_assembler/README.md +++ /dev/null @@ -1,24 +0,0 @@ -## Description - -**ATTENTION:** this tool is not supported anymore. It has been replaced by the **dbimport** tools integrated in AC server sources - -This script allows you to assemble all sql files into one so you can easily import it to your databases (or use the main script to import directly). By default, it creates the merged files in `/env/dist`. - -## How to use: - -First of all, if you need some custom configuration, you have to copy `/conf/dist/config.sh` to `/conf/config.sh` and configure it. The file is here: https://github.com/azerothcore/azerothcore-wotlk/tree/master/conf - -_Read it because there are several options to configure._ - -`db_assembler.sh` script contains an interactive menu to assemble and import sql files. -Just run it to display the options. - - -Note: You can even use actions directly by command lines specifying the option. -Ex: - - ./db_assembler.sh 1 - -It will merge all sql files without an interactive menu. - - diff --git a/apps/db_assembler/conf.dist.sh b/apps/db_assembler/conf.dist.sh deleted file mode 100644 index c16710b7d..000000000 --- a/apps/db_assembler/conf.dist.sh +++ /dev/null @@ -1,121 +0,0 @@ -############################################## -# -# DB ASSEMBLER / EXPORTER CONFIGURATIONS -# -############################################## - -# -# Comma separated list of databases -# -# You can add another element here if you need -# to support multiple databases -# - -DBLIST=${DBLIST:-"AUTH,CHARACTERS,WORLD"} -# convert from comma separated list to an array. -# This is needed to support environment variables -readarray -td, DATABASES <<<"$DBLIST"; - -OUTPUT_FOLDER=${OUTPUT_FOLDER:-"$AC_PATH_ROOT/env/dist/sql/"} - -DBASM_WAIT_TIMEOUT=${DBASM_WAIT_TIMEOUT:-5} -DBASM_WAIT_RETRIES=${DBASM_WAIT_RETRIES:-3} - -####### BACKUP -# Set to true if you want to backup your azerothcore databases before importing the SQL with the db_assembler -# Do not forget to stop your database software (mysql) before doing so - -BACKUP_ENABLE=false - -BACKUP_FOLDER="$AC_PATH_ROOT/env/dist/sql/backup/" - -####### - -# FULL DB -DB_AUTH_PATHS=( - "$SRCPATH/data/sql/base/db_auth/" -) - -DB_CHARACTERS_PATHS=( - "$SRCPATH/data/sql/base/db_characters" -) - -DB_WORLD_PATHS=( - "$SRCPATH/data/sql/base/db_world/" -) - -# UPDATES -DB_AUTH_UPDATES_PATHS=( - "$SRCPATH/data/sql/updates/db_auth/" - "$SRCPATH/data/sql/updates/pending_db_auth/" -) - -DB_CHARACTERS_UPDATES_PATHS=( - "$SRCPATH/data/sql/updates/db_characters/" - "$SRCPATH/data/sql/updates/pending_db_characters/" -) - -DB_WORLD_UPDATES_PATHS=( - "$SRCPATH/data/sql/updates/db_world/" - "$SRCPATH/data/sql/updates/pending_db_world/" -) - -# CUSTOM -DB_AUTH_CUSTOM_PATHS=( - "$SRCPATH/data/sql/custom/db_auth/" -) - -DB_CHARACTERS_CUSTOM_PATHS=( - "$SRCPATH/data/sql/custom/db_characters/" -) - -DB_WORLD_CUSTOM_PATHS=( - "$SRCPATH/data/sql/custom/db_world/" -) - -############################################## -# -# DB EXPORTER/IMPORTER CONFIGURATIONS -# -############################################## - -# -# Skip import of base sql files to avoid -# table dropping -# -DB_SKIP_BASE_IMPORT_IF_EXISTS=true - -# -# Example: -# "C:/Program Files/MySQL/MySQL Server 8.0/bin/mysql.exe" -# "/usr/bin/mysql" -# "mysql" -# - -DB_MYSQL_EXEC="mysql" -DB_MYSQL_DUMP_EXEC="mysqldump" - - -DB_AUTH_CONF=${DB_AUTH_CONF:-"MYSQL_USER='acore'; \ - MYSQL_PASS='acore'; \ - MYSQL_HOST='localhost';\ - MYSQL_PORT='3306';\ - "} - -DB_CHARACTERS_CONF=${DB_CHARACTERS_CONF:-"MYSQL_USER='acore'; \ - MYSQL_PASS='acore'; \ - MYSQL_HOST='localhost';\ - MYSQL_PORT='3306';\ - "} - -DB_WORLD_CONF=${DB_WORLD_CONF:-"MYSQL_USER='acore'; \ - MYSQL_PASS='acore'; \ - MYSQL_HOST='localhost';\ - MYSQL_PORT='3306';\ - "} - -DB_AUTH_NAME="acore_auth" - -DB_CHARACTERS_NAME="acore_characters" - -DB_WORLD_NAME="acore_world" diff --git a/apps/db_assembler/db_assembler.sh b/apps/db_assembler/db_assembler.sh deleted file mode 100755 index ba4e15e6a..000000000 --- a/apps/db_assembler/db_assembler.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash - -echo ----------------------------------------------------------------------------------------------- >&2 -echo ATTENTION: This tool is DEPRECATED. To assemble or update your DB, use the worldserver instead. >&2 -echo ----------------------------------------------------------------------------------------------- >&2 - -set -e - -CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_PATH/includes/includes.sh" - -cmdopt=$1 - -PS3='[Please enter your choice]: ' -options=( - "all: Assemble all" # 1 - "bases: Assemble only bases" # 2 - "updates: Assemble only updates" # 3 - "customs: Assemble only customs" # 4 - "import-all: Assemble & Import all" # 5 - "import-bases: Assemble & Import only bases" # 6 - "import-updates: Assemble & Import only updates" # 7 - "import-customs: Assemble & Import only customs" # 8 - "quit: Exit from this menu" # 9 - ) - -function _switch() { - _reply="$1" - _opt="$2" - - case $_reply in - ""|"all"|"1") - dbasm_run true true true - ;; - ""|"bases"|"2") - dbasm_run true false false - ;; - ""|"updates"|"3") - dbasm_run false true false - ;; - ""|"customs"|"4") - dbasm_run false false true - ;; - ""|"import-all"|"5") - dbasm_import true true true - ;; - ""|"import-bases"|"6") - dbasm_import true false false - ;; - ""|"import-updates"|"7") - dbasm_import false true false - ;; - ""|"import-customs"|"8") - dbasm_import false false true - ;; - ""|"quit"|"9") - echo "Goodbye!" - exit - ;; - ""|"--help") - echo "Available commands:" - printf '%s\n' "${options[@]}" - ;; - *) echo "invalid option, use --help option for the commands list";; - esac -} - -while true -do - # run option directly if specified in argument - [ ! -z $1 ] && _switch $@ - [ ! -z $1 ] && exit 0 - - select opt in "${options[@]}" - do - echo "===== DB ASSEMBLER MENU =====" - _switch $REPLY - break - done -done diff --git a/apps/db_assembler/includes/functions.sh b/apps/db_assembler/includes/functions.sh deleted file mode 100644 index cedea417c..000000000 --- a/apps/db_assembler/includes/functions.sh +++ /dev/null @@ -1,411 +0,0 @@ -# globals -PROMPT_USER="" -PROMPT_PASS="" - -function dbasm_waitMysqlConn() { - DBHOST="$1" - DBPORT="$2" - COUNT=0 - while ! mysqladmin ping -h"$DBHOST" --port="$DBPORT" --silent; do - ((COUNT++)) - if [ $COUNT -gt $DBASM_WAIT_RETRIES ]; then - echo "DBASM Timeout: Cannot ping mysql!" 1>&2 - exit 64 - fi - echo "Cannot ping mysql on $DBHOST:$DBPORT, retry in $DBASM_WAIT_TIMEOUT seconds (remaining: $COUNT/$DBASM_WAIT_RETRIES)..." - sleep $DBASM_WAIT_TIMEOUT - done -} - -# use in a subshell -function dbasm_resetExitCode() { - exit 0 -} - -function dbasm_mysqlExec() { - confs=$1 - command=$2 - options=$3 - - # MYSQL_PORT needs to be reseted as the next eval might not overwite the current value causing the commands to use wrong port - MYSQL_PORT=3306 - eval $confs - - if [[ ! -z "${PROMPT_USER// }" ]]; then - MYSQL_USER=$PROMPT_USER - MYSQL_PASS=$PROMPT_PASS - fi - - dbasm_waitMysqlConn $MYSQL_HOST $MYSQL_PORT - - export MYSQL_PWD=$MYSQL_PASS - - retval=$("$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$MYSQL_USER" -P "$MYSQL_PORT" $options -e "$command") - if [[ $? -ne 0 ]]; then - err=$("$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$MYSQL_USER" -P "$MYSQL_PORT" $options -e "$command" 2>&1 ) - if [[ "$err" == *"Access denied"* ]]; then - read -p "Insert mysql user:" PROMPT_USER - read -p "Insert mysql pass:" -s PROMPT_PASS - export MYSQL_PWD=$PROMPT_PASS - - retval=$("$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$PROMPT_USER" -P "$MYSQL_PORT" $options -e "$command") - if [[ $? -ne 0 ]]; then - err=$("$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$PROMPT_USER" -P "$MYSQL_PORT" $options -e "$command" 2>&1 ) - # it happens on new mysql 5.7 installations - # since mysql_native_password is explicit now - if [[ "$err" == *"Access denied"* ]]; then - echo "Setting mysql_native_password and for $PROMPT_USER ..." - sudo -h "$MYSQL_HOST" "$DB_MYSQL_EXEC" -P "$MYSQL_PORT" -e "UPDATE mysql.user SET authentication_string=PASSWORD('${PROMPT_PASS}'), plugin='mysql_native_password' WHERE User='${PROMPT_USER}'; FLUSH PRIVILEGES;" - fi - fi - - # create configured account if not exists - "$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$PROMPT_USER" $options -P "$MYSQL_PORT" -e "CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'${MYSQL_HOST}' IDENTIFIED BY '${MYSQL_PASS}' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0;" - "$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$PROMPT_USER" $options -P "$MYSQL_PORT" -e "GRANT CREATE ON *.* TO '${MYSQL_USER}'@'${MYSQL_HOST}' WITH GRANT OPTION;" - for db in ${DATABASES[@]} - do - local _uc=${db^^} - local _name="DB_"$_uc"_CONF" - local _confs=${!_name} - - local _name="DB_"$_uc"_NAME" - local _dbname=${!_name} - - eval $_confs - echo "Grant permissions for ${MYSQL_USER}'@'${MYSQL_HOST} to ${_dbname}" - "$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$PROMPT_USER" $options -P "$MYSQL_PORT" -e "GRANT ALL PRIVILEGES ON ${_dbname}.* TO '${MYSQL_USER}'@'${MYSQL_HOST}' WITH GRANT OPTION; FLUSH PRIVILEGES;" - done - else - exit - fi - fi -} - -function dbasm_isNotEmpty() { - dbname=$1 - conf=$2 - - dbasm_mysqlExec "$conf" "SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_schema = '${dbname}'" "--skip-column-names" - if (( $retval > 0 )); then - true - else - false - fi -} - -function dbasm_dbExists() { - dbname=$1 - conf=$2 - - dbasm_mysqlExec "$conf" "SHOW DATABASES LIKE '${dbname}'" "--skip-column-names" - if [ "$retval" == "${dbname}" ]; then - true - else - false - fi -} - -function dbasm_createDB() { - database=${1,,} - - uc=${database^^} - - name="DB_"$uc"_CONF" - confs=${!name} - - name="DB_"$uc"_NAME" - dbname=${!name} - - eval $confs - - CONF_USER=$MYSQL_USER - CONF_PASS=$MYSQL_PASS - - if dbasm_dbExists $dbname "$confs"; then - echo "$dbname database exists" - else - echo "Creating DB ${dbname} ..." - dbasm_mysqlExec "$confs" "CREATE DATABASE \`${dbname}\`;" "" - echo "Creating User ${CONF_USER}@${MYSQL_HOST} identified by ${CONF_PASS}..." - dbasm_mysqlExec "$confs" "CREATE USER IF NOT EXISTS '${CONF_USER}'@'${MYSQL_HOST}' IDENTIFIED BY '${CONF_PASS}';" - echo "Granting user privileges on: ${dbname} ..." - dbasm_mysqlExec "$confs" "GRANT ALL PRIVILEGES ON \`${dbname}\`.* TO '${CONF_USER}'@'${MYSQL_HOST}'" - echo "Flush privileges" - dbasm_mysqlExec "$confs" "FLUSH PRIVILEGES;" - fi -} - -function dbasm_assemble() { - # to lowercase - database=${1,,} - start_sql=$2 - with_base=$3 - with_updates=$4 - with_custom=$5 - - uc=${database^^} - - name="DB_"$uc"_PATHS" - v="$name[@]" - base=("${!v}") - - name="DB_"$uc"_UPDATES_PATHS" - v="$name[@]" - updates=("${!v}") - - name='DB_'$uc'_CUSTOM_PATHS' - v="$name[@]" - custom=("${!v}") - - - suffix_base="_base" - suffix_upd="_updates" - suffix_custom="_custom" - - curTime=`date +%Y_%m_%d_%H_%M_%S` - - # ALLOW FOR RECURSION WITH "**" - shopt -s globstar - - if [ $with_base = true ]; then - echo "" > "$OUTPUT_FOLDER$database$suffix_base.sql" - - - if [ ! ${#base[@]} -eq 0 ]; then - echo "Generating $OUTPUT_FOLDER$database$suffix_base ..." - - for d in "${base[@]}" - do - echo "Searching on $d ..." - if [ ! -z "$d" ]; then - for entry in "$d"/**/*.sql - do - if [[ -e $entry ]]; then - cat "$entry" >> "$OUTPUT_FOLDER$database$suffix_base.sql" - fi - done - fi - done - fi - fi - - if [ $with_updates = true ]; then - updFile="$OUTPUT_FOLDER$database$suffix_upd.sql" - - echo "" > "$updFile" - - if [ ! ${#updates[@]} -eq 0 ]; then - echo "Generating $OUTPUT_FOLDER$database$suffix_upd ..." - - for d in "${updates[@]}" - do - echo "Searching on $d ..." - if [ ! -z "$d" ]; then - for entry in "$d"/**/*.sql - do - if [[ ! -e $entry ]]; then - continue - fi - - echo "-- $file" >> "$updFile" - cat "$entry" >> "$updFile" - done - fi - done - fi - fi - - if [ $with_custom = true ]; then - custFile="$OUTPUT_FOLDER$database$suffix_custom.sql" - - echo "" > "$custFile" - - if [ ! ${#custom[@]} -eq 0 ]; then - echo "Generating $OUTPUT_FOLDER$database$suffix_custom ..." - - for d in "${custom[@]}" - do - echo "Searching on $d ..." - if [ ! -z "$d" ]; then - for entry in "$d"/**/*.sql - do - if [[ ! -e $entry ]]; then - continue - fi - - echo "-- $file" >> "$custFile" - cat "$entry" >> "$custFile" - done - fi - done - fi - fi -} - -function dbasm_run() { - echo "===== STARTING ASSEMBLY PROCESS =====" - - mkdir -p "$OUTPUT_FOLDER" - - for db in ${DATABASES[@]} - do - dbasm_assemble "$db" $version".sql" $1 $2 $3 - done - - echo "===== DONE =====" -} - -function dbasm_db_backup() { - echo "backing up $1" - - database=${1,,} - - uc=${database^^} - - name="DB_"$uc"_CONF" - confs=${!name} - - name="DB_"$uc"_NAME" - dbname=${!name} - - # MYSQL_PORT needs to be reseted as the next eval might not overwite the current value causing the commands to use wrong port - MYSQL_PORT=3306 - eval $confs; - - if [[ ! -z "${PROMPT_USER// }" ]]; then - MYSQL_USER=$PROMPT_USER - MYSQL_PASS=$PROMPT_PASS - fi - - - export MYSQL_PWD=$MYSQL_PASS - - now=`date +%s` - - "$DB_MYSQL_DUMP_EXEC" --opt --user="$MYSQL_USER" --host="$MYSQL_HOST" --port="$MYSQL_PORT" "$dbname" > "${BACKUP_FOLDER}${database}_backup_${now}.sql" && echo "done" - if [[ $? -ne 0 ]]; then - err=$("$DB_MYSQL_DUMP_EXEC" --opt --user="$MYSQL_USER" --host="$MYSQL_HOST" --port="$MYSQL_PORT" "$dbname" 2>&1 ) - if [[ "$err" == *"Access denied"* ]]; then - read -p "Insert mysql user:" PROMPT_USER - read -p "Insert mysql pass:" -s PROMPT_PASS - export MYSQL_PWD=$PROMPT_PASS - - "$DB_MYSQL_DUMP_EXEC" --opt --user="$PROMPT_USER" --host="$MYSQL_HOST" --port="$MYSQL_PORT" "$dbname" > "${BACKUP_FOLDER}${database}_backup_${now}.sql" && echo "done" - else - exit - fi - fi -} - -function dbasm_db_import() { - database=${1,,} - type=$2 - - uc=${database^^} - - name="DB_"$uc"_CONF" - confs=${!name} - - name="DB_"$uc"_NAME" - dbname=${!name} - - if [[ $type = "base" && $DB_SKIP_BASE_IMPORT_IF_EXISTS = true ]]; then - if dbasm_isNotEmpty $dbname "$confs"; then - echo "$dbname is not empty, base importing skipped" - return - else - echo "$dbname seems empty" - fi - fi - - echo "importing $1 - $2 ..." - - # MYSQL_PORT needs to be reseted as the next eval might not overwite the current value causing the commands to use wrong port - MYSQL_PORT=3306 - eval $confs; - - if [[ ! -z "${PROMPT_USER// }" ]]; then - MYSQL_USER=$PROMPT_USER - MYSQL_PASS=$PROMPT_PASS - fi - - dbasm_waitMysqlConn $MYSQL_HOST $MYSQL_PORT - - export MYSQL_PWD=$MYSQL_PASS - - - # TODO: remove this line after we squash our DB updates - "$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$MYSQL_USER" --port="$MYSQL_PORT" -e "SET GLOBAL max_allowed_packet=128*1024*1024;" - - "$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$MYSQL_USER" --port="$MYSQL_PORT" --default-character-set=utf8 "$dbname" < "${OUTPUT_FOLDER}${database}_${type}.sql" - - if [[ $? -ne 0 ]]; then - err=$("$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$MYSQL_USER" -P "$MYSQL_PORT" "$dbname" 2>&1 ) - if [[ "$err" == *"Access denied"* ]]; then - read -p "Insert mysql user:" PROMPT_USER - read -p "Insert mysql pass:" -s PROMPT_PASS - export MYSQL_PWD=$PROMPT_PASS - - "$DB_MYSQL_EXEC" -h "$MYSQL_HOST" -u "$PROMPT_USER" -P "$MYSQL_PORT" "$dbname" < "${OUTPUT_FOLDER}${database}_${type}.sql" - else - exit - fi - fi -} - -function dbasm_import() { - dbasm_run $1 $2 $3 - - with_base=$1 - with_updates=$2 - with_custom=$3 - - echo "===== CHECKING DBs =====" - for db in ${DATABASES[@]} - do - dbasm_createDB "$db" - done - echo "===== DONE =====" - - # - # BACKUP - # - - if [ $BACKUP_ENABLE = true ]; then - echo "===== STARTING BACKUP PROCESS =====" - mkdir -p "$BACKUP_FOLDER" - - for db in ${DATABASES[@]} - do - dbasm_db_backup "$db" - done - echo "===== DONE =====" - fi - - echo "===== STARTING IMPORTING PROCESS =====" - # - # IMPORT - # - if [ $with_base = true ]; then - for db in ${DATABASES[@]} - do - dbasm_db_import "$db" "base" - done - fi - - if [ $with_updates = true ]; then - for db in ${DATABASES[@]} - do - dbasm_db_import "$db" "updates" - done - fi - - if [ $with_custom = true ]; then - for db in ${DATABASES[@]} - do - dbasm_db_import "$db" "custom" - done - fi - - echo "===== DONE =====" -} diff --git a/apps/db_assembler/includes/includes.sh b/apps/db_assembler/includes/includes.sh deleted file mode 100644 index 50bb57535..000000000 --- a/apps/db_assembler/includes/includes.sh +++ /dev/null @@ -1,11 +0,0 @@ -CURRENT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_PATH/../../bash_shared/includes.sh" - -AC_PATH_DBASSEMBLER="$AC_PATH_APPS/db_assembler" - -if [ -f "$AC_PATH_DBASSEMBLER/config.sh" ]; then - source "$AC_PATH_DBASSEMBLER/config.sh" # should overwrite previous -fi - -source "$AC_PATH_DBASSEMBLER/includes/functions.sh" diff --git a/apps/docker/Dockerfile b/apps/docker/Dockerfile index ff88df557..aee1d680e 100644 --- a/apps/docker/Dockerfile +++ b/apps/docker/Dockerfile @@ -18,6 +18,9 @@ LABEL description="AC base image for dev containers" ENV DOCKER=1 +# Ensure ac-dev-server can properly pull versions +ENV GIT_DISCOVERY_ACROSS_FILESYSTEM=1 + # set timezone environment variable ENV TZ=Etc/UTC @@ -34,14 +37,17 @@ RUN apt-get update && apt-get install -y gdb gdbserver git dos2unix lsb-core sud libncurses5-dev ccache \ && rm -rf /var/lib/apt/lists/* +# Ensure git will work with the AzerothCore source directory +RUN git config --global --add safe.directory /azerothcore + # change timezone in container RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata # Create a non-root user -RUN addgroup --gid $GROUP_ID acore && \ - adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID acore && \ - passwd -d acore && \ - echo 'acore ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers +RUN addgroup --gid "$GROUP_ID" "$DOCKER_USER" && \ + adduser --disabled-password --gecos '' --uid "$USER_ID" --gid "$GROUP_ID" "$DOCKER_USER" && \ + passwd -d "$DOCKER_USER" && \ + echo "$DOCKER_USER ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers # must be created to set the correct permissions on them RUN mkdir -p /azerothcore/env/dist/bin @@ -94,11 +100,6 @@ USER $DOCKER_USER # NOTE: this folder is different by the /azerothcore (which is binded instead) COPY --chown=$DOCKER_USER:$DOCKER_USER . /azerothcore -# Needed if we use the dev image without linking any external folder (e.g. acore-docker) -COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/authserver.conf.dockerdist /azerothcore/env/dist/etc/authserver.conf.dockerdist -COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/worldserver.conf.dockerdist /azerothcore/env/dist/etc/worldserver.conf.dockerdist -COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/dbimport.conf.dockerdist /azerothcore/env/dist/etc/dbimport.conf.dockerdist - #================================================================ # # SERVICE BASE: prepare the OS for the production-ready services @@ -122,10 +123,10 @@ ENV TZ=Etc/UTC ENV DEBIAN_FRONTEND=noninteractive # Create a non-root user -RUN addgroup --gid $GROUP_ID acore && \ - adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID acore && \ - passwd -d acore && \ - echo 'acore ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers +RUN addgroup --gid "$GROUP_ID" "$DOCKER_USER" && \ + adduser --disabled-password --gecos '' --uid "$USER_ID" --gid "$GROUP_ID" "$DOCKER_USER" && \ + passwd -d "$DOCKER_USER" && \ + echo "$DOCKER_USER ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers # install the required dependencies to run the server RUN apt-get update && apt-get install -y dos2unix gdb gdbserver google-perftools libgoogle-perftools-dev net-tools \ @@ -205,9 +206,6 @@ COPY --chown=$DOCKER_USER:$DOCKER_USER ./modules /azerothcore/modules # check if we have ccache files available outside RUN rm -rf /azerothcore/var/ccache/* COPY --chown=$DOCKER_USER:$DOCKER_USER var/docker/ccache /azerothcore/var/ccache -COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/authserver.conf.dockerdist /azerothcore/env/dist/etc/authserver.conf.dockerdist -COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/worldserver.conf.dockerdist /azerothcore/env/dist/etc/worldserver.conf.dockerdist -COPY --chown=$DOCKER_USER:$DOCKER_USER env/docker/etc/dbimport.conf.dockerdist /azerothcore/env/dist/etc/dbimport.conf.dockerdist # install eluna RUN git clone --depth=1 --branch=master https://github.com/azerothcore/mod-eluna.git /azerothcore/modules/mod-eluna @@ -279,10 +277,10 @@ ENV TZ=Etc/UTC # set noninteractive mode so tzdata doesn't ask to set timezone on install ENV DEBIAN_FRONTEND=noninteractive -RUN addgroup --gid $GROUP_ID acore && \ - adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID acore && \ - passwd -d acore && \ - echo 'acore ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers +RUN addgroup --gid "$GROUP_ID" "$DOCKER_USER" && \ + adduser --disabled-password --gecos '' --uid "$USER_ID" --gid "$GROUP_ID" "$DOCKER_USER" && \ + passwd -d "$DOCKER_USER" && \ + echo "$DOCKER_USER ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers # ENV DATAPATH=/azerothcore/env/dist/data-temp ENV DATAPATH=/azerothcore/env/dist/data @@ -321,10 +319,10 @@ RUN apt-get update && apt-get install -y libmysqlclient-dev libssl-dev libbz2-de sudo && rm -rf /var/lib/apt/lists/* ; # Create a non-root user -RUN addgroup --gid $GROUP_ID acore && \ - adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID acore && \ - passwd -d acore && \ - echo 'acore ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers +RUN addgroup --gid "$GROUP_ID" "$DOCKER_USER" && \ + adduser --disabled-password --gecos '' --uid "$USER_ID" --gid "$GROUP_ID" "$DOCKER_USER" && \ + passwd -d "$DOCKER_USER" && \ + echo "$DOCKER_USER ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers RUN mkdir -p /azerothcore/env/client/ RUN chown -R $DOCKER_USER:$DOCKER_USER /azerothcore diff --git a/conf/dist/env.docker b/conf/dist/env.docker index 030f20d9f..3a598adad 100644 --- a/conf/dist/env.docker +++ b/conf/dist/env.docker @@ -9,11 +9,7 @@ DOCKER_VOL_ROOT= DOCKER_VOL_CONF= DOCKER_VOL_ETC= DOCKER_VOL_LOGS= -DOCKER_VOL_DATA_CAMERAS= -DOCKER_VOL_DATA_DBC= -DOCKER_VOL_DATA_MAPS= -DOCKER_VOL_DATA_VMAPS= -DOCKER_VOL_DATA_MMAPS= +DOCKER_VOL_DATA= DOCKER_WORLD_EXTERNAL_PORT= DOCKER_SOAP_EXTERNAL_PORT= diff --git a/data/sql/updates/db_world/2023_08_10_00.sql b/data/sql/updates/db_world/2023_08_10_00.sql new file mode 100644 index 000000000..bad9ef958 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_10_00.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_09_02 -> 2023_08_10_00 +-- +DELETE FROM `creature_template_resistance` WHERE `CreatureID` IN (4632, 4633, 4634, 4635, 4636, 4637); diff --git a/data/sql/updates/db_world/2023_08_10_01.sql b/data/sql/updates/db_world/2023_08_10_01.sql new file mode 100644 index 000000000..332924e64 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_10_01.sql @@ -0,0 +1,55 @@ +-- DB update 2023_08_10_00 -> 2023_08_10_01 +DELETE FROM `quest_request_items_locale` WHERE `ID` IN (1201, 1222, 1249, 1258, 1262, 1273, 1324, 1358, 1361, 1367, 1368, 1380, 1381, 1382, 1384, 1385, 1386, 1387, 1434, 1439, 1456, 1457, 1458, 1459, 1466, 1467, 1485, 1487, 1488, 1489, 1498, 1525, 1560, 1578, 1579, 1598, 1618, 1640, 1654, 1655, 1657, 1679, 1692, 1704, 1714, 1719, 1795, 1799, 1819, 1940, 1955, 1957) AND `locale` = 'deDE'; +INSERT INTO `quest_request_items_locale` (`ID`, `locale`, `CompletionText`, `VerifiedBuild`) VALUES +(1201, 'deDE', 'Habt Ihr die Spitzel gefunden, $N?', 0), +(1222, 'deDE', 'Habt Ihr Ignatz gesehen? Ich habe ihn vor einer Weile in die Marschen geschickt und er ist noch nicht zurückgekehrt!', 0), +(1249, 'deDE', 'Ist er entronnen? Sah ein wenig zwielichtig aus, wie er uns beobachtet hat.', 0), +(1258, 'deDE', 'Meine Experimente mit den Schlammpanzerzungen machen gute Fortschritte. Ich hoffe, Eure Krebssuche kommt voran?', 0), +(1262, 'deDE', 'Ihr seid von Brackenwall in den Düstermarschen hierher gereist? Wie geht es Nazeer und wie weit sind seine Bemühungen im Sumpf gediehen?', 0), +(1273, 'deDE', 'Habt Ihr Reethe gefunden?', 0), +(1324, 'deDE', 'Hallo $N. Ich hoffe Ihr habt nichts gegen mein Eingreifen, aber wir konnten nicht zulassen, dass Hendel entkommt oder schlimmer, dass er stirbt.', 0), +(1358, 'deDE', 'Habt Ihr ein Päckchen für mich?', 0), +(1361, 'deDE', 'Wie ich sehe, ist Eure Aufgabe unvollendet, $N. Soll ich Sharlindra über Eure Unfähigkeit in Kenntnis setzen?', 0), +(1367, 'deDE', 'Verschwindet! Die Magram sprechen nicht mit den Schwachen. Wir töten sie!$B$BWenn Ihr mit mir sprechen wollt, dann zeigt mir, dass Ihr stark seid. Kehrt zurück, wenn Ihr viele Gelkis getötet habt.', 0), +(1368, 'deDE', 'Ihr steht mit beiden Füßen auf Erde der Gelkis. Ihr seid hier nicht willkommen!$B$BBeweist, dass Ihr die Freundschaft der Gelkis sucht. Tötet Zentauren der Magram. Kommt wieder, wenn der Boden vom Blut der Magram getränkt ist.', 0), +(1380, 'deDE', 'Ist Khan Hratha tot? Habt Ihr das Schlüsselfragment?', 0), +(1381, 'deDE', 'Tut, was ich verlange. Beweist mir, dass Ihr ein Verbündeter der Magram seid!', 0), +(1382, 'deDE', 'Verschwindet! Die Gelkis wollen Euch hier nicht. Geht jetzt!!$B$BKehrt zurück, nachdem Ihr viele Magram getötet habt, und dann werde ich mit Euch sprechen.', 0), +(1384, 'deDE', 'Habt Ihr die Glücksbringer? Habt Ihr den Kolkar gezeigt, dass sie schwach sind?', 0), +(1385, 'deDE', 'Ihr werdet jetzt gehen oder die Magram werden Euch zerquetschen! Um unser Freund zu sein, müsst Ihr Gelkis töten.', 0), +(1386, 'deDE', 'Habt Ihr Angst vor den Kolkar? Warum tötet Ihr sie nicht? Vielleicht habt Ihr vergessen, wie man tötet. Beeilt Euch und tötet Kolkar bevor sie eines natürlichen Todes sterben!', 0), +(1387, 'deDE', 'Habt Ihr einen Bericht, $N?', 0), +(1434, 'deDE', 'Ich wurde von einem taurischen Gefährten gewarnt, dass die Satyrn nicht das sind, was sie zu sein scheinen. Er glaubt, dass etwas mehr an ihnen dran ist, dass ihr Böses eine Verdrehung ihrer wahren Natur ist. Aber ich habe solche Dinge nicht gesehen.$B$BIch sehe nur das rücksichtslose Abschlachten der Schwachen und die Verderbnis derer, die nach dunkler Macht streben.$B$BIch werde meiner Pflicht, sie zu vernichten, so lange nachkommen, bis der Kriegshäuptling mir etwas anderes befiehlt. Bis dahin habe ich kein Erbarmen mit ihnen.', 0), +(1439, 'deDE', 'Ich fürchte, Tyranis wird versuchen, die Geheimnisse der Brennenden Klinge zu erlernen und sich ihnen anschließen, wenn sie ihn lassen - er hat stets die Macht bewundert, die Magie allen bringt, die sich von ihr verführen lassen.$B$BIch bin nicht sicher, ob ich zu meiner Familie zurückkehren und ihnen sagen kann, dass Tyranis\' Geist mit solchen Gefahren spielt. Bei meinesgleichen ist es ein schreckliches Verbrechen, so etwas zu suchen, aber das zu werden, wovor wir uns schützen möchten, das ist verständlich.', 0), +(1456, 'deDE', 'Nicht, dass ich Nijel zu nahe treten wollte, wer immer das sein mag, aber dieses Lager ist nicht das bequemste, in dem ich je eine Nacht verbrachte, $N.', 0), +(1457, 'deDE', 'Das Geschäft blüht, $N, und ich habe nicht viel Zeit für Fragen. Wenn Ihr etwas von den Wiederholern wollt, rückt heraus damit. Wenn nicht, muss ich Euch bitten, mit einem meiner Handlanger zu sprechen. Sie sind durchaus imstande, sich um alles hier zu kümmern.', 0), +(1458, 'deDE', 'Abscheuliche Kreaturen, die Satyrn. Man sagt, sie seien irgendwie mit den Nachtelfen verwandt, doch das glaube ich nicht.$B$BIch glaube, das liegt nur an dem einen Elfen, der sie vor Jahren überredete, in den Krieg zu ziehen. Das hat die Welt für immer verändert. Heute ist sie viel gefährlicher und Furcht erregender.', 0), +(1459, 'deDE', 'Entschuldigt, dass ich Euch nicht sagen konnte, wo man Kodos oder Skorpashi findet. Ich kenne mich in der Gegend nicht gut aus und hatte keine Zeit, sie zu erkunden.', 0), +(1466, 'deDE', 'Ich wusste nicht einmal, dass es diese Dämonenwesen in Desolace gibt. Zuletzt hörte ich, dass das Land weitgehend den Zentauren gehört, nachdem die Nachtelfen vor Jahren zusammengepackt haben und abgezogen sind.$B$BIch frage mich, warum und wie sie hierher kamen.', 0), +(1467, 'deDE', 'Grüße, $N. Das Geschäft blüht, die Laute von Hämmern auf Ambossen hallen durch ganz Eisenschmiede, die Blasebälge entfachen das Feuer und meine Frau backt mir einen Kuchen als Dessert nach dem Abendessen. Könnte das Leben schöner sein?', 0), +(1485, 'deDE', 'Es ist wichtig, dass Ihr die Wesen kontrollieren könnt, die Ihr durch Eure Magie beschwört. Nur wenige interessieren sich für die Lehren der Hexenmeister, daher möchte ich Euer Leben nicht gefährden, indem ich Euch etwas lehre, ehe Ihr dazu bereit seid.', 0), +(1487, 'deDE', '$N, wir, die Jünger von Naralex, brauchen Eure Hilfe. Unsere Zahl schwindet, während unser Meister in seinem verzerrten Albtraum gefangen ist. Wir haben nicht die nötigen Kräfte, um mit den verdorbenen Kreaturen fertig zu werden, die jetzt diese Höhlen heimsuchen.$b$bIch bitte Euch, betretet die Höhlen und führt Krieg gegen diese abartigen Kreaturen!', 0), +(1488, 'deDE', 'Ruhm für die Horde und Tod für unsere Feinde, $N!$B$BDie Dämonen in Desolace stellen eine größere Bedrohung dar als je zuvor. Meine Hoffnung, zum Kriegshäuptling zurückzukehren, schwindet, je mehr dieser widerlichen Kreaturen auftauchen.$B$BManchmal wünschte ich, wir hätten es nur mit den Zentauren zu tun.', 0), +(1489, 'deDE', 'Eure Meister sind Narren, Euch hierher zu schicken, denn ich werde nie wieder ein Sklave der Geißel sein!', 0), +(1498, 'deDE', 'Habt Ihr die Schuppen, $N? Wenn Ihr den Angriffen der Donnerechsen nicht trotzen könnt, könnt Ihr von meiner Unterweisung nicht profitieren.', 0), +(1525, 'deDE', 'Ich habe genügend Zutaten für ein Feuersapta, wenn Ihr den Reagenzienbeutel und etwas Feuerteer finden könnt. Die Fanatiker der Brennenden Klinge tragen die richtigen Komponenten für die meisten ihrer Zauber in diesen Beuteln und haben meist ausreichend von den Gegenständen, die ich benötige, damit Ihr nicht weiter nach etwas anderem suchen müsst.$B$BDie Saptas werden stets aus Zutaten hergestellt, die in enger Verbindung zu ihrem jeweiligen Element stehen. Es macht unsere Arbeit leichter, da die Hexenmeister mit dem Feuer verbunden sind.', 0), +(1560, 'deDE', 'Wo ist Tooga?', 0), +(1578, 'deDE', 'Ich habe keine Zeit zu plaudern. Haben wir etwas miteinander zu tun?', 0), +(1579, 'deDE', 'Habt Ihr meine Klemmmuffen gefunden, $N? Ohne meine Klemmmuffen kann ich meine Stintelpleuel nicht nachziehen!', 0), +(1598, 'deDE', 'Es wäre zu auffällig für mich gewesen, das Buch selbst zu stehlen. Zum Glück hat mir einer ihrer eigenen Trottel die Drecksarbeit abgenommen.', 0), +(1618, 'deDE', 'Ich hoffe, Ihr bringt gute Nachrichten aus Eisenschmiede. Denn ich bin mit meiner Weisheit am Ende!', 0), +(1640, 'deDE', 'Wenn Ihr diesen Krug wollt, müsst Ihr ihn mir aus den kalten, toten Händen brechen...', 0), +(1654, 'deDE', 'Es dürfte schwer sein, die Gegenstände zu bekommen, die Ihr sucht, aber ich versichere Euch, die Waffe, die ich für Euch anfertige, rechtfertigt den Aufwand.$B$BSie wird meine bis dato beste Arbeit werden, und doch nur ein geringer Lohn für den Dienst, den Ihr mir erwiesen habt.', 0), +(1655, 'deDE', 'Aha, schon Glück gehabt? Ha-ha, diese Oger konnten Euch nichts anhaben, was?', 0), +(1657, 'deDE', 'Habt Ihr unser "Geschenk" an die Leute von Süderstade ausgeliefert?$B$B.', 0), +(1679, 'deDE', NULL, 0), +(1692, 'deDE', 'Seid gegrüßt, $Gjunger:junge; $C. Wie kann ich Euch mit meinen Fertigkeiten dienlich sein?', 0), +(1704, 'deDE', 'Guten Tag, Morgen oder Abend. Ich kann es von hier unten nicht erkennen. Bringt Ihr mir Arbeit?', 0), +(1714, 'deDE', 'Der Kessel blubbert. Seine Dämpfe locken...', 0), +(1719, 'deDE', 'Habt Ihr die Herausforderung absolviert?', 0), +(1795, 'deDE', 'Jedem Hexenmeister sollte ein Teufelsjäger zur Verfügung stehen. Obwohl er schwer zu bändigen ist, macht die Macht, die er seinem Herrn gibt, die Kosten bei weitem wett.', 0), +(1799, 'deDE', 'Da Ihr offensichtlich kein Magier seid, frage ich mich, ob ich Euch überhaupt trauen kann. Ich kann die Macht des Arkanen an Euch riechen, aber Ihr scheint Euch dem Gestank der Verderbnis entzogen zu haben, der Eurer Art so bereitwillig anhängt.$B$BJa, $Gein:eine; $C ... $Gein:eine; $C ist gekommen, um mich um Hilfe zu bitten.$B$BNun, was kann ich für Euch tun, $N?', 0), +(1819, 'deDE', 'Eure Aufgabe ist noch nicht erfüllt, $N. Es ist nicht klug für $Geinen:eine; $C, Furcht zu zeigen...', 0), +(1940, 'deDE', 'Ah, ja. Die Magier im Magiersanktum sagten, dass Ihr mit mir sprechen wollt. Habt Ihr die benötigte Seide?', 0), +(1955, 'deDE', 'Ihr müsst den Dämon töten, um die Kugel von seinem Einfluss zu befreien, $N.', 0), +(1957, 'deDE', 'Ihr habt nicht die erforderliche Anzahl an Manawogen getötet, $N.', 0); diff --git a/data/sql/updates/db_world/2023_08_10_02.sql b/data/sql/updates/db_world/2023_08_10_02.sql new file mode 100644 index 000000000..3d5d550f7 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_10_02.sql @@ -0,0 +1,39 @@ +-- DB update 2023_08_10_01 -> 2023_08_10_02 +DELETE FROM `quest_request_items_locale` WHERE `ID` IN (2118, 2138, 2139, 2201, 2202, 2205, 2206, 2240, 2338, 2358, 2359, 2460, 2500, 2518, 2623, 2742, 2747, 2748, 2749, 2750, 2767, 2768, 2843, 2863, 2871, 2877, 2880, 2881, 2904, 2930, 2933, 2936, 2975, 2980, 2982, 2995) AND `locale` = 'deDE'; +INSERT INTO `quest_request_items_locale` (`ID`, `locale`, `CompletionText`, `VerifiedBuild`) VALUES +(2118, 'deDE', 'Habt Ihr mir das kranke Tier gebracht, $N?$B$BMacht Euch keine Sorgen, sollte das Zuschnappen der Falle nicht gelingen - Tharnariuns Hoffnung währt ewig. Wenn Ihr eine neue Falle braucht, lasst von Eurer Arbeit ab und meldet Euch bei mir.', 0), +(2138, 'deDE', 'Ist Eure Aufgabe abgeschlossen?', 0), +(2139, 'deDE', 'Durch das Töten der infizierten Höhlenmutter wird die Population der tollwütigen Distelbären, die in unser Land eindringen, abnehmen. Vergeudet keine Zeit, $N.', 0), +(2201, 'deDE', 'Talvashs Bild nimmt in dem Wasser der Wahrsageschale Kontur an.$B$B"Hey, Ihr lebt noch! Habt Ihr die Edelsteine gefunden? Könnt Ihr wirklich meinen guten Ruf retten, so wie ich das erhofft habe? Bitte sagt mir, dass Ihr keine Ladung der Phiole verbraucht habt, um mal schnell hallo zu sagen. Diese Dinge sind nicht billig und ich pfeife finanziell gesehen jetzt schon aus dem letzten Loch."', 0), +(2202, 'deDE', 'Habt Ihr die Magentafunguskappen bekommen, die ich für meine alchimistische Arbeit benötige? Keine Kappen - keine Belohnung!', 0), +(2205, 'deDE', 'Kann ich Euch helfen, $C?', 0), +(2206, 'deDE', 'Eure Sterblichkeit schwindet mit jedem Moment, den Ihr in der Kaserne verweilt, $C.', 0), +(2240, 'deDE', 'Habt Ihr etwas zu berichten?', 0), +(2338, 'deDE', 'Ihr habt es Euch überlegt, ja? Ihr seid $Gein schlauer:eine schlaue; $C, wenn Ihr dieses Angebot annehmt - Ihr und ich werden beide bekommen, was wir wollen, und \'Droffers und Sohn Bergungen\' werden denken, dass sie bekommen, was sie wollen.', 0), +(2358, 'deDE', 'Habt Ihr die Hörner des Dämonenprinzen?', 0), +(2359, 'deDE', 'Gibt es etwas Neues von Agentin Kearnen?', 0), +(2460, 'deDE', 'Übung macht den Meister!', 0), +(2500, 'deDE', 'Habt Ihr die Sachen schon, die ich brauche? Ihr werdet nur bezahlt, wenn Ihr mir diese Reagenzien bringt.', 0), +(2518, 'deDE', 'Ich bedauere, dass ich Euch die Aufgabe stellen musste, die ich Euch gestellt habe, aber für Lady Sathrah gibt es keine Hoffnung mehr.$B$BMit den Spinndrüsen wollen wir Elune ein Opfer bringen. Wir hoffen, dass Elune aufgrund dieses Opfers Sathrah segnen wird, damit sie wiedergeboren werden und endlich Frieden finden kann.', 0), +(2623, 'deDE', 'Warten auf Befehle.', 0), +(2742, 'deDE', 'Rin\'ji hat Angst!', 0), +(2747, 'deDE', 'Ich habe bisher nur sehr wenige Eier gesehen, die in außergewöhnlich gutem Zustand aus Feralas geholt wurden. Diese Eier sind extrem selten...', 0), +(2748, 'deDE', 'Ein gutes Ei ist ein Ei, aus dem idealerweise ein Jungtier schlüpft, das frei von den bösen Auswirkungen der Beschwörungen der Oger der Gordunni ist.', 0), +(2749, 'deDE', 'Normalerweise schlüpft etwa aus jedem zweiten Hippogryphen-Ei auch ein Jungtier. Wir hegen und pflegen die Eier nach besten Kräften, und wenn wir Glück haben, dann schlüpft am Ende etwas da raus.', 0), +(2750, 'deDE', 'Diese Eier können nicht gerettet werden - aus ihnen wird niemals etwas schlüpfen.', 0), +(2767, 'deDE', 'Ja, ich bin Glotz Widrikus, Meistererfinder zu Euren Diensten! Gibt es etwas, bei dem ich Euch helfen kann?', 0), +(2768, 'deDE', 'Habt Ihr Unteroffizier Bly gefunden? Habt Ihr meine Wünschel-mato-Rute bekommen?', 0), +(2843, 'deDE', 'Fertig!', 0), +(2863, 'deDE', 'Die Zeit drängt, $N! Solltet Ihr nicht hier sein, um zu berichten, dass Ihr die Alphas ausgeschaltet habt, dann vergeudet Ihr Zeit!', 0), +(2871, 'deDE', 'Ja, kann ich Euch helfen?$B$BMoment, Ihr seid doch $Gder:die; $C, $Gder:die; General Mondfeder und Latro mit der Bedrohung durch die Naga geholfen hat, nicht? Ich bin Vestia, Latros - ähm, natürlich Latronicus’ Frau. Es ist mir eine Freude, Eure Bekanntschaft zu machen!$B$BDoch entschuldigt, Ihr seid sicher geschäftlich hier. Habt Ihr etwas für mich - von ihm vielleicht?', 0), +(2877, 'deDE', 'Versucht nicht, über den vorliegenden Auftrag zu verhandeln, $R! Wenn die Götter diese Schlämme hätten tot sehen wollen, hätten sie das bereits durch ein Wunder erledigt, oder nicht?!', 0), +(2880, 'deDE', 'Ich will 5 von den Stammeshalsketten, die die Trolle tragen. Wenn Ihr es noch deutlicher erklärt haben wollt: Einen zu töten gibt Euch eine gute Chance, eine davon zu erhalten.$B$BBeweist den Wildhämmern Euren Wert!', 0), +(2881, 'deDE', 'Ihr habt das zwar bereits erledigt, aber wir nehmen weiterhin alle Trollstammeshalsketten an, die Ihr findet und eintauschen wollt. Indem Ihr sie bei mir eintauscht, verbessert Ihr weiter Eure Stellung unter den Wildhämmern. Wenn Ihr für uns kämpft, dann kämpfen wir auch für Euch!$B$BIch benötige 5 Trollstammeshalsketten, damit ich es gelten lassen kann, $N.', 0), +(2904, 'deDE', 'Eh? Kernobee lebt??', 0), +(2930, 'deDE', 'Habt Ihr die Prismalochkarte?', 0), +(2933, 'deDE', 'Hallo, $Gedler:edle; $C. Der Tag war lang und nicht ein einziges Experiment ist geglückt... Ich hoffe, Ihr bringt mir gute Neuigkeiten.', 0), +(2936, 'deDE', 'Kennt Ihr den Namen des Spinnengottes?', 0), +(2975, 'deDE', 'Beeilt Euch, $N. Oder ist die von mir verlangte Aufgabe zu schwierig?', 0), +(2980, 'deDE', 'Habt Ihr die Ruinen gefunden, $N?', 0), +(2982, 'deDE', 'Seid wachsam in der Nähe der Gordunni, $N. Ihre Magie scheint das Land, auf dem sie stehen, zu verderben.', 0), +(2995, 'deDE', 'Der Schlüssel ist, die Hochtalelfen zu isolieren. Habt Ihr die Hütte gefunden?', 0); diff --git a/data/sql/updates/db_world/2023_08_11_00.sql b/data/sql/updates/db_world/2023_08_11_00.sql new file mode 100644 index 000000000..7f09d705c --- /dev/null +++ b/data/sql/updates/db_world/2023_08_11_00.sql @@ -0,0 +1,9 @@ +-- DB update 2023_08_10_02 -> 2023_08_11_00 +-- +DELETE FROM `acore_string` WHERE `entry` IN (600,601); +INSERT INTO `acore_string` (`entry`, `content_default`) VALUES +(600,'Event %u (%s) is started'), +(601,'Event %u (%s) is stopped'); + +UPDATE `acore_string` SET `content_default` = 'Event %u (%s) is already active!', `locale_deDE` = 'Event %u (%s) bereits aktiv!', `locale_zhCN` = '事件 %u (%s) 已经激活了。' WHERE `entry` = 587; +UPDATE `acore_string` SET `content_default` = 'Event %u (%s) is not active!', `locale_deDE` = 'Event %u (%s) nicht aktiv!', `locale_zhCN` = '事件 %u (%s) 没有被激活。' WHERE `entry` = 588; diff --git a/data/sql/updates/db_world/2023_08_11_01.sql b/data/sql/updates/db_world/2023_08_11_01.sql new file mode 100644 index 000000000..c54e9e582 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_11_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_11_00 -> 2023_08_11_01 +-- +UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = 20 WHERE `creature_id` = 9816; diff --git a/data/sql/updates/db_world/2023_08_11_02.sql b/data/sql/updates/db_world/2023_08_11_02.sql new file mode 100644 index 000000000..0fe48cf41 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_11_02.sql @@ -0,0 +1,9 @@ +-- DB update 2023_08_11_01 -> 2023_08_11_02 + -- Infected Wildkin smart ai +SET @ENTRY := 17322; +DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryOrGuid` = @ENTRY; +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = @ENTRY; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 0, 0, 0, 0, 100, 0, 10000, 15000, 0, 0, 11, 31282, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Infected Wildkin - In Combat - Cast \'Infected Wound\''); + + diff --git a/data/sql/updates/db_world/2023_08_11_03.sql b/data/sql/updates/db_world/2023_08_11_03.sql new file mode 100644 index 000000000..31563fd07 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_11_03.sql @@ -0,0 +1,10 @@ +-- DB update 2023_08_11_02 -> 2023_08_11_03 +-- +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_inoculate_nestlewood_owlkin'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(29528, 'spell_inoculate_nestlewood_owlkin'); + +UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 16518; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 16518); +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1651800) AND (`source_type` = 9) AND (`id` IN (0, 1, 2, 3, 4, 5, 6, 7, 8)); diff --git a/data/sql/updates/db_world/2023_08_12_00.sql b/data/sql/updates/db_world/2023_08_12_00.sql new file mode 100644 index 000000000..f3668e6db --- /dev/null +++ b/data/sql/updates/db_world/2023_08_12_00.sql @@ -0,0 +1,10 @@ +-- DB update 2023_08_11_03 -> 2023_08_12_00 + -- Wrathscale Sorceress smart ai +SET @ENTRY := 17336; +DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryOrGuid` = @ENTRY; +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = @ENTRY; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(@ENTRY, 0, 0, 0, 0, 0, 100, 0, 3500, 12000, 3500, 12000, 11, 9672, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Wrathscale Sorceress - In Combat - Cast \'Frostbolt\''); + + + diff --git a/data/sql/updates/db_world/2023_08_12_01.sql b/data/sql/updates/db_world/2023_08_12_01.sql new file mode 100644 index 000000000..a239f401a --- /dev/null +++ b/data/sql/updates/db_world/2023_08_12_01.sql @@ -0,0 +1,10 @@ +-- DB update 2023_08_12_00 -> 2023_08_12_01 +-- +ALTER TABLE `gossip_menu` + CHANGE COLUMN `MenuID` `MenuID` INT UNSIGNED NOT NULL DEFAULT 0 FIRST; + +ALTER TABLE `gossip_menu_option` + CHANGE COLUMN `MenuID` `MenuID` INT UNSIGNED NOT NULL DEFAULT 0 FIRST; + +ALTER TABLE `gossip_menu_option_locale` + CHANGE COLUMN `MenuID` `MenuID` INT UNSIGNED NOT NULL DEFAULT 0 FIRST; diff --git a/data/sql/updates/db_world/2023_08_12_02.sql b/data/sql/updates/db_world/2023_08_12_02.sql new file mode 100644 index 000000000..1bddd487d --- /dev/null +++ b/data/sql/updates/db_world/2023_08_12_02.sql @@ -0,0 +1,10 @@ +-- DB update 2023_08_12_01 -> 2023_08_12_02 +-- +ALTER TABLE `smart_scripts` + ADD COLUMN `event_param6` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `event_param5`; + +UPDATE `smart_scripts` SET `event_param6` = `event_param5` WHERE `event_type` = 106 AND `source_type` = 0; +UPDATE `smart_scripts` SET `event_param5` = 0 WHERE `event_type` = 106 AND `source_type` = 0; + +UPDATE `smart_scripts` SET `event_param6` = `event_param5` WHERE `event_type` = 105 AND `source_type` = 0; +UPDATE `smart_scripts` SET `event_param5` = 0 WHERE `event_type` = 105 AND `source_type` = 0; diff --git a/data/sql/updates/db_world/2023_08_13_00.sql b/data/sql/updates/db_world/2023_08_13_00.sql new file mode 100644 index 000000000..bb10eb693 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_13_00.sql @@ -0,0 +1,42 @@ +-- DB update 2023_08_12_02 -> 2023_08_13_00 +-- +DELETE FROM `event_scripts` WHERE `id` = 14376; + +UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 185220; +DELETE FROM `smart_scripts` WHERE (`source_type` = 1 AND `entryorguid` = 185220); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(185220, 1, 0, 0, 70, 0, 100, 0, 2, 0, 0, 0, 0, 107, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Massive Treasure Chest - On Gameobject State Changed - Summon Creature Group'); + +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 1) AND (`SourceEntry` = 185220); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(22, 1, 185220, 1, 0, 29, 1, 22369, 100, 0, 1, 0, 0, '', 'Only Spawn Dread Relic Thrall (22369) if none are nearby already'); + +DELETE FROM `creature_summon_groups` WHERE `summonerId` = 185220; +INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `summonType`, `summonTime`, `Comment`, `position_x`, `position_y`, `position_z`, `orientation`) VALUES +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3750.57, 4737.88, -19.35, 4.01853), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3744.9, 4736.18, -18.717, 2.8797), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3773.46, 4720.45, -21.5752, 1.44792), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3773.85, 4715.78, -21.6975, 1.45735), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3774.08, 4710.46, -21.7888, 0.492878), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3774.95, 4704.25, -21.977, 0), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3772.26, 4699.55, -21.3722, 0.111175), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3769.89, 4694.89, -20.7665, 0.406484), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3767.46, 4691.24, -20.1502, 6.20901), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3763.69, 4688.06, -19.2893, 0.613044), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3760.22, 4685.72, -18.5906, 0.334227), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3756.1, 4683.74, -17.9125, 0.734772), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3751.6, 4682.35, -17.3406, 1.57044), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3746.76, 4682.73, -16.8866, 1.93172), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3742.75, 4684.69, -16.6026, 1.98513), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3739.15, 4687.17, -16.4299, 1.88145), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3736.77, 4689.91, -16.3146, 2.49721), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3733.74, 4693.02, -16.24, 2.487), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3764.99, 4733.9, -20.6666, 5.65487), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3770.51, 4728.37, -21.0502, 0), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3767.97, 4731.29, -20.9252, 4.03171), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3772.36, 4724.78, -21.3002, 5.81195), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3731.43, 4697.39, -16.1774, 2.74225), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3729.91, 4701.97, -16.1335, 3.04384), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3729.4, 4706.81, -16.1222, 3.61561), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3760.43, 4736.39, -20.2451, 4.01068), +(185220, 1, 1, 22369, 4, 300000, 'Massive Chest - Quest: The Dread Relic', -3755.66, 4737.93, -19.8168, 4.3861); diff --git a/data/sql/updates/db_world/2023_08_13_01.sql b/data/sql/updates/db_world/2023_08_13_01.sql new file mode 100644 index 000000000..f826f02f7 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_13_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_13_00 -> 2023_08_13_01 +-- +UPDATE `conditions` SET `ConditionValue2` = 1, `Comment` = 'Require incendiary bombs placed' WHERE `SourceTypeOrReferenceId` = 15 AND `SourceGroup` = 7499 AND `SourceEntry` = 0 AND `SourceId` = 0 AND `ElseGroup` = 0 AND `ConditionTypeOrReference` = 13 AND `ConditionTarget` = 0 AND `ConditionValue1` = 0 AND `ConditionValue2` = 2 AND `ConditionValue3` = 0; diff --git a/data/sql/updates/db_world/2023_08_13_02.sql b/data/sql/updates/db_world/2023_08_13_02.sql new file mode 100644 index 000000000..b9f5fabf2 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_13_02.sql @@ -0,0 +1,4 @@ +-- DB update 2023_08_13_01 -> 2023_08_13_02 +-- +DELETE FROM `creature` WHERE `id1` IN (16179, 16180, 16181); +DELETE FROM `linked_respawn` WHERE `guid` = 135369; diff --git a/data/sql/updates/db_world/2023_08_13_03.sql b/data/sql/updates/db_world/2023_08_13_03.sql new file mode 100644 index 000000000..b71d9f085 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_13_03.sql @@ -0,0 +1,250 @@ +-- DB update 2023_08_13_02 -> 2023_08_13_03 +-- +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|1|2|4|16|64|256|512|1024|2048|4096|8192|131072|8388608|33554432 WHERE `entry` = 16504; +UPDATE `creature_template_addon` SET `auras` = '18950 19818' WHERE (`entry` = 16504); + +DELETE FROM `creature` WHERE (`id1` = 16504); +INSERT INTO `creature` (`guid`, `id1`, `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`, `VerifiedBuild`) VALUES +(135684, 16504, 532, 3457, 3457, 1, 1, 0, -11260.5087890625, -1879.0595703125, 135.9311676025390625, 1.909694314002990722, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135685, 16504, 532, 3457, 3457, 1, 1, 0, -11232.4775390625, -1829.6251220703125, 136.011383056640625, 0.858925580978393554, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135686, 16504, 532, 3457, 3457, 1, 1, 0, -11207.046875, -1795.9210205078125, 136.011383056640625, 3.821264982223510742, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135687, 16504, 532, 3457, 3457, 1, 1, 0, -11255.5576171875, -1808.8509521484375, 135.700286865234375, 1.39106762409210205, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135688, 16504, 532, 3457, 3457, 1, 1, 0, -11224.5009765625, -1775.4560546875, 135.8892059326171875, 5.352929115295410156, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135689, 16504, 532, 3457, 3457, 1, 1, 0, -11280.7724609375, -1806.5499267578125, 148.2413482666015625, 1.098113179206848144, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135690, 16504, 532, 3457, 3457, 1, 1, 0, -11246.9052734375, -1766.41943359375, 135.744354248046875, 5.099393844604492187, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890), +(135691, 16504, 532, 3457, 3457, 1, 1, 0, -11356.568359375, -1859.6551513671875, 172.0524139404296875, 0.652408897876739501, 604800, 0, 0, 24394, 0, 1, 0, 0, 0, 49890); + +DELETE FROM `creature_addon` WHERE (`guid` IN (135684, 135685, 135686, 135687, 135688, 135689, 135690, 135691)); +INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES +(135684, 1356840, 0, 0, 1, 0, 0, '18950 19818'), +(135685, 1356850, 0, 0, 1, 0, 0, '18950 19818'), +(135686, 1356860, 0, 0, 1, 0, 0, '18950 19818'), +(135687, 1356870, 0, 0, 1, 0, 0, '18950 19818'), +(135688, 1356880, 0, 0, 1, 0, 0, '18950 19818'), +(135689, 1356890, 0, 0, 1, 0, 0, '18950 19818'), +(135690, 1356890, 0, 0, 1, 0, 0, '18950 19818'), +(135691, 1356891, 0, 0, 1, 0, 0, '18950 19818'); + + + +-- Pathing for Entry: 16504 +SET @NPC := 135684; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11282.719,`position_y`=-1747.2125,`position_z`=135.91495 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11282.719,-1747.2125,135.91495,NULL,0,0,0,100,0), +(@PATH,2,-11278.085,-1756.3627,135.8214,NULL,0,0,0,100,0), +(@PATH,3,-11275.22,-1766.3102,135.6382,NULL,0,0,0,100,0), +(@PATH,4,-11274.691,-1776.3484,137.43626,NULL,0,0,0,100,0), +(@PATH,5,-11275.114,-1787.6228,141.67157,NULL,0,0,0,100,0), +(@PATH,6,-11278.173,-1801.4655,146.54819,NULL,0,0,0,100,0), +(@PATH,7,-11283.93,-1812.7236,149.86386,NULL,0,0,0,100,0), +(@PATH,8,-11295.427,-1825.6823,154.9022,NULL,0,0,0,100,0), +(@PATH,9,-11307.174,-1836.3917,159.4869,NULL,0,0,0,100,0), +(@PATH,10,-11315.685,-1843.8234,162.48993,NULL,0,0,0,100,0), +(@PATH,11,-11324.192,-1851.0717,165.1561,NULL,0,0,0,100,0), +(@PATH,12,-11334.766,-1860.4056,167.11708,NULL,0,0,0,100,0), +(@PATH,13,-11344.708,-1869.108,169.00255,NULL,0,0,0,100,0), +(@PATH,14,-11334.766,-1860.4056,167.11708,NULL,0,0,0,100,0), +(@PATH,15,-11324.192,-1851.0717,165.1561,NULL,0,0,0,100,0), +(@PATH,16,-11315.685,-1843.8234,162.48993,NULL,0,0,0,100,0), +(@PATH,17,-11307.174,-1836.3917,159.4869,NULL,0,0,0,100,0), +(@PATH,18,-11295.427,-1825.6823,154.9022,NULL,0,0,0,100,0), +(@PATH,19,-11283.93,-1812.7236,149.86386,NULL,0,0,0,100,0), +(@PATH,20,-11278.173,-1801.4655,146.54819,NULL,0,0,0,100,0), +(@PATH,21,-11275.114,-1787.6228,141.67157,NULL,0,0,0,100,0), +(@PATH,22,-11274.691,-1776.3484,137.43626,NULL,0,0,0,100,0), +(@PATH,23,-11275.22,-1766.3102,135.6382,NULL,0,0,0,100,0), +(@PATH,24,-11278.085,-1756.3627,135.8214,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135685; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11244.635,`position_y`=-1861.6107,`position_z`=136.00499 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11244.635,-1861.6107,136.00499,NULL,0,0,0,100,0), +(@PATH,2,-11243.633,-1849.3298,136.01608,NULL,0,0,0,100,0), +(@PATH,3,-11240.205,-1838.5823,136.01138,NULL,0,0,0,100,0), +(@PATH,4,-11232.055,-1829.1354,136.01138,NULL,0,0,0,100,0), +(@PATH,5,-11222.885,-1823.4156,136.01138,NULL,0,0,0,100,0), +(@PATH,6,-11214.087,-1820.8082,136.01137,NULL,0,0,0,100,0), +(@PATH,7,-11200.884,-1822.6813,136.01137,NULL,0,0,0,100,0), +(@PATH,8,-11190.939,-1827.63,136.01114,NULL,0,0,0,100,0), +(@PATH,9,-11181.966,-1835.762,136.01112,NULL,0,0,0,100,0), +(@PATH,10,-11173.904,-1843.7567,136.01112,NULL,0,0,0,100,0), +(@PATH,11,-11181.966,-1835.762,136.01112,NULL,0,0,0,100,0), +(@PATH,12,-11190.939,-1827.63,136.01114,NULL,0,0,0,100,0), +(@PATH,13,-11200.884,-1822.6813,136.01137,NULL,0,0,0,100,0), +(@PATH,14,-11214.087,-1820.8082,136.01137,NULL,0,0,0,100,0), +(@PATH,15,-11222.885,-1823.4156,136.01138,NULL,0,0,0,100,0), +(@PATH,16,-11232.055,-1829.1354,136.01138,NULL,0,0,0,100,0), +(@PATH,17,-11240.205,-1838.5823,136.01138,NULL,0,0,0,100,0), +(@PATH,18,-11243.633,-1849.3298,136.01608,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135686; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11179.357,`position_y`=-1819.6996,`position_z`=136.01114 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11179.357,-1819.6996,136.01114,NULL,0,0,0,100,0), +(@PATH,2,-11184.585,-1812.9401,136.01114,NULL,0,0,0,100,0), +(@PATH,3,-11191.397,-1804.2574,136.01115,NULL,0,0,0,100,0), +(@PATH,4,-11196.627,-1797.484,136.01112,NULL,0,0,0,100,0), +(@PATH,5,-11201.327,-1791.2985,136.01138,NULL,0,0,0,100,0), +(@PATH,6,-11207.811,-1796.5381,136.0114,NULL,0,0,0,100,0), +(@PATH,7,-11213.821,-1801.6233,136.01138,NULL,0,0,0,100,0), +(@PATH,8,-11220.307,-1807.0294,136.01138,NULL,0,0,0,100,0), +(@PATH,9,-11227.366,-1813.0164,136.01138,NULL,0,0,0,100,0), +(@PATH,10,-11235.879,-1820.589,136.01138,NULL,0,0,0,100,0), +(@PATH,11,-11243.814,-1827.6565,136.01138,NULL,0,0,0,100,0), +(@PATH,12,-11250.698,-1833.699,135.97995,NULL,0,0,0,100,0), +(@PATH,13,-11243.877,-1827.712,136.0166,NULL,0,0,0,100,0), +(@PATH,14,-11235.879,-1820.589,136.01138,NULL,0,0,0,100,0), +(@PATH,15,-11227.366,-1813.0164,136.01138,NULL,0,0,0,100,0), +(@PATH,16,-11220.307,-1807.0294,136.01138,NULL,0,0,0,100,0), +(@PATH,17,-11213.821,-1801.6233,136.01138,NULL,0,0,0,100,0), +(@PATH,18,-11207.811,-1796.5381,136.0114,NULL,0,0,0,100,0), +(@PATH,19,-11201.327,-1791.2985,136.01138,NULL,0,0,0,100,0), +(@PATH,20,-11196.627,-1797.484,136.01112,NULL,0,0,0,100,0), +(@PATH,21,-11191.397,-1804.2574,136.01115,NULL,0,0,0,100,0), +(@PATH,22,-11184.585,-1812.9401,136.01114,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135687; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11254.315,`position_y`=-1802.0162,`position_z`=135.67534 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11254.315,-1802.0162,135.67534,NULL,0,0,0,100,0), +(@PATH,2,-11255.973,-1811.1375,135.70863,NULL,0,0,0,100,0), +(@PATH,3,-11259.613,-1821.1395,135.7157,NULL,0,0,0,100,0), +(@PATH,4,-11266.448,-1833.0944,135.74219,NULL,0,0,0,100,0), +(@PATH,5,-11273.001,-1840.8385,135.65984,NULL,0,0,0,100,0), +(@PATH,6,-11269.364,-1844.9835,135.70094,NULL,0,0,0,100,0), +(@PATH,7,-11265.347,-1850.7305,135.75291,NULL,0,0,0,100,0), +(@PATH,8,-11260.148,-1858.1432,135.82002,NULL,0,0,0,100,0), +(@PATH,9,-11261.842,-1866.3837,135.85799,NULL,0,0,0,100,0), +(@PATH,10,-11269.297,-1871.5432,135.94835,NULL,0,0,0,100,0), +(@PATH,11,-11261.842,-1866.3837,135.85799,NULL,0,0,0,100,0), +(@PATH,12,-11260.148,-1858.1432,135.82002,NULL,0,0,0,100,0), +(@PATH,13,-11265.347,-1850.7305,135.75291,NULL,0,0,0,100,0), +(@PATH,14,-11269.364,-1844.9835,135.70094,NULL,0,0,0,100,0), +(@PATH,15,-11273.001,-1840.8385,135.65984,NULL,0,0,0,100,0), +(@PATH,16,-11266.448,-1833.0944,135.74219,NULL,0,0,0,100,0), +(@PATH,17,-11259.613,-1821.1395,135.7157,NULL,0,0,0,100,0), +(@PATH,18,-11255.973,-1811.1375,135.70863,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135688; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11213.536,`position_y`=-1889.4314,`position_z`=152.04805 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11213.536,-1889.4314,152.04805,NULL,0,0,0,100,0), +(@PATH,2,-11226.246,-1898.772,147.91463,NULL,0,0,0,100,0), +(@PATH,3,-11234.652,-1902.2678,144.80687,NULL,0,0,0,100,0), +(@PATH,4,-11242.376,-1901.0875,142.21738,NULL,0,0,0,100,0), +(@PATH,5,-11250.143,-1895.2155,139.11664,NULL,0,0,0,100,0), +(@PATH,6,-11257.955,-1886.3018,135.98216,NULL,0,0,0,100,0), +(@PATH,7,-11260.844,-1878.108,135.92447,NULL,0,0,0,100,0), +(@PATH,8,-11255.884,-1871.2458,135.91449,NULL,0,0,0,100,0), +(@PATH,9,-11248.533,-1868.3633,135.99532,NULL,0,0,0,100,0), +(@PATH,10,-11242.855,-1871.226,135.99905,NULL,0,0,0,100,0), +(@PATH,11,-11255.884,-1871.2458,135.91449,NULL,0,0,0,100,0), +(@PATH,12,-11260.844,-1878.108,135.92447,NULL,0,0,0,100,0), +(@PATH,13,-11258.019,-1886.2291,135.98065,NULL,0,0,0,100,0), +(@PATH,14,-11250.143,-1895.2155,139.11664,NULL,0,0,0,100,0), +(@PATH,15,-11242.376,-1901.0875,142.21738,NULL,0,0,0,100,0), +(@PATH,16,-11234.652,-1902.2678,144.80687,NULL,0,0,0,100,0), +(@PATH,17,-11226.246,-1898.772,147.91463,NULL,0,0,0,100,0), +(@PATH,18,-11218.449,-1893.0543,151.34467,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135689; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11244.246,`position_y`=-1781.3795,`position_z`=135.7957 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11244.246,-1781.3795,135.7957,NULL,0,0,0,100,0), +(@PATH,2,-11244.443,-1772.4609,135.75342,NULL,0,0,0,100,0), +(@PATH,3,-11248.54,-1762.4084,135.76776,NULL,0,0,0,100,0), +(@PATH,4,-11254.743,-1754.2867,135.89478,NULL,0,0,0,100,0), +(@PATH,5,-11262.073,-1745.61,135.93542,NULL,0,0,0,100,0), +(@PATH,6,-11269.613,-1736.4952,136.00697,NULL,0,0,0,100,0), +(@PATH,7,-11277.36,-1727.5326,136.01083,NULL,0,0,0,100,0), +(@PATH,8,-11284.054,-1733.3395,136.01456,NULL,0,0,0,100,0), +(@PATH,9,-11290.676,-1739.1726,136.01823,NULL,0,0,0,100,0), +(@PATH,10,-11284.054,-1733.3395,136.01456,NULL,0,0,0,100,0), +(@PATH,11,-11277.36,-1727.5326,136.01083,NULL,0,0,0,100,0), +(@PATH,12,-11269.613,-1736.4952,136.00697,NULL,0,0,0,100,0), +(@PATH,13,-11262.073,-1745.61,135.93542,NULL,0,0,0,100,0), +(@PATH,14,-11254.743,-1754.2867,135.89478,NULL,0,0,0,100,0), +(@PATH,15,-11248.54,-1762.4084,135.76776,NULL,0,0,0,100,0), +(@PATH,16,-11244.443,-1772.4609,135.75342,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135690; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11346.433,`position_y`=-1851.5946,`position_z`=170.19037 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11346.433,-1851.5946,170.19037,NULL,0,0,0,100,0), +(@PATH,2,-11353.817,-1857.5533,171.80334,NULL,0,0,0,100,0), +(@PATH,3,-11360.403,-1862.5851,172.39963,NULL,0,0,0,100,0), +(@PATH,4,-11366.273,-1855.2086,173.61658,NULL,0,0,0,100,0), +(@PATH,5,-11372.065,-1847.9648,175.13911,NULL,0,0,0,100,0), +(@PATH,6,-11378.154,-1839.9221,177.20697,NULL,0,0,0,100,0), +(@PATH,7,-11384.107,-1832.3479,179.37885,NULL,0,0,0,100,0), +(@PATH,8,-11389.809,-1824.9479,179.73013,NULL,0,0,0,100,0), +(@PATH,9,-11395.728,-1817.1012,179.73013,NULL,0,0,0,100,0), +(@PATH,10,-11389.809,-1824.9479,179.73013,NULL,0,0,0,100,0), +(@PATH,11,-11384.107,-1832.3479,179.37885,NULL,0,0,0,100,0), +(@PATH,12,-11378.154,-1839.9221,177.20697,NULL,0,0,0,100,0), +(@PATH,13,-11372.065,-1847.9648,175.13911,NULL,0,0,0,100,0), +(@PATH,14,-11366.273,-1855.2086,173.61658,NULL,0,0,0,100,0), +(@PATH,15,-11360.403,-1862.5851,172.39963,NULL,0,0,0,100,0), +(@PATH,16,-11353.817,-1857.5533,171.80334,NULL,0,0,0,100,0); + +-- Pathing for Entry: 16504 +SET @NPC := 135691; +SET @PATH := @NPC * 10; +UPDATE `creature` SET `wander_distance`=0,`MovementType`=2,`position_x`=-11244.46,`position_y`=-1804.8809,`position_z`=135.81401 WHERE `guid`=@NPC; +DELETE FROM `creature_addon` WHERE `guid`=@NPC; +INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`visibilityDistanceType`,`auras`) VALUES (@NPC,@PATH,0,0,1,0,0, ''); +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES +(@PATH,1,-11244.46,-1804.8809,135.81401,NULL,0,0,0,100,0), +(@PATH,2,-11236.382,-1798.8492,135.89545,NULL,0,0,0,100,0), +(@PATH,3,-11227.848,-1792.5315,135.9404,NULL,0,0,0,100,0), +(@PATH,4,-11217.406,-1784.903,135.9538,NULL,0,0,0,100,0), +(@PATH,5,-11221.928,-1778.9088,135.90015,NULL,0,0,0,100,0), +(@PATH,6,-11228.954,-1769.4824,135.9033,NULL,0,0,0,100,0), +(@PATH,7,-11235.162,-1761.6926,135.9174,NULL,0,0,0,100,0), +(@PATH,8,-11228.104,-1756.5549,135.97401,NULL,0,0,0,100,0), +(@PATH,9,-11217.438,-1749.0182,135.99788,NULL,0,0,0,100,0), +(@PATH,10,-11207.726,-1741.2073,136.01138,NULL,0,0,0,100,0), +(@PATH,11,-11217.438,-1749.0182,135.99788,NULL,0,0,0,100,0), +(@PATH,12,-11228.104,-1756.5549,135.97401,NULL,0,0,0,100,0), +(@PATH,13,-11235.162,-1761.6926,135.9174,NULL,0,0,0,100,0), +(@PATH,14,-11228.954,-1769.4824,135.9033,NULL,0,0,0,100,0), +(@PATH,15,-11221.928,-1778.9088,135.90015,NULL,0,0,0,100,0), +(@PATH,16,-11217.406,-1784.903,135.9538,NULL,0,0,0,100,0), +(@PATH,17,-11227.848,-1792.5315,135.9404,NULL,0,0,0,100,0), +(@PATH,18,-11236.382,-1798.8492,135.89545,NULL,0,0,0,100,0); diff --git a/data/sql/updates/db_world/2023_08_14_00.sql b/data/sql/updates/db_world/2023_08_14_00.sql new file mode 100644 index 000000000..edbecb235 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_14_00.sql @@ -0,0 +1,2 @@ +-- DB update 2023_08_13_03 -> 2023_08_14_00 +UPDATE `creature_template` SET `flags_extra` = 67108864 WHERE (`entry` = 10438); diff --git a/data/sql/updates/db_world/2023_08_14_01.sql b/data/sql/updates/db_world/2023_08_14_01.sql new file mode 100644 index 000000000..38acf2a93 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_14_01.sql @@ -0,0 +1,4 @@ +-- DB update 2023_08_14_00 -> 2023_08_14_01 +-- +UPDATE `smart_scripts` SET `action_param1` = 16098 WHERE `entryorguid` = 10503 AND `source_type` = 0 AND `id` = 0 AND `link` = 0; +UPDATE `smart_scripts` SET `action_param1` = 8994 WHERE `entryorguid` = 10503 AND `source_type` = 0 AND `id` = 1 AND `link` = 0; diff --git a/data/sql/updates/db_world/2023_08_14_02.sql b/data/sql/updates/db_world/2023_08_14_02.sql new file mode 100644 index 000000000..8e5d16697 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_14_02.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_14_01 -> 2023_08_14_02 +-- +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|256|8388608 WHERE `entry` = 18829; diff --git a/data/sql/updates/db_world/2023_08_14_03.sql b/data/sql/updates/db_world/2023_08_14_03.sql new file mode 100644 index 000000000..195d7defa --- /dev/null +++ b/data/sql/updates/db_world/2023_08_14_03.sql @@ -0,0 +1,41 @@ +-- DB update 2023_08_14_02 -> 2023_08_14_03 +-- +DELETE FROM `creature_formations` WHERE `leaderguid` IN (135229, 135217, 135233, 135206); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(135229, 135229, 0, 0, 3, 0, 0), +(135229, 135222, 0, 0, 3, 0, 0), +(135229, 135226, 0, 0, 3, 0, 0), +(135229, 135225, 0, 0, 3, 0, 0), +(135229, 135224, 0, 0, 3, 0, 0), +(135229, 135228, 0, 0, 3, 0, 0), +(135229, 135221, 0, 0, 3, 0, 0), +(135229, 135223, 0, 0, 3, 0, 0), + +(135217, 135217, 0, 0, 3, 0, 0), +(135217, 135215, 0, 0, 3, 0, 0), +(135217, 135218, 0, 0, 3, 0, 0), +(135217, 135219, 0, 0, 3, 0, 0), +(135217, 135216, 0, 0, 3, 0, 0), +(135217, 135212, 0, 0, 3, 0, 0), +(135217, 135213, 0, 0, 3, 0, 0), +(135217, 135214, 0, 0, 3, 0, 0), +(135217, 135220, 0, 0, 3, 0, 0), + +(135233, 135233, 0, 0, 3, 0, 0), +(135233, 135232, 0, 0, 3, 0, 0), +(135233, 135231, 0, 0, 3, 0, 0), +(135233, 135234, 0, 0, 3, 0, 0), +(135233, 135238, 0, 0, 3, 0, 0), +(135233, 135237, 0, 0, 3, 0, 0), +(135233, 135236, 0, 0, 3, 0, 0), +(135233, 135235, 0, 0, 3, 0, 0), + +(135206, 135206, 0, 0, 3, 0, 0), +(135206, 135211, 0, 0, 3, 0, 0), +(135206, 135205, 0, 0, 3, 0, 0), +(135206, 135209, 0, 0, 3, 0, 0), +(135206, 135210, 0, 0, 3, 0, 0), +(135206, 135204, 0, 0, 3, 0, 0), +(135206, 135207, 0, 0, 3, 0, 0), +(135206, 135203, 0, 0, 3, 0, 0), +(135206, 135208, 0, 0, 3, 0, 0); diff --git a/data/sql/updates/db_world/2023_08_14_04.sql b/data/sql/updates/db_world/2023_08_14_04.sql new file mode 100644 index 000000000..7b1e6baf6 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_14_04.sql @@ -0,0 +1,2 @@ +-- DB update 2023_08_14_03 -> 2023_08_14_04 +UPDATE `creature_template` SET `flags_extra` = `flags_extra`|2 WHERE `entry` IN (26582, 26583); diff --git a/data/sql/updates/db_world/2023_08_19_00.sql b/data/sql/updates/db_world/2023_08_19_00.sql new file mode 100644 index 000000000..a7a1841fc --- /dev/null +++ b/data/sql/updates/db_world/2023_08_19_00.sql @@ -0,0 +1,10 @@ +-- DB update 2023_08_14_04 -> 2023_08_19_00 +-- Vile Like Fire! (13071) +-- fix Njorndar Proto-Drake vehicle unable to fly +DELETE FROM `creature_template_spell` WHERE `CreatureID` = 30564; +INSERT INTO `creature_template_spell` (`CreatureID`, `Index`, `Spell`, `VerifiedBuild`) VALUES +(30564, 0, 57493, 12340), +(30564, 2, 7769, 12340), +(30564, 6, 57403, 12340); +-- fix Njorndar Proto-Drake display status on the ground +UPDATE `creature_template_movement` SET `Flight`=2 WHERE `CreatureId`=30272; diff --git a/data/sql/updates/db_world/2023_08_19_01.sql b/data/sql/updates/db_world/2023_08_19_01.sql new file mode 100644 index 000000000..a9aecf6f0 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_19_01.sql @@ -0,0 +1,9 @@ +-- DB update 2023_08_19_00 -> 2023_08_19_01 +-- +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_q10651_q10692_book_of_fel_names'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(36298, 'spell_q10651_q10692_book_of_fel_names'); + +DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 37906) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 1) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 21178) AND (`ConditionValue3` = 0); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17, 0, 37906, 0, 0, 31, 1, 3, 21178, 0, 0, 0, 0, '', 'Book of Fel Names can only target Varedis'); diff --git a/data/sql/updates/db_world/2023_08_19_02.sql b/data/sql/updates/db_world/2023_08_19_02.sql new file mode 100644 index 000000000..be94ea941 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_19_02.sql @@ -0,0 +1,106 @@ +-- DB update 2023_08_19_01 -> 2023_08_19_02 +-- +SET @GEVENT := 46; +SET @CGUID := 152340; + +DELETE FROM `game_event` WHERE `eventEntry` = @GEVENT; +INSERT INTO `game_event` (`eventEntry`, `start_time`, `end_time`, `occurence`, `length`, `holiday`, `holidayStage`, `description`, `world_event`, `announce`) VALUES +(@GEVENT, '2008-09-08 12:00:00', '2008-09-24 12:00:00', 1051897, 23040 , 0, 0, 'Spirit of Competition', 0, 2); + +UPDATE `creature_template` SET `gossip_menu_id` = 9517, `npcflag` = 1 WHERE `entry` = 27399; + +DELETE FROM `gossip_menu_option` WHERE `MenuID` = 9517 AND `OptionID` = 0; +INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`) VALUES +(9517, 0, 0, 'I would like to enter the secret code to receive my Competitor''s Souvenir.', 26513, 1, 1); + +DELETE FROM `creature` WHERE `id1` IN (27346, 27398, 27399); +INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES +(@CGUID, 27398, 0, 0, 0, 1537, 1537, 0, 1, 0, -5040.92, -1250.81, 507.76, 0.70, 300, 0, 0, 0, 0, 0, 0, 0, 0, '', 0), -- Grandhammer +(@CGUID+1, 27346, 0, 0, 0, 1537, 1537, 0, 1, 0, -5041.91, -1250.2, 507.76, 1.37, 300, 0, 0, 0, 0, 0, 0, 0, 0, '', 0), -- IF Dragon +(@CGUID+2, 27399, 0, 0, 1, 1637, 1637, 0, 1, 0, 1964.39, -4798.77, 56.99, 0.08, 300, 0, 0, 0, 0, 0, 0, 0, 0, '', 0), -- Muja +(@CGUID+3, 27346, 0, 0, 1, 1637, 1637, 0, 1, 0, 1963.26, -4797.62, 56.99, 0.72, 300, 0, 0, 0, 0, 0, 0, 0, 0, '', 0); -- Org Dragon +-- Positions based on screenshots. +DELETE FROM `game_event_creature` WHERE `eventEntry` = @GEVENT; +INSERT INTO `game_event_creature` (`eventEntry`, `guid`) VALUES +(@GEVENT, @CGUID), +(@GEVENT, @CGUID+1), +(@GEVENT, @CGUID+2), +(@GEVENT, @CGUID+3), + +-- Goblin Commoneers +(@GEVENT, 724), +(@GEVENT, 725), +(@GEVENT, 726), +(@GEVENT, 727), +(@GEVENT, 91115), +(@GEVENT, 91116), +(@GEVENT, 91117), +(@GEVENT, 91118), +(@GEVENT, 91579), +(@GEVENT, 91580), +(@GEVENT, 91752), +(@GEVENT, 91753), +(@GEVENT, 91754), +(@GEVENT, 91756), +(@GEVENT, 91757), +(@GEVENT, 91758), +(@GEVENT, 91759), +(@GEVENT, 91760), +(@GEVENT, 91761), +(@GEVENT, 91762), +(@GEVENT, 91766), +(@GEVENT, 91767), +(@GEVENT, 91768), +(@GEVENT, 91769), +(@GEVENT, 91770), +(@GEVENT, 91771), +(@GEVENT, 91801), +(@GEVENT, 240327), +(@GEVENT, 240328), +(@GEVENT, 240329), +(@GEVENT, 240330), +(@GEVENT, 240331), +(@GEVENT, 240332), +(@GEVENT, 240333), +(@GEVENT, 240334), +(@GEVENT, 240335), +(@GEVENT, 240336), +(@GEVENT, 240337), +(@GEVENT, 240338); + +DELETE FROM `creature_text` WHERE `CreatureID` = 20102 AND `GroupID` = 1; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `BroadcastTextId`) VALUES +(20102, 1, 1, 'The Spirits of Competition have grown strong again.', 12, 0, 100, 26564); + +DELETE FROM `smart_scripts` WHERE `entryorguid`=20102 AND `source_type`=0 AND `id`=1 AND `link`=0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(20102, 0, 1, 0, 1, 0, 100, 0, 3000, 15000, 45000, 90000, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Goblin Commoner - OOC - Say'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceGroup`=2 AND `SourceEntry`=20102 AND `SourceId`=0 AND `ElseGroup`=0 AND `ConditionTypeOrReference`=12 AND `ConditionTarget`=1 AND `ConditionValue1`=46 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, 2, 20102, 0, 0, 12, 1, 46, 0, 0, 0, 0, 0, '', 'Commoner - Spirit of Competition must be active'); + +DELETE FROM `gossip_menu` WHERE `MenuID` = 10248 AND `TextID` IN (12819); +DELETE FROM `gossip_menu` WHERE `MenuID` = 90000 AND `TextID` IN (12820); +DELETE FROM `gossip_menu` WHERE `MenuID` = 90001 AND `TextID` IN (12821); +INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES +(10248, 12819), +(90000, 12820), +(90001, 12821); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=10248 AND `SourceEntry`=12819 AND `ConditionTypeOrReference`=12 AND `ConditionTarget`=0 AND `ConditionValue1`=46; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=10248 AND `SourceEntry` IN (0,1) AND `ConditionTypeOrReference`=12 AND `ConditionValue1`=46; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(14, 10248, 12819, 0, 0, 12, 0, 46, 0, 0, 0, 0, 0, '', 'Show gossip text if event 46 is active'), +(15, 10248, 0, 0, 0, 12, 0, 46, 0, 0, 0, 0, 0, '', 'Show gossip option if event 46 is active'), +(15, 10248, 1, 0, 0, 12, 0, 46, 0, 0, 0, 0, 0, '', 'Show gossip option if event 46 is active'); + +DELETE FROM `gossip_menu_option` WHERE `MenuID` = 10248 AND `OptionID` IN (0,1); +INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`) VALUES +(10248, 0, 0, 'How do I earn a Competitor''s Tabard?', 26508, 1, 1, 90000), +(10248, 1, 0, 'How can I gain the favor of a Spirit of Competition?', 26509, 1, 1, 90001); + +DELETE FROM `spell_script_names` WHERE `spell_id` IN (48163,48164); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(48163,'spell_gen_spirit_of_competition_participant'), +(48164,'spell_gen_spirit_of_competition_winner'); diff --git a/data/sql/updates/db_world/2023_08_20_00.sql b/data/sql/updates/db_world/2023_08_20_00.sql new file mode 100644 index 000000000..0683917b0 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_20_00.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_19_02 -> 2023_08_20_00 +-- +UPDATE `conditions` SET `ConditionValue1` = 1, `ConditionValue1` = 3, `ConditionValue3` = 2, `Comment` = 'Require Lt. Drake encounter complete' WHERE `ConditionValue2` = 2 AND `SourceTypeOrReferenceId` = 14 AND `SourceGroup` = 7499 AND `SourceEntry` = 9090; diff --git a/data/sql/updates/db_world/2023_08_21_00.sql b/data/sql/updates/db_world/2023_08_21_00.sql new file mode 100644 index 000000000..f2fc4e23a --- /dev/null +++ b/data/sql/updates/db_world/2023_08_21_00.sql @@ -0,0 +1,489 @@ +-- DB update 2023_08_20_00 -> 2023_08_21_00 +DELETE FROM `pet_levelstats` WHERE `creature_entry` IN (416,1860,1863,417,17252,89); +INSERT INTO `pet_levelstats` (`creature_entry`,`level`,`hp`,`mana`,`armor`,`str`,`agi`,`sta`,`inte`,`spi`,`min_dmg`,`max_dmg`) VALUES +-- Imp +(416,1,34,10,22,20,20,20,25,23,0,1), +(416,2,43,48,21,21,20,20,26,24,1,2), +(416,3,56,57,32,22,20,21,27,25,2,4), +(416,4,68,66,57,23,21,21,29,26,3,6), +(416,5,80,76,87,23,21,22,30,27,4,8), +(416,6,92,85,122,24,21,22,31,28,6,10), +(416,7,105,95,166,25,21,23,32,29,7,12), +(416,8,119,105,216,26,21,23,33,30,8,13), +(416,9,134,115,275,27,21,23,35,32,9,14), +(416,10,149,126,342,27,22,24,36,33,9,15), +(416,11,167,151,362,28,22,24,39,35,10,16), +(416,12,184,177,384,29,22,26,44,38,11,17), +(416,13,202,198,405,30,22,26,47,40,11,18), +(416,14,220,234,429,31,22,28,56,45,12,19), +(416,15,239,260,451,32,23,29,61,48,12,20), +(416,16,257,282,475,34,23,30,64,50,13,21), +(416,17,277,309,498,36,23,31,68,53,14,23), +(416,18,297,336,519,37,23,32,72,55,15,24), +(416,19,318,368,543,38,23,33,76,58,17,26), +(416,20,340,396,565,40,24,35,81,61,17,27), +(416,21,362,419,588,42,24,35,84,64,18,28), +(416,22,389,447,612,44,24,37,89,67,19,30), +(416,23,415,476,633,45,24,37,92,69,20,31), +(416,24,444,509,657,46,25,39,97,73,20,31), +(416,25,471,538,679,47,25,40,101,75,21,33), +(416,26,502,563,701,49,25,41,105,78,21,34), +(416,27,532,597,725,50,25,43,110,81,23,35), +(416,28,562,652,747,52,25,43,121,86,23,36), +(416,29,591,682,770,54,26,45,126,89,23,37), +(416,30,618,717,792,54,26,46,131,92,25,39), +(416,31,646,743,814,56,26,47,134,95,26,40), +(416,32,674,779,838,57,26,49,139,98,27,41), +(416,33,701,810,860,59,27,49,143,101,27,42), +(416,34,728,842,883,60,27,51,147,104,27,43), +(416,35,757,884,904,62,27,52,152,107,28,44), +(416,36,785,911,972,63,28,53,156,110,29,45), +(416,37,814,943,1045,64,28,55,161,114,30,47), +(416,38,843,982,1118,66,28,55,165,116,31,48), +(416,39,873,1015,1196,68,28,57,170,120,32,49), +(416,40,904,1053,1277,70,29,59,174,123,33,51), +(416,41,932,1087,1363,72,29,59,178,126,35,54), +(416,42,970,1145,1454,77,29,61,190,131,37,57), +(416,43,1008,1180,1546,81,29,62,194,134,39,60), +(416,44,1047,1214,1646,88,30,63,199,138,42,65), +(416,45,1087,1254,1747,91,30,65,204,141,45,75), +(416,46,1127,1294,1782,93,30,66,208,144,46,70), +(416,47,1170,1330,1818,95,31,68,213,148,47,72), +(416,48,1212,1366,1851,97,31,68,218,151,48,73), +(416,49,1257,1412,1887,99,31,70,223,155,49,75), +(416,50,1302,1449,1920,101,32,72,228,158,51,77), +(416,51,1347,1487,1956,103,32,73,232,161,51,78), +(416,52,1394,1534,1991,105,32,74,237,165,52,80), +(416,53,1441,1572,2025,107,33,75,241,168,54,82), +(416,54,1489,1615,2060,109,33,77,247,172,54,83), +(416,55,1537,1654,2093,111,33,79,252,176,56,85), +(416,56,1587,1717,2131,114,34,80,265,181,57,87), +(416,57,1637,1762,2165,116,34,81,271,185,58,88), +(416,58,1688,1802,2198,117,34,82,275,188,69,105), +(416,59,1741,1847,2234,120,35,84,281,193,75,114), +(416,60,1793,1897,2427,122,35,86,286,196,109,165), +(416,61,1848,1938,2617,125,35,87,286,206,116,175), +(416,62,1903,1984,2807,126,35,89,286,212,124,187), +(416,63,1958,2031,2998,129,36,90,286,220,132,199), +(416,64,2014,2078,3188,131,36,92,287,226,139,211), +(416,65,2071,2125,3378,134,36,94,288,233,148,223), +(416,66,2131,2173,3569,135,37,94,297,239,156,236), +(416,67,2192,2226,3759,138,37,96,306,246,164,248), +(416,68,2255,2270,3949,140,37,97,312,251,192,290), +(416,69,2317,2319,4141,143,38,99,319,257,211,317), +(416,70,2381,2374,4330,145,38,101,327,263,228,343), +(416,71,2526,2419,4524,147,41,102,331,269,235,354), +(416,72,2666,2475,4717,150,44,104,335,275,242,364), +(416,73,2809,2526,4910,153,47,105,339,281,249,374), +(416,74,2955,2577,5104,168,51,107,343,333,256,385), +(416,75,3102,2634,5299,185,55,109,347,339,264,397), +(416,76,3250,2686,5492,203,59,110,351,344,271,408), +(416,77,3401,2743,5688,224,64,113,355,349,279,420), +(416,78,3553,2791,5881,246,68,114,360,355,287,432), +(416,79,3709,2850,6078,270,74,116,364,360,295,444), +(416,80,3867,2908,6273,297,79,118,369,367,305,458), +-- Voidwalker +(1860,1,1,1,1,1,1,1,1,1,1,1), +(1860,2,1,1,1,1,1,1,1,1,1,1), +(1860,3,1,1,1,1,1,1,1,1,1,1), +(1860,4,1,1,1,1,1,1,1,1,1,1), +(1860,5,1,1,1,1,1,1,1,1,1,1), +(1860,6,1,1,1,1,1,1,1,1,1,1), +(1860,7,1,1,1,1,1,1,1,1,1,1), +(1860,8,1,1,1,1,1,1,1,1,1,1), +(1860,9,1,1,1,1,1,1,1,1,1,1), +(1860,10,205,147,831,29,10,29,25,27,7,13), +(1860,11,229,158,875,30,10,32,26,28,8,14), +(1860,12,253,192,931,31,10,36,27,29,9,15), +(1860,13,278,203,987,32,11,40,28,30,9,15), +(1860,14,304,228,1044,33,11,44,29,31,9,16), +(1860,15,331,252,1102,34,12,48,31,32,11,18), +(1860,16,358,275,1160,36,12,52,31,33,11,19), +(1860,17,385,300,1217,38,12,55,32,34,13,21), +(1860,18,415,314,1273,39,13,59,34,36,12,21), +(1860,19,444,352,1330,40,13,63,34,37,13,22), +(1860,20,476,378,1386,42,14,67,36,38,14,23), +(1860,21,510,393,1446,44,14,71,37,39,15,25), +(1860,22,548,420,1503,46,14,75,38,41,15,25), +(1860,23,586,448,1559,47,15,79,39,42,16,26), +(1860,24,628,477,1617,49,16,83,40,43,16,27), +(1860,25,671,505,1672,50,16,87,42,44,18,29), +(1860,26,716,534,1729,52,16,91,43,46,19,30), +(1860,27,759,564,1788,53,17,95,43,47,19,31), +(1860,28,805,582,1842,55,17,99,45,48,20,32), +(1860,29,850,625,1900,57,18,103,46,49,20,32), +(1860,30,892,657,1955,57,18,107,48,51,21,34), +(1860,31,935,677,2012,59,19,111,49,52,22,35), +(1860,32,977,720,2071,60,19,115,50,53,22,36), +(1860,33,1021,742,2125,62,20,119,51,54,23,37), +(1860,34,1064,776,2184,63,20,123,52,56,23,37), +(1860,35,1110,822,2238,65,21,127,54,57,24,39), +(1860,36,1155,845,2415,66,21,131,55,59,25,40), +(1860,37,1202,880,2602,68,21,135,56,60,26,41), +(1860,38,1249,917,2795,70,22,139,58,62,26,42), +(1860,39,1298,953,3002,72,22,143,59,63,27,43), +(1860,40,1349,988,3219,74,23,148,61,65,28,44), +(1860,41,1395,1026,3444,76,23,152,62,66,30,47), +(1860,42,1453,1064,3685,81,23,156,63,67,31,49), +(1860,43,1510,1104,3936,86,24,160,65,69,34,53), +(1860,44,1569,1143,4203,93,25,164,65,70,36,58), +(1860,45,1626,1182,4480,96,25,169,67,72,38,60), +(1860,46,1689,1223,4573,98,26,173,68,73,38,61), +(1860,47,1751,1264,4641,100,26,177,70,75,40,63), +(1860,48,1815,1306,4749,102,27,181,72,76,40,64), +(1860,49,1881,1348,4841,104,27,186,73,78,42,66), +(1860,50,1949,1393,4931,107,28,190,75,80,43,68), +(1860,51,2017,1436,5018,109,29,194,76,81,43,68), +(1860,52,2087,1482,5110,111,29,199,77,82,45,71), +(1860,53,2158,1528,5200,113,30,203,79,84,45,72), +(1860,54,2229,1573,5287,115,30,207,80,85,47,74), +(1860,55,2300,1631,5376,117,31,212,82,88,48,75), +(1860,56,2375,1667,5468,120,31,216,83,89,48,76), +(1860,57,2450,1727,5556,122,32,221,84,90,50,78), +(1860,58,2527,1764,5645,124,33,225,87,92,63,99), +(1860,59,2606,1825,5734,127,33,230,88,94,68,107), +(1860,60,2686,1876,6236,129,34,234,90,96,87,134), +(1860,61,2767,1915,6730,132,35,239,105,99,100,154), +(1860,62,2849,1979,7223,133,36,243,108,102,110,169), +(1860,63,2932,2019,7717,136,37,248,112,105,117,180), +(1860,64,3014,2084,8210,138,38,252,115,108,125,191), +(1860,65,3101,2150,8704,141,39,257,119,110,132,202), +(1860,66,3189,2193,9197,143,39,261,122,113,140,214), +(1860,67,3280,2260,9693,146,41,266,124,115,148,226), +(1860,68,3374,2304,10186,148,41,271,127,118,173,264), +(1860,69,3468,2373,10679,151,42,275,130,120,189,289), +(1860,70,3564,2431,11173,153,43,280,133,122,207,314), +(1860,71,3742,2489,11670,155,47,285,134,125,212,323), +(1860,72,3915,2550,12165,158,50,289,136,127,218,332), +(1860,73,4094,2610,12662,161,54,294,138,130,225,342), +(1860,74,4276,2671,13159,177,58,299,139,190,231,352), +(1860,75,4461,2744,13658,195,63,304,141,194,238,362), +(1860,76,4647,2807,14155,214,67,309,143,196,244,371), +(1860,77,4837,2870,14652,236,72,314,144,200,250,381), +(1860,78,5029,2935,15151,260,78,318,146,202,257,392), +(1860,79,5226,3000,15650,285,84,323,148,206,264,403), +(1860,80,5428,3077,16148,314,90,328,150,209,271,414), +-- Succubus +(1863,1,1,1,1,1,1,1,1,1,1,1), +(1863,2,1,1,1,1,1,1,1,1,1,1), +(1863,3,1,1,1,1,1,1,1,1,1,1), +(1863,4,1,1,1,1,1,1,1,1,1,1), +(1863,5,1,1,1,1,1,1,1,1,1,1), +(1863,6,1,1,1,1,1,1,1,1,1,1), +(1863,7,1,1,1,1,1,1,1,1,1,1), +(1863,8,1,1,1,1,1,1,1,1,1,1), +(1863,9,1,1,1,1,1,1,1,1,1,1), +(1863,10,1,1,1,1,1,1,1,1,1,1), +(1863,11,1,1,1,1,1,1,1,1,1,1), +(1863,12,1,1,1,1,1,1,1,1,1,1), +(1863,13,1,1,1,1,1,1,1,1,1,1), +(1863,14,1,1,1,1,1,1,1,1,1,1), +(1863,15,1,1,1,1,1,1,1,1,1,1), +(1863,16,1,1,1,1,1,1,1,1,1,1), +(1863,17,1,1,1,1,1,1,1,1,1,1), +(1863,18,1,1,1,1,1,1,1,1,1,1), +(1863,19,1,1,1,1,1,1,1,1,1,1), +(1863,20,387,378,836,42,14,67,36,38,19,31), +(1863,21,415,393,872,44,14,71,37,39,21,32), +(1863,22,445,420,906,46,14,75,38,41,21,33), +(1863,23,477,448,940,47,15,79,39,42,22,35), +(1863,24,511,477,975,49,16,83,40,43,23,36), +(1863,25,546,505,1008,50,16,87,42,44,24,38), +(1863,26,583,534,1042,52,16,91,43,46,25,39), +(1863,27,618,564,1078,53,17,95,43,47,26,40), +(1863,28,656,582,1110,55,17,99,45,48,27,42), +(1863,29,693,625,1145,57,18,103,46,49,28,43), +(1863,30,727,657,1178,57,18,107,48,51,29,44), +(1863,31,762,677,1213,59,19,111,49,52,30,46), +(1863,32,796,720,1248,60,19,115,50,53,30,47), +(1863,33,832,742,1281,62,20,119,51,54,32,48), +(1863,34,867,776,1316,63,20,123,52,56,32,49), +(1863,35,904,822,1349,65,21,127,54,57,33,51), +(1863,36,941,845,1455,66,21,131,55,59,35,53), +(1863,37,980,880,1567,68,21,135,56,60,35,54), +(1863,38,1017,917,1683,70,22,139,58,62,36,55), +(1863,39,1058,953,1807,72,22,143,59,63,37,57), +(1863,40,1099,961,1937,74,23,148,61,65,38,58), +(1863,41,1137,1026,2072,76,23,152,62,66,41,62), +(1863,42,1185,1064,2216,81,23,156,63,67,43,65), +(1863,43,1232,1104,2367,86,24,160,65,69,46,70), +(1863,44,1279,1143,2527,93,25,164,65,70,50,76), +(1863,45,1326,1182,2693,96,25,169,67,72,52,79), +(1863,46,1377,1223,2749,98,26,173,68,73,53,80), +(1863,47,1393,1264,2802,100,26,177,70,75,55,83), +(1863,48,1481,1306,2855,102,27,181,72,76,55,84), +(1863,49,1535,1348,2910,104,27,186,73,78,57,87), +(1863,50,1590,1393,2964,107,28,190,75,80,59,89), +(1863,51,1646,1436,3017,109,29,194,76,81,59,90), +(1863,52,1702,1482,3072,111,29,199,77,82,61,93), +(1863,53,1761,1528,3126,113,30,203,79,84,62,94), +(1863,54,1818,1573,3178,115,30,207,80,85,64,97), +(1863,55,1877,1631,3232,117,31,212,82,88,65,98), +(1863,56,1938,1667,3287,120,31,216,83,89,66,100), +(1863,57,1999,1727,3340,122,32,221,84,90,68,103), +(1863,58,2062,1764,3394,124,33,225,87,92,85,128), +(1863,59,2127,1825,3447,127,33,230,88,94,91,137), +(1863,60,2193,1876,3748,129,34,234,90,96,113,171), +(1863,61,2258,1915,4044,132,35,239,105,99,130,195), +(1863,62,2326,1979,4340,133,36,243,108,102,142,214), +(1863,63,2392,2019,4636,136,37,248,112,105,151,227), +(1863,64,2460,2084,4932,138,38,252,115,108,160,241), +(1863,65,2531,2150,5228,141,39,257,119,110,170,255), +(1863,66,2603,2193,5523,143,39,261,122,113,180,270), +(1863,67,2678,2260,5821,146,41,266,124,115,190,285), +(1863,68,2754,2304,6116,148,41,271,127,118,220,331), +(1863,69,2832,2373,6412,151,42,275,130,120,241,361), +(1863,70,2910,2431,6708,153,43,280,133,122,261,392), +(1863,71,3070,2489,7007,155,47,285,134,125,269,403), +(1863,72,3225,2550,7305,158,50,289,136,127,276,415), +(1863,73,3384,2610,7604,161,54,294,138,130,284,427), +(1863,74,3546,2671,7903,177,58,299,139,190,293,440), +(1863,75,3710,2744,8204,195,63,304,141,194,302,453), +(1863,76,3874,2807,8503,214,67,309,143,196,310,466), +(1863,77,4044,2870,8803,236,72,314,144,200,320,480), +(1863,78,4214,2935,9104,260,78,318,146,202,330,494), +(1863,79,4387,3000,9405,285,84,323,148,206,340,509), +(1863,80,4567,3077,9706,314,90,328,150,209,350,524), +-- Felhunter +(417,1,1,1,1,1,1,1,1,1,1,1), +(417,2,1,1,1,1,1,1,1,1,1,1), +(417,3,1,1,1,1,1,1,1,1,1,1), +(417,4,1,1,1,1,1,1,1,1,1,1), +(417,5,1,1,1,1,1,1,1,1,1,1), +(417,6,1,1,1,1,1,1,1,1,1,1), +(417,7,1,1,1,1,1,1,1,1,1,1), +(417,8,1,1,1,1,1,1,1,1,1,1), +(417,9,1,1,1,1,1,1,1,1,1,1), +(417,10,1,1,1,1,1,1,1,1,1,1), +(417,11,1,1,1,1,1,1,1,1,1,1), +(417,12,1,1,1,1,1,1,1,1,1,1), +(417,13,1,1,1,1,1,1,1,1,1,1), +(417,14,1,1,1,1,1,1,1,1,1,1), +(417,15,1,1,1,1,1,1,1,1,1,1), +(417,16,1,1,1,1,1,1,1,1,1,1), +(417,17,1,1,1,1,1,1,1,1,1,1), +(417,18,1,1,1,1,1,1,1,1,1,1), +(417,19,1,1,1,1,1,1,1,1,1,1), +(417,20,1,1,1,1,1,1,1,1,1,1), +(417,21,1,1,1,1,1,1,1,1,1,1), +(417,22,1,1,1,1,1,1,1,1,1,1), +(417,23,1,1,1,1,1,1,1,1,1,1), +(417,24,1,1,1,1,1,1,1,1,1,1), +(417,25,1,1,1,1,1,1,1,1,1,1), +(417,26,1,1,1,1,1,1,1,1,1,1), +(417,27,1,1,1,1,1,1,1,1,1,1), +(417,28,1,1,1,1,1,1,1,1,1,1), +(417,29,1,1,1,1,1,1,1,1,1,1), +(417,30,770,657,946,57,18,107,48,51,19,31), +(417,31,807,677,974,59,19,111,49,52,19,32), +(417,32,844,720,1002,60,19,115,50,53,19,32), +(417,33,882,742,1028,62,20,119,51,54,20,33), +(417,34,919,776,1057,63,20,123,52,56,20,34), +(417,35,958,822,1083,65,21,127,54,57,21,35), +(417,36,997,845,1168,66,21,131,55,59,22,36), +(417,37,1038,880,1257,68,21,135,56,60,23,37), +(417,38,1078,917,1350,70,22,139,58,62,23,37), +(417,39,1120,953,1450,72,22,143,59,63,24,39), +(417,40,1165,988,1554,74,23,148,61,65,24,40), +(417,41,1204,1026,1662,76,23,152,62,66,26,43), +(417,42,1255,1064,1777,81,23,156,63,67,27,45), +(417,43,1304,1104,1898,86,24,160,65,69,30,48), +(417,44,1354,1143,2026,93,25,164,65,70,32,52), +(417,45,1404,1182,2159,96,25,169,67,72,34,54), +(417,46,1458,1223,2204,98,26,173,68,73,34,55), +(417,47,1512,1264,2246,100,26,177,70,75,35,57), +(417,48,1567,1306,2289,102,27,181,72,76,36,58), +(417,49,1624,1348,2333,104,27,186,73,78,37,60), +(417,50,1683,1393,2376,107,28,190,75,80,38,61), +(417,51,1742,1436,2419,109,29,194,76,81,38,62), +(417,52,1802,1482,2463,111,29,199,77,82,40,64), +(417,53,1863,1528,2506,113,30,203,79,84,40,65), +(417,54,1925,1573,2548,115,30,207,80,85,42,67), +(417,55,1986,1631,2591,117,31,212,82,88,42,68), +(417,56,2051,1667,2635,120,31,216,83,89,43,69), +(417,57,2116,1727,2678,122,32,221,84,90,44,71), +(417,58,2182,1764,2721,124,33,225,87,92,57,89), +(417,59,2251,1825,2764,127,33,230,88,94,61,97), +(417,60,2320,1876,3005,129,34,234,90,96,78,122), +(417,61,2389,1915,3242,132,35,239,105,99,90,140), +(417,62,2460,1979,3479,133,36,243,108,102,100,154), +(417,63,2531,2019,3716,136,37,248,112,105,107,165), +(417,64,2602,2084,3953,138,38,252,115,108,113,175), +(417,65,2678,2150,4190,141,39,257,119,110,120,185), +(417,66,2754,2193,4426,143,39,261,122,113,128,197), +(417,67,2833,2260,4665,146,41,266,124,115,135,208), +(417,68,2913,2304,4901,148,41,271,127,118,158,243), +(417,69,2995,2373,5138,151,42,275,130,120,173,266), +(417,70,3077,2431,5375,153,43,280,133,122,189,289), +(417,71,3242,2489,5615,155,47,285,134,125,194,297), +(417,72,3401,2550,5854,158,50,289,136,127,200,306), +(417,73,3566,2610,6094,161,54,294,138,130,206,315), +(417,74,3733,2671,6334,177,58,299,139,190,212,324), +(417,75,3903,2744,6575,195,63,304,141,194,217,333), +(417,76,4072,2807,6815,214,67,309,143,196,222,341), +(417,77,4247,2870,7056,236,72,314,144,200,228,350), +(417,78,4422,2935,7298,260,78,318,146,202,234,359), +(417,79,4602,3000,7540,285,84,323,148,206,240,369), +(417,80,4787,3077,7782,314,90,328,150,209,246,379), +-- Felguard +(17252,1,1,1,1,1,1,1,1,1,1,1), +(17252,2,1,1,1,1,1,1,1,1,1,1), +(17252,3,1,1,1,1,1,1,1,1,1,1), +(17252,4,1,1,1,1,1,1,1,1,1,1), +(17252,5,1,1,1,1,1,1,1,1,1,1), +(17252,6,1,1,1,1,1,1,1,1,1,1), +(17252,7,1,1,1,1,1,1,1,1,1,1), +(17252,8,1,1,1,1,1,1,1,1,1,1), +(17252,9,1,1,1,1,1,1,1,1,1,1), +(17252,10,1,1,1,1,1,1,1,1,1,1), +(17252,11,1,1,1,1,1,1,1,1,1,1), +(17252,12,1,1,1,1,1,1,1,1,1,1), +(17252,13,1,1,1,1,1,1,1,1,1,1), +(17252,14,1,1,1,1,1,1,1,1,1,1), +(17252,15,1,1,1,1,1,1,1,1,1,1), +(17252,16,1,1,1,1,1,1,1,1,1,1), +(17252,17,1,1,1,1,1,1,1,1,1,1), +(17252,18,1,1,1,1,1,1,1,1,1,1), +(17252,19,1,1,1,1,1,1,1,1,1,1), +(17252,20,1,1,1,1,1,1,1,1,1,1), +(17252,21,1,1,1,1,1,1,1,1,1,1), +(17252,22,1,1,1,1,1,1,1,1,1,1), +(17252,23,1,1,1,1,1,1,1,1,1,1), +(17252,24,1,1,1,1,1,1,1,1,1,1), +(17252,25,1,1,1,1,1,1,1,1,1,1), +(17252,26,1,1,1,1,1,1,1,1,1,1), +(17252,27,1,1,1,1,1,1,1,1,1,1), +(17252,28,1,1,1,1,1,1,1,1,1,1), +(17252,29,1,1,1,1,1,1,1,1,1,1), +(17252,30,1,1,1,1,1,1,1,1,1,1), +(17252,31,1,1,1,1,1,1,1,1,1,1), +(17252,32,1,1,1,1,1,1,1,1,1,1), +(17252,33,1,1,1,1,1,1,1,1,1,1), +(17252,34,1,1,1,1,1,1,1,1,1,1), +(17252,35,1,1,1,1,1,1,1,1,1,1), +(17252,36,1,1,1,1,1,1,1,1,1,1), +(17252,37,1,1,1,1,1,1,1,1,1,1), +(17252,38,1,1,1,1,1,1,1,1,1,1), +(17252,39,1,1,1,1,1,1,1,1,1,1), +(17252,40,1,1,1,1,1,1,1,1,1,1), +(17252,41,1,1,1,1,1,1,1,1,1,1), +(17252,42,1,1,1,1,1,1,1,1,1,1), +(17252,43,1,1,1,1,1,1,1,1,1,1), +(17252,44,1,1,1,1,1,1,1,1,1,1), +(17252,45,1,1,1,1,1,1,1,1,1,1), +(17252,46,1,1,1,1,1,1,1,1,1,1), +(17252,47,1,1,1,1,1,1,1,1,1,1), +(17252,48,1,1,1,1,1,1,1,1,1,1), +(17252,49,1,1,1,1,1,1,1,1,1,1), +(17252,50,1949,1393,4285,107,28,190,75,80,54,83), +(17252,51,2017,1436,4361,109,29,194,76,81,55,84), +(17252,52,2087,1482,4441,111,29,199,77,82,57,87), +(17252,53,2158,1528,4519,113,30,203,79,84,58,88), +(17252,54,2229,1573,4594,115,30,207,80,85,60,91), +(17252,55,2300,1631,4672,117,31,212,82,88,61,92), +(17252,56,2375,1667,4752,120,31,216,83,89,61,94), +(17252,57,2450,1727,4828,122,32,221,84,90,63,96), +(17252,58,2527,1764,4906,124,33,225,87,92,79,120), +(17252,59,2606,1825,4983,127,33,230,88,94,85,129), +(17252,60,2686,1876,5419,129,34,234,90,96,106,161), +(17252,61,2767,1915,5848,132,35,239,105,99,122,184), +(17252,62,2849,1979,6276,133,36,243,108,102,134,202), +(17252,63,2932,2019,6705,136,37,248,112,105,142,215), +(17252,64,3014,2084,7134,138,38,252,115,108,151,228), +(17252,65,3101,2150,7563,141,39,257,119,110,160,241), +(17252,66,3189,2193,7990,143,39,261,122,113,169,255), +(17252,67,3280,2260,8422,146,41,266,124,115,179,269), +(17252,68,3374,2304,8849,148,41,271,127,118,208,314), +(17252,69,3468,2373,9278,151,42,275,130,120,227,342), +(17252,70,3564,2431,9707,153,43,280,133,122,247,372), +(17252,71,3742,2489,10139,155,47,285,134,125,254,382), +(17252,72,3915,2550,10569,158,50,289,136,127,261,393), +(17252,73,4094,2610,11001,161,54,294,138,130,268,404), +(17252,74,4276,2671,11433,177,58,299,139,190,277,417), +(17252,75,4461,2744,11867,195,63,304,141,194,285,429), +(17252,76,4647,2807,12299,214,67,309,143,196,266,441), +(17252,77,4837,2870,12731,236,72,314,144,200,302,454), +(17252,78,5029,2935,13165,260,78,318,146,202,310,467), +(17252,79,5226,3000,13599,285,84,323,148,206,320,481), +(17252,80,5428,3077,14033,314,90,328,150,209,329,495), +-- Infernal +(89,1,1,1,1,1,1,1,1,1,1,1), +(89,2,1,1,1,1,1,1,1,1,1,1), +(89,3,1,1,1,1,1,1,1,1,1,1), +(89,4,1,1,1,1,1,1,1,1,1,1), +(89,5,1,1,1,1,1,1,1,1,1,1), +(89,6,1,1,1,1,1,1,1,1,1,1), +(89,7,1,1,1,1,1,1,1,1,1,1), +(89,8,1,1,1,1,1,1,1,1,1,1), +(89,9,1,1,1,1,1,1,1,1,1,1), +(89,10,1,1,1,1,1,1,1,1,1,1), +(89,11,1,1,1,1,1,1,1,1,1,1), +(89,12,1,1,1,1,1,1,1,1,1,1), +(89,13,1,1,1,1,1,1,1,1,1,1), +(89,14,1,1,1,1,1,1,1,1,1,1), +(89,15,1,1,1,1,1,1,1,1,1,1), +(89,16,1,1,1,1,1,1,1,1,1,1), +(89,17,1,1,1,1,1,1,1,1,1,1), +(89,18,1,1,1,1,1,1,1,1,1,1), +(89,19,1,1,1,1,1,1,1,1,1,1), +(89,20,1,1,1,1,1,1,1,1,1,1), +(89,21,1,1,1,1,1,1,1,1,1,1), +(89,22,1,1,1,1,1,1,1,1,1,1), +(89,23,1,1,1,1,1,1,1,1,1,1), +(89,24,1,1,1,1,1,1,1,1,1,1), +(89,25,1,1,1,1,1,1,1,1,1,1), +(89,26,1,1,1,1,1,1,1,1,1,1), +(89,27,1,1,1,1,1,1,1,1,1,1), +(89,28,1,1,1,1,1,1,1,1,1,1), +(89,29,1,1,1,1,1,1,1,1,1,1), +(89,30,1,1,1,1,1,1,1,1,1,1), +(89,31,1,1,1,1,1,1,1,1,1,1), +(89,32,1,1,1,1,1,1,1,1,1,1), +(89,33,1,1,1,1,1,1,1,1,1,1), +(89,34,1,1,1,1,1,1,1,1,1,1), +(89,35,1,1,1,1,1,1,1,1,1,1), +(89,36,1,1,1,1,1,1,1,1,1,1), +(89,37,1,1,1,1,1,1,1,1,1,1), +(89,38,1,1,1,1,1,1,1,1,1,1), +(89,39,1,1,1,1,1,1,1,1,1,1), +(89,40,1,1,1,1,1,1,1,1,1,1), +(89,41,1,1,1,1,1,1,1,1,1,1), +(89,42,1,1,1,1,1,1,1,1,1,1), +(89,43,1,1,1,1,1,1,1,1,1,1), +(89,44,1,1,1,1,1,1,1,1,1,1), +(89,45,1,1,1,1,1,1,1,1,1,1), +(89,46,1,1,1,1,1,1,1,1,1,1), +(89,47,1,1,1,1,1,1,1,1,1,1), +(89,48,1,1,1,1,1,1,1,1,1,1), +(89,49,1,1,1,1,1,1,1,1,1,1), +(89,50,4577,1692,4931,107,28,190,75,80,243,327), +(89,51,4733,1747,5018,109,29,194,76,81,250,330), +(89,52,4883,1793,5110,111,29,199,77,82,251,338), +(89,53,5048,1850,5200,113,30,203,79,84,258,346), +(89,54,5209,1895,5287,115,30,207,80,85,263,354), +(89,55,5372,1965,5376,117,31,212,82,88,270,361), +(89,56,5533,2012,5468,120,31,216,83,89,276,362), +(89,57,5704,2072,5556,122,32,221,84,90,279,377), +(89,58,8002,2121,5645,124,33,225,87,92,329,450), +(89,59,8302,2182,5734,127,33,230,88,94,352,478), +(89,60,9892,2244,6236,129,34,234,90,96,430,587), +(89,61,10241,2295,6730,132,35,239,105,99,472,659), +(89,62,10598,2359,7223,133,36,243,108,102,517,707), +(89,63,10960,2410,7717,136,37,248,112,105,541,762), +(89,64,11317,2487,8210,138,38,252,115,108,583,772), +(89,65,11714,2553,8704,141,39,257,119,110,600,852), +(89,66,12106,2607,9197,143,39,261,122,113,632,871), +(89,67,12505,2686,9693,146,41,266,124,115,675,929), +(89,68,13768,2730,10186,148,41,271,127,118,763,1028), +(89,69,15674,2810,10679,151,42,275,130,120,826,1176), +(89,70,17579,2880,11173,153,43,280,133,122,907,1282), +(89,71,18254,2938,11670,155,47,285,134,125,928,1311), +(89,72,18941,3010,12165,158,50,289,136,127,940,1337), +(89,73,19649,3082,12662,161,54,294,138,130,1006,1384), +(89,74,20371,3154,13159,177,58,299,139,190,1010,1442), +(89,75,21131,3227,13658,195,63,304,141,194,1052,1462), +(89,76,21908,3302,14155,214,67,309,143,196,1091,1537), +(89,77,22698,3376,14652,236,72,314,144,200,1136,1581), +(89,78,23531,3453,15151,260,78,318,146,202,1165,1657), +(89,79,24381,3529,15650,285,84,323,148,206,1224,1687), +(89,80,25261,3618,16148,314,90,328,150,209,1263,1768); diff --git a/data/sql/updates/db_world/2023_08_21_01.sql b/data/sql/updates/db_world/2023_08_21_01.sql new file mode 100644 index 000000000..b62d43226 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_21_01.sql @@ -0,0 +1,5 @@ +-- DB update 2023_08_21_00 -> 2023_08_21_01 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` IN (37906, 36298); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(37906, 'spell_q10651_q10692_book_of_fel_names'); diff --git a/data/sql/updates/db_world/2023_08_23_00.sql b/data/sql/updates/db_world/2023_08_23_00.sql new file mode 100644 index 000000000..5dd97cdd9 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_23_00.sql @@ -0,0 +1,13 @@ +-- DB update 2023_08_21_01 -> 2023_08_23_00 +-- Giselda the Crone +DELETE FROM `creature_text` WHERE `CreatureID` = 18391; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(18391, 0, 0, 'Your blood will coat the walls of Kil\'sorrow!', 12, 0, 100, 0, 0, 0, 16062, 0, 'Giselda the Crone - Say on Transformation'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 18391); +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 +(18391, 0, 0, 0, 0, 0, 100, 0, 4500, 8500, 3600, 14500, 0, 0, 11, 32000, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Giselda the Crone - In Combat - Cast \'Mind Sear\''), +(18391, 0, 1, 2, 2, 0, 100, 1, 0, 65, 0, 0, 0, 0, 11, 33316, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Giselda the Crone - Between 0-65% Health - Cast \'Giselda Transform DND\' (No Repeat)'), +(18391, 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, 'Giselda the Crone - Between 0-65% Health - Say Line 0 (No Repeat)'); + +UPDATE `creature_template_addon` SET `auras` = '16592' WHERE (`entry` = 18391); diff --git a/data/sql/updates/db_world/2023_08_23_01.sql b/data/sql/updates/db_world/2023_08_23_01.sql new file mode 100644 index 000000000..4f9aadc01 --- /dev/null +++ b/data/sql/updates/db_world/2023_08_23_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_08_23_00 -> 2023_08_23_01 +-- +UPDATE `item_template` SET `spellppmRate_1` = 0.25 WHERE (`entry` = 28441); diff --git a/data/sql/updates/db_world/2023_08_24_00.sql b/data/sql/updates/db_world/2023_08_24_00.sql new file mode 100644 index 000000000..d47db7c3a --- /dev/null +++ b/data/sql/updates/db_world/2023_08_24_00.sql @@ -0,0 +1,4 @@ +-- DB update 2023_08_23_01 -> 2023_08_24_00 +-- +UPDATE `smart_scripts` SET `action_param6` = 2 WHERE `entryorguid` = 3662 AND `source_type` = 0 AND `id` = 3; +UPDATE `smart_scripts` SET `action_param6` = 2 WHERE `entryorguid` = 366200 AND `source_type` = 9 AND `id` = 1; diff --git a/deps/git-subrepo b/deps/git-subrepo deleted file mode 160000 index 2f6859642..000000000 --- a/deps/git-subrepo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2f6859642ae9104a9699021218bf607598f5a0ea diff --git a/docker-compose.yml b/docker-compose.yml index 16c515e33..4624cb2c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,9 +33,9 @@ x-ac-service-conf: &ac-service-conf <<: *ac-shared-conf # List can't be merged. See: https://forums.docker.com/t/how-to-merge-a-list-of-volumes-from-an-extension-field-into-the-service-definition/77454 # volumes: - # - ${DOCKER_VOL_ETC:-./env/docker/etc}:/azerothcore/env/dist/etc + # - ${DOCKER_VOL_ETC:-./env/dist/etc}:/azerothcore/env/dist/etc # # [osxfs optimization]: https://stackoverflow.com/a/63437557/1964544 - # - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated + # - ${DOCKER_VOL_LOGS:-./env/dist/logs}:/azerothcore/env/dist/logs:delegated services: @@ -94,7 +94,7 @@ services: # expose some dist folder outside allowing the host to use them - ${DOCKER_VOL_CONF:-./conf}:/azerothcore/conf - ${DOCKER_VOL_BIN:-ac-bin-dev}:/azerothcore/env/dist/bin - - ${DOCKER_VOL_ETC:-./env/docker/etc}:/azerothcore/env/dist/etc + - ${DOCKER_VOL_ETC:-./env/dist/etc}:/azerothcore/env/dist/etc - ac-build-dev:/azerothcore/var/build - ac-ccache-dev:/azerothcore/var/ccache profiles: [dev-build] @@ -118,32 +118,22 @@ services: - seccomp:unconfined env_file: ${DOCKER_AC_ENV_FILE:-conf/dist/env.ac} + environment: + AC_DATA_DIR: "/azerothcore/env/dist/data" + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_WORLD_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" + AC_CHARACTER_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" + AC_CLOSE_IDLE_CONNECTIONS: "0" ports: - ${DOCKER_AUTH_EXTERNAL_PORT:-3724}:3724 - ${DOCKER_WORLD_EXTERNAL_PORT:-8085}:8085 - ${DOCKER_SOAP_EXTERNAL_PORT:-7878}:7878 volumes: - ${DOCKER_VOL_ROOT:-.}:/azerothcore:cached - # expose some dist folder outside allowing the host to use them - - ${DOCKER_VOL_CONF:-./conf}:/azerothcore/conf - - ${DOCKER_VOL_BIN:-ac-bin-dev}:/azerothcore/env/dist/bin - - ${DOCKER_VOL_ETC:-./env/docker/etc}:/azerothcore/env/dist/etc # [osxfs optimization]: https://stackoverflow.com/a/63437557/1964544 - - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated - ac-build-dev:/azerothcore/var/build - ac-ccache-dev:/azerothcore/var/ccache - # client data - - ${DOCKER_VOL_DATA_CAMERAS:-./env/docker/data/Cameras}:/azerothcore/env/dist/data/Cameras - - ${DOCKER_VOL_DATA_DBC:-./env/docker/data/dbc}:/azerothcore/env/dist/data/dbc - - ${DOCKER_VOL_DATA_MAPS:-./env/docker/data/maps}:/azerothcore/env/dist/data/maps - - ${DOCKER_VOL_DATA_VMAPS:-./env/docker/data/vmaps}:/azerothcore/env/dist/data/vmaps - - ${DOCKER_VOL_DATA_MMAPS:-./env/docker/data/mmaps}:/azerothcore/env/dist/data/mmaps - # remount again for the extractors - - ${DOCKER_VOL_DATA_CAMERAS:-./env/docker/data/Cameras}:/azerothcore/env/dist/bin/Cameras - - ${DOCKER_VOL_DATA_DBC:-./env/docker/data/dbc}:/azerothcore/env/dist/bin/dbc - - ${DOCKER_VOL_DATA_MAPS:-./env/docker/data/maps}:/azerothcore/env/dist/bin/maps - - ${DOCKER_VOL_DATA_VMAPS:-./env/docker/data/vmaps}:/azerothcore/env/dist/bin/vmaps - - ${DOCKER_VOL_DATA_MMAPS:-./env/docker/data/mmaps}:/azerothcore/env/dist/bin/mmaps # this is not the directory of the extracted data! It's the client folder used by the extractors - ${DOCKER_AC_CLIENT_FOLDER:-./var/client}:/azerothcore/env/dist/bin/Data profiles: [dev] @@ -155,12 +145,19 @@ services: <<: *ac-shared-conf image: acore/ac-wotlk-worldserver-local:${DOCKER_IMAGE_TAG:-master} # name of the generated image after built locally command: ./env/dist/bin/dbimport + environment: + AC_DATA_DIR: "/azerothcore/env/dist/data" + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_WORLD_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" + AC_CHARACTER_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" + AC_CLOSE_IDLE_CONNECTIONS: "0" volumes: # read-only binaries compiled by ac-dev-server - ${DOCKER_VOL_BIN:-ac-bin-dev}:/azerothcore/env/dist/bin:ro - - ${DOCKER_VOL_ETC:-./env/docker/etc}:/azerothcore/env/dist/etc + - ${DOCKER_VOL_ETC:-./env/dist/etc}:/azerothcore/env/dist/etc:ro # [osxfs optimization]: https://stackoverflow.com/a/63437557/1964544 - - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated + - ${DOCKER_VOL_LOGS:-./env/dist/logs}:/azerothcore/env/dist/logs:delegated profiles: [local, app, db-import-local] depends_on: ac-database: @@ -183,6 +180,13 @@ services: restart: unless-stopped env_file: ${DOCKER_AC_ENV_FILE:-conf/dist/env.ac} + environment: + AC_DATA_DIR: "/azerothcore/env/dist/data" + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_WORLD_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" + AC_CHARACTER_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" + AC_CLOSE_IDLE_CONNECTIONS: "0" user: ${DOCKER_USER:-root} privileged: true build: @@ -194,15 +198,11 @@ services: volumes: # read-only binaries compiled by ac-dev-server - ${DOCKER_VOL_BIN:-ac-bin-dev}:/azerothcore/env/dist/bin:ro - - ${DOCKER_VOL_ETC:-./env/docker/etc}:/azerothcore/env/dist/etc + - ${DOCKER_VOL_ETC:-./env/dist/etc}:/azerothcore/env/dist/etc:ro # [osxfs optimization]: https://stackoverflow.com/a/63437557/1964544 - - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated + - ${DOCKER_VOL_LOGS:-./env/dist/logs}:/azerothcore/env/dist/logs:delegated # client data - - ${DOCKER_VOL_DATA_CAMERAS:-./env/docker/data/Cameras}:/azerothcore/env/dist/data/Cameras - - ${DOCKER_VOL_DATA_DBC:-./env/docker/data/dbc}:/azerothcore/env/dist/data/dbc - - ${DOCKER_VOL_DATA_MAPS:-./env/docker/data/maps}:/azerothcore/env/dist/data/maps - - ${DOCKER_VOL_DATA_VMAPS:-./env/docker/data/vmaps}:/azerothcore/env/dist/data/vmaps - - ${DOCKER_VOL_DATA_MMAPS:-./env/docker/data/mmaps}:/azerothcore/env/dist/data/mmaps + - ${DOCKER_VOL_DATA:-./env/dist/data/}:/azerothcore/env/dist/data/ profiles: [local, app, worldserver] depends_on: ac-database: @@ -218,6 +218,12 @@ services: restart: unless-stopped env_file: ${DOCKER_AC_ENV_FILE:-conf/dist/env.ac} + environment: + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_TEMP_DIR: "/azerothcore/env/dist/temp" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_SQLDRIVER_LOG_FILE: "SQLDriver.log" + AC_SQLDRIVER_QUERY_LOGGING: "1" user: ${DOCKER_USER:-root} build: target: authserver-local @@ -225,9 +231,9 @@ services: volumes: # read-only binaries compiled by ac-dev-server - ${DOCKER_VOL_BIN:-ac-bin-dev}:/azerothcore/env/dist/bin:ro - - ${DOCKER_VOL_ETC:-./env/docker/etc}:/azerothcore/env/dist/etc + - ${DOCKER_VOL_ETC:-./env/dist/etc}:/azerothcore/env/dist/etc # [osxfs optimization]: https://stackoverflow.com/a/63437557/1964544 - - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated + - ${DOCKER_VOL_LOGS:-./env/dist/logs}:/azerothcore/env/dist/logs:delegated ports: - ${DOCKER_AUTH_EXTERNAL_PORT:-3724}:3724 profiles: [local, app, authserver] @@ -281,6 +287,13 @@ services: restart: unless-stopped env_file: ${DOCKER_AC_ENV_FILE:-conf/dist/env.ac} + environment: + AC_DATA_DIR: "/azerothcore/env/dist/data" + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_WORLD_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" + AC_CHARACTER_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" + AC_CLOSE_IDLE_CONNECTIONS: "0" user: ${DOCKER_USER:-root} privileged: true build: @@ -290,7 +303,7 @@ services: - ${DOCKER_WORLD_EXTERNAL_PORT:-8085}:8085 - ${DOCKER_SOAP_EXTERNAL_PORT:-7878}:7878 volumes: - - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated + - ${DOCKER_VOL_LOGS:-./env/dist/logs}:/azerothcore/env/dist/logs:delegated - ${DOCKER_VOL_CLIENT_DATA_PROD:-ac-client-data-prod}:/azerothcore/env/dist/data:ro profiles: [prod, prod-app, prod-worldserver] depends_on: @@ -309,12 +322,18 @@ services: restart: unless-stopped env_file: ${DOCKER_AC_ENV_FILE:-conf/dist/env.ac} + environment: + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_TEMP_DIR: "/azerothcore/env/dist/temp" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_SQLDRIVER_LOG_FILE: "SQLDriver.log" + AC_SQLDRIVER_QUERY_LOGGING: "1" user: ${DOCKER_USER:-root} build: target: authserver <<: *build-params volumes: - - ${DOCKER_VOL_LOGS:-./env/docker/logs}:/azerothcore/env/dist/logs:delegated + - ${DOCKER_VOL_LOGS:-./env/dist/logs}:/azerothcore/env/dist/logs:delegated ports: - ${DOCKER_AUTH_EXTERNAL_PORT:-3724}:3724 profiles: [prod, prod-app, prod-authserver] @@ -324,7 +343,6 @@ services: ac-db-import-prod: condition: service_completed_successfully - ac-client-data-init: image: acore/ac-wotlk-client-data:${DOCKER_IMAGE_TAG:-master} # name of the generated image after built locally user: ${DOCKER_USER:-root} @@ -356,6 +374,13 @@ services: <<: *ac-shared-conf image: acore/ac-wotlk-worldserver:${DOCKER_IMAGE_TAG:-master} # name of the generated image after built locally command: ./env/dist/bin/dbimport + environment: + AC_DATA_DIR: "/azerothcore/env/dist/data" + AC_LOGS_DIR: "/azerothcore/env/dist/logs" + AC_LOGIN_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_auth" + AC_WORLD_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_world" + AC_CHARACTER_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_characters" + AC_CLOSE_IDLE_CONNECTIONS: "0" profiles: [prod, prod-app, db-import-prod] # diff --git a/env/docker/bin/.gitkeep b/env/docker/bin/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/data/.gitkeep b/env/docker/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/data/Cameras/.gitkeep b/env/docker/data/Cameras/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/data/dbc/.gitkeep b/env/docker/data/dbc/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/data/maps/.gitkeep b/env/docker/data/maps/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/data/mmaps/.gitkeep b/env/docker/data/mmaps/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/data/vmaps/.gitkeep b/env/docker/data/vmaps/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/etc/.gitkeep b/env/docker/etc/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/env/docker/etc/authserver.conf.dockerdist b/env/docker/etc/authserver.conf.dockerdist deleted file mode 100644 index 15eb0e107..000000000 --- a/env/docker/etc/authserver.conf.dockerdist +++ /dev/null @@ -1,22 +0,0 @@ -############################################### -# AzerothCore Auth Server configuration file # -############################################### -[authserver] - -# Do not change this -# Files in LogsDir will reflect on your host directory: docker/authserver/logs -LogsDir = "/azerothcore/env/dist/logs" -# Files in TempDir will reflect on your host directory: docker/authserver/temp -TempDir = "/azerothcore/env/dist/temp" - -# Change this configuration accordingly with your docker setup -# The format is "hostname;port;username;password;database": -# - docker containers must be on the same docker network to be able to communicate -# - the DB hostname will be the name of the database docker container -LoginDatabaseInfo = "ac-database;3306;root;password;acore_auth" - -# Add more configuration overwrites by copying settings from from authserver.conf.dist - -SQLDriverLogFile = "SQLDriver.log" -SQLDriverQueryLogging = 1 - diff --git a/env/docker/etc/dbimport.conf.dockerdist b/env/docker/etc/dbimport.conf.dockerdist deleted file mode 100644 index e9f97375a..000000000 --- a/env/docker/etc/dbimport.conf.dockerdist +++ /dev/null @@ -1,18 +0,0 @@ -# Do NOT change those Dir configs -# Files in LogsDir will reflect on your host directory: docker/worldserver/logs -LogsDir = "/azerothcore/env/dist/logs" -# Files in TempDir will reflect on your host directory: docker/authserver/temp -DataDir = "/azerothcore/env/dist/data" - -# Change this configuration accordingly with your docker setup -# The format is "hostname;port;username;password;database": -# - docker containers must be on the same docker network to be able to communicate -# - the DB hostname will be the name of the database docker container -LoginDatabaseInfo = "ac-database;3306;root;password;acore_auth" -WorldDatabaseInfo = "ac-database;3306;root;password;acore_world" -CharacterDatabaseInfo = "ac-database;3306;root;password;acore_characters" - -# Add more configuration overwrites by copying settings from worldserver.conf.dist - -# Disable idle connections automatic kick since it doesn't work well on macOS + Docker -CloseIdleConnections = 0 diff --git a/env/docker/etc/worldserver.conf.dockerdist b/env/docker/etc/worldserver.conf.dockerdist deleted file mode 100644 index a51ef16d5..000000000 --- a/env/docker/etc/worldserver.conf.dockerdist +++ /dev/null @@ -1,23 +0,0 @@ -################################################ -# AzerothCore World Server configuration file # -################################################ -[worldserver] - -# Do NOT change those Dir configs -# Files in LogsDir will reflect on your host directory: docker/worldserver/logs -LogsDir = "/azerothcore/env/dist/logs" -# Files in TempDir will reflect on your host directory: docker/authserver/temp -DataDir = "/azerothcore/env/dist/data" - -# Change this configuration accordingly with your docker setup -# The format is "hostname;port;username;password;database": -# - docker containers must be on the same docker network to be able to communicate -# - the DB hostname will be the name of the database docker container -LoginDatabaseInfo = "ac-database;3306;root;password;acore_auth" -WorldDatabaseInfo = "ac-database;3306;root;password;acore_world" -CharacterDatabaseInfo = "ac-database;3306;root;password;acore_characters" - -# Add more configuration overwrites by copying settings from worldserver.conf.dist - -# Disable idle connections automatic kick since it doesn't work well on macOS + Docker -CloseIdleConnections = 0 diff --git a/env/docker/logs/.gitkeep b/env/docker/logs/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/pull_request_template.md b/pull_request_template.md index 3b677b0d2..7f6c343dc 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,8 +1,12 @@ ## Changes Proposed: -- -- +This PR proposes changes to: +- [ ] Core (units, players, creatures, game systems). +- [ ] Scripts (bosses, spell scripts, creature scripts). +- [ ] Database (SAI, creatures, etc). + +If your pull request promotes complex changes that require a detailed explanation, please describe them in detail specifying what your solution is and what is it meant to address. ## Issues Addressed: @@ -10,16 +14,26 @@ ## SOURCE: +The changes have been validated through: +- [ ] Live research (checked on live servers, e.g Classic WotLK, Retail, etc.) +- [ ] Sniffs (remember to share them with the open source community!) +- [ ] Video evidence, knowledge databases or other public sources (e.g forums, Wowhead, etc.) +- [ ] The changes promoted by this pull request come partially or entirely from another project (cherry-pick). **Cherry-picks must be committed using the proper --author tag in order to be accepted, thus crediting the original authors, unless otherwise unable to be found** ## Tests Performed: -- -- +This PR has been: +- [ ] Tested in-game by the author. +- [ ] Tested in-game by other community members/someone else other than the author/has been live on production servers. +- [ ] This pull request requires further testing and may have edge cases to be tested. ## How to Test the Changes: +- [ ] This pull request can be tested by following the reproduction steps provided in the linked issue +- [ ] This pull request requires further testing. Provide steps to test your changes. If it requires any specific setup e.g multiple players please specify it as well. + 1. 2. 3. diff --git a/src/cmake/macros/FindMySQL.cmake b/src/cmake/macros/FindMySQL.cmake index 2feb77055..09a7fd1df 100644 --- a/src/cmake/macros/FindMySQL.cmake +++ b/src/cmake/macros/FindMySQL.cmake @@ -24,19 +24,6 @@ set( MYSQL_FOUND 0 ) -if(WIN32) - # read environment variables and change \ to / - SET(PROGRAM_FILES_32 $ENV{ProgramFiles}) - if (${PROGRAM_FILES_32}) - STRING(REPLACE "\\\\" "/" PROGRAM_FILES_32 ${PROGRAM_FILES_32}) - endif(${PROGRAM_FILES_32}) - - SET(PROGRAM_FILES_64 $ENV{ProgramW6432}) - if (${PROGRAM_FILES_64}) - STRING(REPLACE "\\\\" "/" PROGRAM_FILES_64 ${PROGRAM_FILES_64}) - endif(${PROGRAM_FILES_64}) -endif(WIN32) - # Find MariaDB for Windows if (WIN32) # Set know versions MariaDB @@ -55,8 +42,8 @@ if (WIN32) mysql.h PATHS ${MYSQL_ADD_INCLUDE_PATH} - "${PROGRAM_FILES_64}/${MariaDBVersion}/include/mysql" - "${PROGRAM_FILES_32}/${MariaDBVersion}/include/mysql" + "$ENV{ProgramW6432}/${MariaDBVersion}/include/mysql" + "$ENV{ProgramFiles}/${MariaDBVersion}/include/mysql" "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/mysql" DOC "Specify the directory containing mysql.h." @@ -71,10 +58,9 @@ if (WIN32) libmariadb PATHS ${MYSQL_ADD_LIBRARIES_PATH} - "${PROGRAM_FILES_64}/${MariaDBVersion}/lib" - "${PROGRAM_FILES_64}/${MariaDBVersion}/lib/opt" - "${PROGRAM_FILES_32}/${MariaDBVersion}/lib" - "${PROGRAM_FILES_32}/${MariaDBVersion}/lib/opt" + "$ENV{ProgramW6432}/${MariaDBVersion}/lib" + "$ENV{ProgramW6432}/${MariaDBVersion}/lib/opt" + "$ENV{ProgramFiles}/${MariaDBVersion}/lib" "$ENV{ProgramFiles}/${MariaDBVersion}/lib/opt" "$ENV{SystemDrive}/${MariaDBVersion}/lib/opt" "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" @@ -88,10 +74,9 @@ if (WIN32) find_program(MYSQL_EXECUTABLE mysql PATHS - "${PROGRAM_FILES_64}/${MariaDBVersion}/bin" - "${PROGRAM_FILES_64}/${MariaDBVersion}/bin/opt" - "${PROGRAM_FILES_32}/${MariaDBVersion}/bin" - "${PROGRAM_FILES_32}/${MariaDBVersion}/bin/opt" + "$ENV{ProgramW6432}/${MariaDBVersion}/bin" + "$ENV{ProgramW6432}/${MariaDBVersion}/bin/opt" + "$ENV{ProgramFiles}/${MariaDBVersion}/bin" "$ENV{ProgramFiles}/${MariaDBVersion}/bin/opt" "$ENV{SystemDrive}/${MariaDBVersion}/bin/opt" DOC @@ -171,18 +156,17 @@ find_path(MYSQL_INCLUDE_DIR /usr/local/include/mysql /usr/local/mysql/include "C:/tools/mysql/current/include" # chocolatey package - "C:/Program Files/MySQL/MySQL Server 8.0/include" - "C:/Program Files/MySQL/MySQL Server 5.7/include" - "C:/Program Files/MySQL/include" - "C:/MySQL/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/include" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/include" - "$ENV{ProgramFiles}/MySQL/*/include" - "$ENV{SystemDrive}/MySQL/*/include" - "c:/msys/local/include" + "$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/include" + "$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/include" + "$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/include" + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/include" + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/include" + "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.1/include" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/include" + "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/include" "$ENV{MYSQL_INCLUDE_DIR}" + "$ENV{MYSQL_DIR}/include" DOC "Specify the directory containing mysql.h." ) @@ -211,23 +195,17 @@ if( WIN32 ) PATHS ${MYSQL_ADD_LIBRARIES_PATH} "C:/tools/mysql/current/lib" # chocolatey package - "C:/Program Files/MySQL/MySQL Server 8.0/lib" - "C:/Program Files/MySQL/MySQL Server 8.0/lib/opt" - "C:/Program Files/MySQL/MySQL Server 5.7/lib/opt" - "C:/Program Files/MySQL/lib" - "C:/MySQL/lib/debug" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/lib/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt" - "$ENV{ProgramFiles}/MySQL/*/lib/opt" - "$ENV{SystemDrive}/MySQL/*/lib/opt" - "c:/msys/local/include" + "$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/lib" + "$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/lib" + "$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/lib" + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/lib" + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/lib" + "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/lib" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.1/lib" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/lib" + "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/lib" "$ENV{MYSQL_LIBRARY}" + "$ENV{MYSQL_DIR}/lib" DOC "Specify the location of the mysql library here." ) endif( WIN32 ) @@ -264,30 +242,15 @@ if( WIN32 ) find_program(MYSQL_EXECUTABLE mysql PATHS "C:/tools/mysql/current/bin" # chocolatey package - "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin/opt" - "${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt" - "${PROGRAM_FILES_64}/MySQL/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin/opt" - "${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin/opt" - "${PROGRAM_FILES_32}/MySQL/bin" - "C:/MySQL/bin/debug" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin/opt" - "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin/opt" - "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin/opt" - "c:/msys/local/include" + "$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/bin" + "$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/bin" + "$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/bin" + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/bin" + "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin" + "$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.1/bin" + "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin" + "$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin" "$ENV{MYSQL_ROOT}/bin" DOC "path to your mysql binary.") diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index d5750120d..d01d3f7b8 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -21,6 +21,7 @@ #include "StringFormat.h" #include "Tokenize.h" #include "Util.h" +#include #include #include #include @@ -215,6 +216,81 @@ namespace return false; } + + // Converts ini keys to the environment variable key (upper snake case). + // Example of conversions: + // SomeConfig => SOME_CONFIG + // myNestedConfig.opt1 => MY_NESTED_CONFIG_OPT_1 + // LogDB.Opt.ClearTime => LOG_DB_OPT_CLEAR_TIME + std::string IniKeyToEnvVarKey(std::string const& key) + { + std::string result; + + const char* str = key.c_str(); + size_t n = key.length(); + + char curr; + bool isEnd; + bool nextIsUpper; + bool currIsNumeric; + bool nextIsNumeric; + + for (size_t i = 0; i < n; ++i) + { + curr = str[i]; + if (curr == ' ' || curr == '.' || curr == '-') + { + result += '_'; + continue; + } + + isEnd = i == n - 1; + if (!isEnd) + { + nextIsUpper = isupper(str[i + 1]); + + // handle "aB" to "A_B" + if (!isupper(curr) && nextIsUpper) + { + result += static_cast(std::toupper(curr)); + result += '_'; + continue; + } + + currIsNumeric = isNumeric(curr); + nextIsNumeric = isNumeric(str[i + 1]); + + // handle "a1" to "a_1" + if (!currIsNumeric && nextIsNumeric) + { + result += static_cast(std::toupper(curr)); + result += '_'; + continue; + } + + // handle "1a" to "1_a" + if (currIsNumeric && !nextIsNumeric) + { + result += static_cast(std::toupper(curr)); + result += '_'; + continue; + } + } + + result += static_cast(std::toupper(curr)); + } + return result; + } + + Optional EnvVarForIniKey(std::string const& key) + { + std::string envKey = "AC_" + IniKeyToEnvVarKey(key); + char* val = std::getenv(envKey.c_str()); + if (!val) + return std::nullopt; + + return std::string(val); + } } bool ConfigMgr::LoadInitial(std::string const& file, bool isReload /*= false*/) @@ -243,25 +319,72 @@ bool ConfigMgr::Reload() return false; } - return LoadModulesConfigs(true, false); + if (!LoadModulesConfigs(true, false)) + { + return false; + } + + OverrideWithEnvVariablesIfAny(); + + return true; +} + +std::vector ConfigMgr::OverrideWithEnvVariablesIfAny() +{ + std::lock_guard lock(_configLock); + + std::vector overriddenKeys; + + for (auto& itr : _configOptions) + { + if (itr.first.empty()) + continue; + + Optional envVar = EnvVarForIniKey(itr.first); + if (!envVar) + continue; + + itr.second = *envVar; + + overriddenKeys.push_back(itr.first); + } + + return overriddenKeys; } template T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLogs /*= true*/) const { + std::string strValue; auto const& itr = _configOptions.find(name); if (itr == _configOptions.end()) { - if (showLogs) + Optional envVar = EnvVarForIniKey(name); + if (!envVar) { - LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.", - name, _filename, name, Acore::ToString(def)); + if (showLogs) + { + LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.", + name, _filename, name, Acore::ToString(def)); + } + + return def; } - return def; + if (showLogs) + { + LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.", + name.c_str(), _filename.c_str(), envVar->c_str()); + } + + strValue = *envVar; + } + else + { + strValue = itr->second; } - auto value = Acore::StringTo(itr->second); + auto value = Acore::StringTo(strValue); if (!value) { if (showLogs) @@ -282,6 +405,18 @@ std::string ConfigMgr::GetValueDefault(std::string const& name, std auto const& itr = _configOptions.find(name); if (itr == _configOptions.end()) { + Optional envVar = EnvVarForIniKey(name); + if (envVar) + { + if (showLogs) + { + LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.", + name.c_str(), _filename.c_str(), envVar->c_str()); + } + + return *envVar; + } + if (showLogs) { LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.", diff --git a/src/common/Configuration/Config.h b/src/common/Configuration/Config.h index ddac0efb6..db7410e05 100644 --- a/src/common/Configuration/Config.h +++ b/src/common/Configuration/Config.h @@ -39,6 +39,9 @@ public: bool Reload(); + /// Overrides configuration with environment variables and returns overridden keys + std::vector OverrideWithEnvVariablesIfAny(); + std::string const GetFilename(); std::string const GetConfigPath(); [[nodiscard]] std::vector const& GetArguments() const; diff --git a/src/server/apps/authserver/Main.cpp b/src/server/apps/authserver/Main.cpp index 4c110db7a..bc40f2f10 100644 --- a/src/server/apps/authserver/Main.cpp +++ b/src/server/apps/authserver/Main.cpp @@ -85,6 +85,8 @@ int main(int argc, char** argv) if (!sConfigMgr->LoadAppConfigs()) return 1; + std::vector overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny(); + // Init logging sLog->RegisterAppender(); sLog->Initialize(nullptr); @@ -101,6 +103,9 @@ int main(int argc, char** argv) LOG_INFO("server.authserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); }); + for (std::string const& key : overriddenKeys) + LOG_INFO("server.authserver", "Configuration field {} was overridden with environment variable.", key); + OpenSSLCrypto::threadsSetup(); std::shared_ptr opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); }); diff --git a/src/server/apps/worldserver/Main.cpp b/src/server/apps/worldserver/Main.cpp index 8483737e2..385ce122b 100644 --- a/src/server/apps/worldserver/Main.cpp +++ b/src/server/apps/worldserver/Main.cpp @@ -184,6 +184,8 @@ int main(int argc, char** argv) if (!sConfigMgr->LoadAppConfigs()) return 1; + std::vector overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny(); + std::shared_ptr ioContext = std::make_shared(); // Init all logs @@ -203,6 +205,9 @@ int main(int argc, char** argv) LOG_INFO("server.worldserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); }); + for (std::string const& key : overriddenKeys) + LOG_INFO("server.worldserver", "Configuration field {} was overridden with environment variable.", key); + OpenSSLCrypto::threadsSetup(); std::shared_ptr opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); }); diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index 13f3bd716..7df85b510 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -3949,8 +3949,8 @@ AuctionHouse.SearchTimeout = 1000 Appender.Console=1,4,0,"1 9 3 6 5 8" Appender.Server=2,5,0,Server.log,w -Appender.GM=2,5,15,gm_%s.log -Appender.DBErrors=2,5,0,DBErrors.log +# Appender.GM=2,5,15,gm_%s.log +Appender.Errors=2,5,0,Errors.log # Appender.DB=3,5,0 # Logger config values: Given a logger "name" @@ -3977,10 +3977,11 @@ Logger.diff=3,Console Server Logger.mmaps=4,Server Logger.scripts.hotswap=4,Console Server Logger.server=4,Console Server -Logger.sql.sql=2,Console DBErrors +Logger.sql.sql=2,Console Errors Logger.sql=4,Console Server Logger.time.update=4,Console Server Logger.module=4,Console Server +Logger.spells.scripts=2,Console Errors #Logger.achievement=4,Console Server #Logger.addon=4,Console Server diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 623533a2a..e6fa97751 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -27,7 +27,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_DEL_CRELINKED_RESPAWN, "DELETE FROM linked_respawn WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_REP_CREATURE_LINKED_RESPAWN, "REPLACE INTO linked_respawn (guid, linkedGuid) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_CREATURE_TEXT, "SELECT CreatureID, GroupID, ID, Text, Type, Language, Probability, Emote, Duration, Sound, BroadcastTextId, TextRange FROM creature_text", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_param4, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_SMART_SCRIPTS, "SELECT 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 FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z, orientation, delay FROM waypoints ORDER BY entry, pointid", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_GAMEOBJECT, "DELETE FROM gameobject WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_EVENT_GAMEOBJECT, "DELETE FROM game_event_gameobject WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 784451441..dd5f09297 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1958,7 +1958,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; ObjectVector casters; - GetTargets(casters, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0, 0), unit); + GetTargets(casters, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0, 0), unit); for (WorldObject* caster : casters) { @@ -2891,6 +2891,101 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } break; } + case SMART_ACTION_FOLLOW_GROUP: + { + if (!e.action.followGroup.followState) + { + for (WorldObject* target : targets) + if (IsUnit(target)) + target->ToCreature()->GetMotionMaster()->MoveIdle(); + + break; + } + + uint8 membCount = targets.size(); + uint8 itr = 1; + float dist = float(e.action.followGroup.dist / 100); + switch (e.action.followGroup.followType) + { + case FOLLOW_TYPE_CIRCLE: + { + float angle = (membCount > 4 ? (M_PI * 2)/membCount : (M_PI / 2)); // 90 degrees is the maximum angle + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist, angle * itr); + itr++; + } + } + break; + } + case FOLLOW_TYPE_SEMI_CIRCLE_BEHIND: + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist, (M_PI / 2.0f) + (M_PI / membCount) * (itr - 1)); + itr++; + } + } + break; + } + case FOLLOW_TYPE_SEMI_CIRCLE_FRONT: + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist, (M_PI + (M_PI / 2.0f) + (M_PI / membCount) * (itr - 1))); + itr++; + } + } + break; + } + case FOLLOW_TYPE_LINE: + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist * (((itr - 1) / 2) + 1), itr % 2 ? 0.f : M_PI); + itr++; + } + } + break; + } + case FOLLOW_TYPE_COLUMN: + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist * (((itr - 1) / 2) + 1), itr % 2 ? (M_PI / 2) : (M_PI * 1.5f)); + itr++; + } + } + break; + } + case FOLLOW_TYPE_ANGULAR: + { + for (WorldObject* target : targets) + { + if (IsCreature(target)) + { + target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist * (((itr - 1) / 2) + 1), itr % 2 ? M_PI - (M_PI / 4) : M_PI + (M_PI / 4)); + itr++; + } + } + break; + } + default: + break; + } + + break; + } default: LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); break; @@ -2935,18 +3030,18 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e) { case SMARTAI_TEMPLATE_CASTER: { - AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 1); - AddEvent(SMART_EVENT_RANGE, 0, e.action.installTtemplate.param4, 300, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); - AddEvent(SMART_EVENT_RANGE, 0, 0, e.action.installTtemplate.param4 > 10 ? e.action.installTtemplate.param4 - 10 : 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); - AddEvent(SMART_EVENT_MANA_PCT, 0, e.action.installTtemplate.param5 - 15 > 100 ? 100 : e.action.installTtemplate.param5 + 15, 100, 1000, 1000, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); - AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, SMART_ACTION_SET_EVENT_PHASE, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); - AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 1); + AddEvent(SMART_EVENT_RANGE, 0, e.action.installTtemplate.param4, 300, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); + AddEvent(SMART_EVENT_RANGE, 0, 0, e.action.installTtemplate.param4 > 10 ? e.action.installTtemplate.param4 - 10 : 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); + AddEvent(SMART_EVENT_MANA_PCT, 0, e.action.installTtemplate.param5 - 15 > 100 ? 100 : e.action.installTtemplate.param5 + 15, 100, 1000, 1000, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); break; } case SMARTAI_TEMPLATE_TURRET: { - AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 0); - AddEvent(SMART_EVENT_JUST_CREATED, 0, 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_JUST_CREATED, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); break; } case SMARTAI_TEMPLATE_CAGED_NPC_PART: @@ -2954,22 +3049,22 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e) if (!me) return; //store cage as id1 - AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_GAMEOBJECT, e.action.installTtemplate.param1, 10, 0, 0, 0); + AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_GAMEOBJECT, e.action.installTtemplate.param1, 10, 0, 0, 0); //reset(close) cage on hostage(me) respawn - AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 0, 0, 0, 0, 0, SMART_ACTION_RESET_GOBJECT, 0, 0, 0, 0, 0, 0, SMART_TARGET_GAMEOBJECT_DISTANCE, e.action.installTtemplate.param1, 5, 0, 0, 0); + AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 0, 0, 0, 0, 0, 0, SMART_ACTION_RESET_GOBJECT, 0, 0, 0, 0, 0, 0, SMART_TARGET_GAMEOBJECT_DISTANCE, e.action.installTtemplate.param1, 5, 0, 0, 0); - AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_RUN, e.action.installTtemplate.param3, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); - AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_RUN, e.action.installTtemplate.param3, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); - AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 1000, 1000, 0, 0, 0, SMART_ACTION_MOVE_FORWARD, e.action.installTtemplate.param4, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); + AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 1000, 1000, 0, 0, 0, 0, SMART_ACTION_MOVE_FORWARD, e.action.installTtemplate.param4, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); //phase 1: give quest credit on movepoint reached - AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 1); + AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 1); //phase 1: despawn after time on movepoint reached - AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, SMART_ACTION_FORCE_DESPAWN, e.action.installTtemplate.param2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); + AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_FORCE_DESPAWN, e.action.installTtemplate.param2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); if (sCreatureTextMgr->TextExist(me->GetEntry(), (uint8)e.action.installTtemplate.param5)) - AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, SMART_ACTION_TALK, e.action.installTtemplate.param5, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); + AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_TALK, e.action.installTtemplate.param5, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1); break; } case SMARTAI_TEMPLATE_CAGED_GO_PART: @@ -2977,16 +3072,16 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e) if (!go) return; //store hostage as id1 - AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_CREATURE, e.action.installTtemplate.param1, 10, 0, 0, 0); + AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_CREATURE, e.action.installTtemplate.param1, 10, 0, 0, 0); //store invoker as id2 - AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); + AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0); //signal hostage - AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 0); + AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 0); //when hostage raeched end point, give credit to invoker if (e.action.installTtemplate.param2) - AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0); + AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0); else - AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0); + AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0); break; } case SMARTAI_TEMPLATE_BASIC: @@ -2995,12 +3090,12 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e) } } -void SmartScript::AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask) +void SmartScript::AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask) { - mInstallEvents.push_back(CreateSmartEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, target_param4, phaseMask)); + mInstallEvents.push_back(CreateSmartEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, event_param6, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, target_param4, phaseMask)); } -SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask) +SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask) { SmartScriptHolder script; script.event.type = e; @@ -3009,6 +3104,7 @@ SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flag script.event.raw.param3 = event_param3; script.event.raw.param4 = event_param4; script.event.raw.param5 = event_param5; + script.event.raw.param6 = event_param6; script.event.event_phase_mask = phaseMask; script.event.event_flags = event_flags; script.event.event_chance = 100; @@ -4329,7 +4425,6 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!me || !me->IsEngaged()) return; - float range = static_cast(e.event.areaCasting.range); ThreatContainer::StorageType threatList = me->GetThreatMgr().GetThreatList(); for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i) { @@ -4338,7 +4433,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!target || target->IsPet() || target->IsTotem() || !target->IsNonMeleeSpellCast(false, false, true)) continue; - if (e.event.areaCasting.range && !me->IsWithinDistInMap(target, range)) + if (e.event.areaCasting.rangeMin && !(me->IsInRange(target, (float)e.event.areaCasting.rangeMin, (float)e.event.areaCasting.rangeMax))) continue; ProcessAction(e, target); @@ -4363,7 +4458,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui { if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid())) { - if (!(me->IsInRange(target, 0.f, (float)e.event.areaRange.range))) + if (!(me->IsInRange(target, (float)e.event.areaRange.rangeMin, (float)e.event.areaRange.rangeMax))) continue; ProcessAction(e, target); diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 72007ebc4..61a1d7efa 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -47,8 +47,8 @@ public: void GetTargets(ObjectVector& targets, SmartScriptHolder const& e, Unit* invoker = nullptr) const; void GetWorldObjectsInDist(ObjectVector& objects, float dist) const; void InstallTemplate(SmartScriptHolder const& e); - static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); - void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); + static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); + void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask); void SetPathId(uint32 id) { mPathId = id; } uint32 GetPathId() const { return mPathId; } WorldObject* GetBaseObject() const diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index fbd2b6078..5142145b8 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -223,24 +223,25 @@ void SmartAIMgr::LoadSmartAIFromDB() temp.event.raw.param3 = fields[10].Get(); temp.event.raw.param4 = fields[11].Get(); temp.event.raw.param5 = fields[12].Get(); + temp.event.raw.param6 = fields[13].Get(); - temp.action.type = (SMART_ACTION)fields[13].Get(); - temp.action.raw.param1 = fields[14].Get(); - temp.action.raw.param2 = fields[15].Get(); - temp.action.raw.param3 = fields[16].Get(); - temp.action.raw.param4 = fields[17].Get(); - temp.action.raw.param5 = fields[18].Get(); - temp.action.raw.param6 = fields[19].Get(); + temp.action.type = (SMART_ACTION)fields[14].Get(); + temp.action.raw.param1 = fields[15].Get(); + temp.action.raw.param2 = fields[16].Get(); + temp.action.raw.param3 = fields[17].Get(); + temp.action.raw.param4 = fields[18].Get(); + temp.action.raw.param5 = fields[19].Get(); + temp.action.raw.param6 = fields[20].Get(); - temp.target.type = (SMARTAI_TARGETS)fields[20].Get(); - temp.target.raw.param1 = fields[21].Get(); - temp.target.raw.param2 = fields[22].Get(); - temp.target.raw.param3 = fields[23].Get(); - temp.target.raw.param4 = fields[24].Get(); - temp.target.x = fields[25].Get(); - temp.target.y = fields[26].Get(); - temp.target.z = fields[27].Get(); - temp.target.o = fields[28].Get(); + temp.target.type = (SMARTAI_TARGETS)fields[21].Get(); + temp.target.raw.param1 = fields[22].Get(); + temp.target.raw.param2 = fields[23].Get(); + temp.target.raw.param3 = fields[24].Get(); + temp.target.raw.param4 = fields[25].Get(); + temp.target.x = fields[26].Get(); + temp.target.y = fields[27].Get(); + temp.target.z = fields[28].Get(); + temp.target.o = fields[29].Get(); //check target if (!IsTargetValid(temp)) @@ -781,6 +782,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_SET_SCALE: return sizeof(SmartAction::setScale); case SMART_ACTION_SUMMON_RADIAL: return sizeof(SmartAction::radialSummon); case SMART_ACTION_PLAY_SPELL_VISUAL: return sizeof(SmartAction::spellVisual); + case SMART_ACTION_FOLLOW_GROUP: return sizeof(SmartAction::followGroup); default: LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); @@ -977,6 +979,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsMinMaxValid(e, e.event.areaRange.repeatMin, e.event.areaRange.repeatMax)) return false; + if (!IsMinMaxValid(e, e.event.areaRange.rangeMin, e.event.areaRange.rangeMax)) + return false; + break; case SMART_EVENT_SPELLHIT: case SMART_EVENT_SPELLHIT_TARGET: @@ -1073,6 +1078,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsMinMaxValid(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax)) return false; + + if (!IsMinMaxValid(e, e.event.areaCasting.rangeMin, e.event.areaCasting.rangeMax)) + return false; break; case SMART_EVENT_PASSENGER_BOARDED: case SMART_EVENT_PASSENGER_REMOVED: @@ -1964,6 +1972,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SET_SCALE: case SMART_ACTION_SUMMON_RADIAL: case SMART_ACTION_PLAY_SPELL_VISUAL: + case SMART_ACTION_FOLLOW_GROUP: break; default: LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index e8b6b5947..b822ae989 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -523,7 +523,8 @@ struct SmartEvent uint32 max; uint32 repeatMin; uint32 repeatMax; - uint32 range; + uint32 rangeMin; + uint32 rangeMax; } areaCasting; struct @@ -532,7 +533,8 @@ struct SmartEvent uint32 max; uint32 repeatMin; uint32 repeatMax; - uint32 range; + uint32 rangeMin; + uint32 rangeMax; } areaRange; struct @@ -542,6 +544,7 @@ struct SmartEvent uint32 param3; uint32 param4; uint32 param5; + uint32 param6; } raw; }; @@ -739,8 +742,9 @@ enum SMART_ACTION SMART_ACTION_SET_SCALE = 227, // scale SMART_ACTION_SUMMON_RADIAL = 228, // summonEntry, summonDuration, repetitions, startAngle, stepAngle, dist SMART_ACTION_PLAY_SPELL_VISUAL = 229, // visualId, visualIdImpact + SMART_ACTION_FOLLOW_GROUP = 230, // followState, followType, dist - SMART_ACTION_AC_END = 230, // placeholder + SMART_ACTION_AC_END = 231, // placeholder }; enum class SmartActionSummonCreatureFlags @@ -1442,6 +1446,13 @@ struct SmartAction { uint32 visualId; } spellVisual; + + struct + { + uint32 followState; + uint32 followType; + uint32 dist; + } followGroup; //! Note for any new future actions //! All parameters must have type uint32 @@ -1880,6 +1891,16 @@ enum SmartCastFlags SMARTCAST_THREATLIST_NOT_SINGLE = 0x80 //Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment) }; +enum SmartFollowType +{ + FOLLOW_TYPE_CIRCLE = 1, // 360 degrees around leader, 90 degrees is the maximum angle + FOLLOW_TYPE_SEMI_CIRCLE_BEHIND = 2, // 180 degrees behind leader + FOLLOW_TYPE_SEMI_CIRCLE_FRONT = 3, // 180 degrees in front of leader + FOLLOW_TYPE_LINE = 4, // front -> back -> front -> back + FOLLOW_TYPE_COLUMN = 5, // left -> right -> left -> right + FOLLOW_TYPE_ANGULAR = 6 // geese-like formation 135 and 225 degrees behind leader +}; + // one line in DB is one event struct SmartScriptHolder { diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 3723778ea..eac4b5595 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -916,9 +916,49 @@ void Battleground::EndBattleground(PvPTeamId winnerTeamId) player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, player->GetMapId()); } + if (IsEventActive(EVENT_SPIRIT_OF_COMPETITION) && isBattleground()) + SpiritofCompetitionEvent(winnerTeamId); + sScriptMgr->OnBattlegroundEnd(this, GetTeamId(winnerTeamId)); } +bool Battleground::SpiritofCompetitionEvent(PvPTeamId winnerTeamId) +{ + // Everyone is eligible for tabard reward + for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + Player* player = itr->second; + bool questStatus = player->GetQuestStatus(QUEST_FLAG_PARTICIPANT) != QUEST_STATUS_REWARDED; + + if (player && questStatus) + player->CastSpell(player, SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT, true); + } + + // In case of a draw nobody get rewarded + if (winnerTeamId == PVP_TEAM_NEUTRAL) + return false; + + std::vector filteredPlayers; + + for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + Player* player = itr->second; + bool playerTeam = player->GetBgTeamId() == GetTeamId(winnerTeamId); + bool questStatus = player->GetQuestStatus(QUEST_FLAG_WINNER) != QUEST_STATUS_REWARDED; + + if (player && playerTeam && questStatus) + filteredPlayers.push_back(player); + } + + if (filteredPlayers.size()) + { + if (Player* wPlayer = filteredPlayers[rand() % filteredPlayers.size()]) + wPlayer->CastSpell(wPlayer, SPELL_SPIRIT_OF_COMPETITION_WINNER, true); + } + + return true; +} + uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const { //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill) diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index f077b3931..0a8cc6dc6 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -238,6 +238,15 @@ enum BattlegroundStartingEventsIds BG_STARTING_EVENT_FOURTH = 3 }; +enum SpiritOfCompetitionEvent +{ + EVENT_SPIRIT_OF_COMPETITION = 46, + QUEST_FLAG_PARTICIPANT = 12187, + QUEST_FLAG_WINNER = 12186, + SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT = 48163, + SPELL_SPIRIT_OF_COMPETITION_WINNER = 48164, +}; + constexpr auto BG_STARTING_EVENT_COUNT = 4; class ArenaLogEntryData @@ -338,6 +347,9 @@ public: [[nodiscard]] uint32 GetScriptId() const { return ScriptId; } [[nodiscard]] uint32 GetBonusHonorFromKill(uint32 kills) const; + // Spirit of Competition event + bool SpiritofCompetitionEvent(PvPTeamId winnerTeamId); + bool IsRandom() { return m_IsRandom; } // Set methods: diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 8a29cc2af..349132086 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -48,7 +48,7 @@ Pet::Pet(Player* owner, PetType type) : Guardian(nullptr, owner ? owner->GetGUID m_loading(false), m_petRegenTimer(PET_FOCUS_REGEN_INTERVAL), m_tempspellTarget(nullptr), - m_tempoldTarget(nullptr), + m_tempoldTarget(), m_tempspellIsPositive(false), m_tempspell(0) { @@ -710,7 +710,11 @@ void Pet::Update(uint32 diff) if (m_tempspell) { Unit* tempspellTarget = m_tempspellTarget; - Unit* tempoldTarget = m_tempoldTarget; + Unit* tempoldTarget = nullptr; + + if (!m_tempoldTarget.IsEmpty()) + tempoldTarget = ObjectAccessor::GetUnit(*this, m_tempoldTarget); + bool tempspellIsPositive = m_tempspellIsPositive; uint32 tempspell = m_tempspell; Unit* charmer = GetCharmerOrOwner(); @@ -783,7 +787,7 @@ void Pet::Update(uint32 diff) } } - m_tempoldTarget = nullptr; + m_tempoldTarget = ObjectGuid::Empty; m_tempspellIsPositive = false; } } @@ -793,7 +797,7 @@ void Pet::Update(uint32 diff) { m_tempspell = 0; m_tempspellTarget = nullptr; - m_tempoldTarget = nullptr; + m_tempoldTarget = ObjectGuid::Empty; m_tempspellIsPositive = false; Unit* victim = charmer->GetVictim(); @@ -1218,11 +1222,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) } case NPC_INFERNAL: { - float highAmt = petlevel / 11.0f; - float lowAmt = petlevel / 12.0f; - SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, lowAmt * lowAmt * lowAmt); - SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, highAmt * highAmt * highAmt); - + if (pInfo) + { + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(pInfo->min_dmg)); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(pInfo->max_dmg)); + } AddAura(SPELL_PET_AVOIDANCE, this); AddAura(SPELL_WARLOCK_PET_SCALING_05, this); AddAura(SPELL_INFERNAL_SCALING_01, this); @@ -2414,7 +2418,7 @@ void Pet::SetDisplayId(uint32 modelId) player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); } -void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarget, bool spellIsPositive) +void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, ObjectGuid oldTarget, bool spellIsPositive) { if (!spellid) return; @@ -2426,7 +2430,7 @@ void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarg m_tempspell = spellid; m_tempspellIsPositive = spellIsPositive; - if (oldTarget) + if (!oldTarget.IsEmpty()) m_tempoldTarget = oldTarget; } @@ -2435,7 +2439,7 @@ void Pet::ClearCastWhenWillAvailable() m_tempspellIsPositive = false; m_tempspell = 0; m_tempspellTarget = nullptr; - m_tempoldTarget = nullptr; + m_tempoldTarget = ObjectGuid::Empty; } void Pet::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */) diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 329672d8c..d32f04fc6 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -96,7 +96,7 @@ public: void LearnPetPassives(); void CastPetAuras(bool current); - void CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarget, bool spellIsPositive = false); + void CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, ObjectGuid oldTarget, bool spellIsPositive = false); void ClearCastWhenWillAvailable(); void RemoveSpellCooldown(uint32 spell_id, bool update /* = false */); @@ -157,10 +157,10 @@ protected: std::unique_ptr m_declinedname; - Unit* m_tempspellTarget; - Unit* m_tempoldTarget; - bool m_tempspellIsPositive; - uint32 m_tempspell; + Unit* m_tempspellTarget; + ObjectGuid m_tempoldTarget; + bool m_tempspellIsPositive; + uint32 m_tempspell; private: void SaveToDB(uint32, uint8, uint32) override // override of Creature::SaveToDB - must not be called diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index c442ff35c..3dc023eb4 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -39,6 +39,8 @@ MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMo MotionTransport::~MotionTransport() { + HashMapHolder::Remove(this); + ASSERT(_passengers.empty()); UnloadStaticPassengers(); } diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index c12a7f431..e6ca90428 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -388,22 +388,19 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) && unit->GetTypeId() == TYPEID_PLAYER && seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL) { - try + // Removed try catch + ABORT() here, and make it as simple condition check. + if (!_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE)) { - if (!_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE)) - ABORT(); - } - catch (...) - { - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy()!"); - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). not null: {}", _me ? 1 : 0); + // I assume SetCharmedBy should always be true. + // If not, let's log some debug info. + LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). not null: {}", _me ? 1 : 0); if (!_me) return false; - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Is: {}!", _me->IsInWorld()); - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Is2: {}!", _me->IsDuringRemoveFromWorld()); - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Unit {}!", _me->GetName()); - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). typeid: {}!", _me->GetTypeId()); - LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Unit {}, typeid: {}, in world: {}, duringremove: {} has wrong CharmType! Charmer {}, typeid: {}, in world: {}, duringremove: {}.", _me->GetName(), _me->GetTypeId(), _me->IsInWorld(), _me->IsDuringRemoveFromWorld(), unit->GetName(), unit->GetTypeId(), unit->IsInWorld(), unit->IsDuringRemoveFromWorld()); + LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Is: {}!", _me->IsInWorld()); + LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Is2: {}!", _me->IsDuringRemoveFromWorld()); + LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Unit {}!", _me->GetName()); + LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). typeid: {}!", _me->GetTypeId()); + LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Unit {}, typeid: {}, in world: {}, duringremove: {} has wrong CharmType! Charmer {}, typeid: {}, in world: {}, duringremove: {}.", _me->GetName(), _me->GetTypeId(), _me->IsInWorld(), _me->IsDuringRemoveFromWorld(), unit->GetName(), unit->GetTypeId(), unit->IsInWorld(), unit->IsDuringRemoveFromWorld()); return false; } } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 702f71441..491338d6f 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -491,7 +491,7 @@ void ObjectMgr::LoadGossipMenuItemsLocales() { Field* fields = result->Fetch(); - uint16 MenuID = fields[0].Get(); + uint32 MenuID = fields[0].Get(); uint16 OptionID = fields[1].Get(); LocaleConstant locale = GetLocaleByName(fields[2].Get()); @@ -9226,7 +9226,7 @@ void ObjectMgr::LoadGossipMenu() GossipMenus gMenu; - gMenu.MenuID = fields[0].Get(); + gMenu.MenuID = fields[0].Get(); gMenu.TextID = fields[1].Get(); if (!GetGossipText(gMenu.TextID)) @@ -9266,7 +9266,7 @@ void ObjectMgr::LoadGossipMenuItems() GossipMenuItems gMenuItem; - gMenuItem.MenuID = fields[0].Get(); + gMenuItem.MenuID = fields[0].Get(); gMenuItem.OptionID = fields[1].Get(); gMenuItem.OptionIcon = fields[2].Get(); gMenuItem.OptionText = fields[3].Get(); diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index f4b421369..102b2088c 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -530,7 +530,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe pet->SendPetAIReaction(guid1); } - pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, nullptr, tempspellIsPositive); + pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, ObjectGuid::Empty, tempspellIsPositive); } } else if (haspositiveeffect) @@ -566,7 +566,11 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe pet->SendPetAIReaction(guid1); } - pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, victim, tmpSpellIsPositive); + ObjectGuid oldTarget = ObjectGuid::Empty; + if (victim) + oldTarget = victim->GetGUID(); + + pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, oldTarget, tmpSpellIsPositive); } } } diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 0ac55cbf4..824810fda 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -645,7 +645,10 @@ enum AcoreStrings // End Level 3 list, continued at 1100 - // 600-704 - free + LANG_EVENT_STARTED = 600, + LANG_EVENT_STOPPED = 601, + + // 602-704 - free LANG_WAIT_BEFORE_SPEAKING = 705, LANG_NOT_EQUIPPED_ITEM = 706, diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index 67c7473db..6934add0c 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4560,6 +4560,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].TriggerSpell = 62585; // Mulgore Hatchling (fear) }); + // Poultryized! + ApplySpellFix({ 30504 }, [](SpellInfo* spellInfo) + { + spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_TAKE_DAMAGE; + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; diff --git a/src/server/scripts/Commands/cs_event.cpp b/src/server/scripts/Commands/cs_event.cpp index f1c1da6b7..cf7ef2123 100644 --- a/src/server/scripts/Commands/cs_event.cpp +++ b/src/server/scripts/Commands/cs_event.cpp @@ -152,11 +152,12 @@ public: GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList(); if (activeEvents.find(eventId) != activeEvents.end()) { - handler->PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE, uint16(eventId)); + handler->PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE, uint16(eventId), eventData.description.c_str()); handler->SetSentErrorMessage(true); return false; } + handler->PSendSysMessage(LANG_EVENT_STARTED, uint16(eventId), eventData.description.c_str()); sGameEventMgr->StartEvent(eventId, true); return true; } @@ -184,11 +185,12 @@ public: if (activeEvents.find(eventId) == activeEvents.end()) { - handler->PSendSysMessage(LANG_EVENT_NOT_ACTIVE, uint16(eventId)); + handler->PSendSysMessage(LANG_EVENT_NOT_ACTIVE, uint16(eventId), eventData.description.c_str()); handler->SetSentErrorMessage(true); return false; } + handler->PSendSysMessage(LANG_EVENT_STOPPED, uint16(eventId), eventData.description.c_str()); sGameEventMgr->StopEvent(eventId, true); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp index eb6ef3ddb..91fd97f24 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp @@ -31,8 +31,8 @@ uint32 const DragonspireMobs[3] = { NPC_BLACKHAND_DREADWEAVER, NPC_BLACKHAND_SUM enum EventIds { - EVENT_DARGONSPIRE_ROOM_STORE = 1, - EVENT_DARGONSPIRE_ROOM_CHECK = 2, + EVENT_DRAGONSPIRE_ROOM_STORE = 1, + EVENT_DRAGONSPIRE_ROOM_CHECK = 2, EVENT_SOLAKAR_WAVE = 3 }; @@ -352,7 +352,7 @@ public: if (data == AREATRIGGER_DRAGONSPIRE_HALL) { if (GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE) - Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_STORE, 1s); + Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_STORE, 1s); } break; case DATA_SOLAKAR_FLAMEWREATH: @@ -555,14 +555,14 @@ public: { switch (eventId) { - case EVENT_DARGONSPIRE_ROOM_STORE: + case EVENT_DRAGONSPIRE_ROOM_STORE: Dragonspireroomstore(); - Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3s); + Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s); break; - case EVENT_DARGONSPIRE_ROOM_CHECK: + case EVENT_DRAGONSPIRE_ROOM_CHECK: Dragonspireroomcheck(); if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)) - Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3s); + Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s); break; case EVENT_SOLAKAR_WAVE: SummonSolakarWave(CurrentSolakarWave); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp index 82ccd7030..6885556f3 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp @@ -38,11 +38,12 @@ enum Spells struct boss_maiden_of_virtue : public BossAI { - boss_maiden_of_virtue(Creature* creature) : BossAI(creature, DATA_MAIDEN) { } - - void Reset() override + boss_maiden_of_virtue(Creature* creature) : BossAI(creature, DATA_MAIDEN) { - BossAI::Reset(); + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } void JustEngagedWith(Unit* who) override @@ -82,18 +83,6 @@ struct boss_maiden_of_virtue : public BossAI BossAI::JustDied(killer); Talk(SAY_DEATH); } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - scheduler.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - DoMeleeAttackIfReady(); - } }; void AddSC_boss_maiden_of_virtue() diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp index 0c23ed406..4dd8dbb76 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_servant_quarters.cpp @@ -40,30 +40,11 @@ struct boss_servant_quarters : public BossAI void Reset() override { _scheduler.CancelAll(); - me->SetVisible(false); - me->SetReactState(REACT_PASSIVE); - me->SetFaction(FACTION_FRIENDLY); - _scheduler.Schedule(5s, [this](TaskContext context) - { - if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE) - { - me->SetVisible(true); - me->SetReactState(REACT_AGGRESSIVE); - me->RestoreFaction(); - } - else - { - context.Repeat(5s); - } - }); + if (me->GetEntry() == NPC_HYAKISS_THE_LURKER) { DoCastSelf(SPELL_SNEAK, true); } - if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry()) - { - me->DespawnOrUnsummon(1); - } } void JustEngagedWith(Unit* /*who*/) override diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index 908e42feb..287c4eab9 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -24,6 +24,7 @@ EndScriptData */ #include "Player.h" #include "ScriptMgr.h" +#include "TaskScheduler.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellInfo.h" @@ -112,748 +113,611 @@ void SummonCroneIfReady(InstanceScript* instance, Creature* creature) } } -class boss_dorothee : public CreatureScript +void DespawnAll(InstanceScript* instance) { -public: - boss_dorothee() : CreatureScript("boss_dorothee") { } - - CreatureAI* GetAI(Creature* creature) const override + if (Creature* dorothee = instance->GetCreature(DATA_DOROTHEE)) { - return GetKarazhanAI(creature); + dorothee->DespawnOrUnsummon(); } - - struct boss_dorotheeAI : public ScriptedAI + if (Creature* roar = instance->GetCreature(DATA_ROAR)) { - boss_dorotheeAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); - //this is kinda a big no-no. but it will prevent her from moving to chase targets. she should just cast her spells. in this case, since there is not really something to LOS her with or get out of range this would work. but a more elegant solution would be better - Initialize(); - instance = creature->GetInstanceScript(); - } - - void Initialize() - { - AggroTimer = 12000; - - WaterBoltTimer = 0; - FearTimer = 15000; - SummonTitoTimer = 41000; - - SummonedTito = false; - TitoDied = false; - } - - InstanceScript* instance; - - uint32 AggroTimer; - - uint32 WaterBoltTimer; - uint32 FearTimer; - uint32 SummonTitoTimer; - - bool SummonedTito; - bool TitoDied; - bool IntroDone = false; - - void Reset() override - { - Initialize(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->SetInCombatWithZone(); - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void SummonTito(); - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DOROTHEE_DEATH); - SummonCroneIfReady(instance, me); - me->DespawnOrUnsummon(); - } - - void AttackStart(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - if(!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - me->DespawnOrUnsummon(); - } - } - - void UpdateAI(uint32 diff) override - { - if(!IntroDone) - { - if(!me->IsInEvadeMode()) - { - Talk(SAY_DOROTHEE_AGGRO); - IntroDone = true; - } - } - - if (AggroTimer) - { - if (AggroTimer <= diff) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToPC(false); - me->SetInCombatWithZone(); - AggroTimer = 0; - } - else - AggroTimer -= diff; - } - - if (!UpdateVictim()) - return; - - if (WaterBoltTimer <= diff) - { - DoCast(SelectTarget(SelectTargetMethod::Random, 0), SPELL_WATERBOLT); - WaterBoltTimer = 1500; - } - else - WaterBoltTimer -= diff; - - if (FearTimer <= diff) - { - DoCastVictim(SPELL_SCREAM); - FearTimer = 30000; - } - else - FearTimer -= diff; - - if (!SummonedTito) - { - if (SummonTitoTimer <= diff) - SummonTito(); - else - SummonTitoTimer -= diff; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_tito : public CreatureScript -{ -public: - npc_tito() : CreatureScript("npc_tito") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + roar->DespawnOrUnsummon(); } - - struct npc_titoAI : public ScriptedAI + if (Creature* strawman = instance->GetCreature(DATA_STRAWMAN)) { - npc_titoAI(Creature* creature) : ScriptedAI(creature) { } - - ObjectGuid DorotheeGUID; - uint32 YipTimer; - - void Reset() override - { - DorotheeGUID.Clear(); - YipTimer = 10000; - } - - void JustEngagedWith(Unit* /*who*/) override - { - DoZoneInCombat(); - } - - void JustDied(Unit* /*killer*/) override - { - if (DorotheeGUID) - { - Creature* Dorothee = ObjectAccessor::GetCreature(*me, DorotheeGUID); - if (Dorothee && Dorothee->IsAlive()) - { - CAST_AI(boss_dorothee::boss_dorotheeAI, Dorothee->AI())->TitoDied = true; - Talk(SAY_DOROTHEE_TITO_DEATH, Dorothee); - } - } - me->DespawnOrUnsummon(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (YipTimer <= diff) - { - DoCastVictim(SPELL_YIPPING); - YipTimer = 10000; - } - else - YipTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; -}; - -void boss_dorothee::boss_dorotheeAI::SummonTito() -{ - if (Creature* pTito = me->SummonCreature(CREATURE_TITO, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + strawman->DespawnOrUnsummon(); + } + if (Creature* tinhead = instance->GetCreature(DATA_TINHEAD)) { - Talk(SAY_DOROTHEE_SUMMON); - CAST_AI(npc_tito::npc_titoAI, pTito->AI())->DorotheeGUID = me->GetGUID(); - pTito->AI()->AttackStart(me->GetVictim()); - SummonedTito = true; - TitoDied = false; + tinhead->DespawnOrUnsummon(); + } + if (Creature* tito = instance->GetCreature(DATA_TITO)) + { + tito->DespawnOrUnsummon(); } } -class boss_roar : public CreatureScript +struct boss_dorothee : public ScriptedAI { -public: - boss_roar() : CreatureScript("boss_roar") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_dorothee(Creature* creature) : ScriptedAI(creature) { - return GetKarazhanAI(creature); + SetCombatMovement(false); + //this is kinda a big no-no. but it will prevent her from moving to chase targets. she should just cast her spells. in this case, since there is not really something to LOS her with or get out of range this would work. but a more elegant solution would be better + Initialize(); + instance = creature->GetInstanceScript(); + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - struct boss_roarAI : public ScriptedAI + void ScheduleActivation() { - boss_roarAI(Creature* creature) : ScriptedAI(creature) + _scheduler.Schedule(16670ms, [this](TaskContext) { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 AggroTimer; - uint32 MangleTimer; - uint32 ShredTimer; - uint32 ScreamTimer; - - void Reset() override - { - AggroTimer = 16670; - MangleTimer = 5000; - ShredTimer = 10000; - ScreamTimer = 15000; - } - - void MoveInLineOfSight(Unit* who) override - - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - if(!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + if (Creature* roar = instance->GetCreature(DATA_ROAR)) { - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - me->DespawnOrUnsummon(); + roar->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + roar->SetImmuneToPC(false); + roar->SetInCombatWithZone(); } - } - - void AttackStart(Unit* who) override + }).Schedule(26300ms, [this](TaskContext) { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_ROAR_AGGRO); - DoZoneInCombat(); - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_ROAR_DEATH); - SummonCroneIfReady(instance, me); - me->DespawnOrUnsummon(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_ROAR_SLAY); - } - - void UpdateAI(uint32 diff) override - { - if (AggroTimer) + if (Creature* strawman = instance->GetCreature(DATA_STRAWMAN)) { - if (AggroTimer <= diff) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToPC(false); - me->SetInCombatWithZone(); - AggroTimer = 0; - } - else - AggroTimer -= diff; + strawman->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + strawman->SetImmuneToPC(false); + strawman->SetInCombatWithZone(); } - - if (!UpdateVictim()) - return; - - if (MangleTimer <= diff) + }).Schedule(34470ms, [this](TaskContext) + { + if (Creature* tinhead = instance->GetCreature(DATA_TINHEAD)) { - DoCastVictim(SPELL_MANGLE); - MangleTimer = urand(5000, 8000); + tinhead->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + tinhead->SetImmuneToPC(false); + tinhead->SetInCombatWithZone(); } - else - MangleTimer -= diff; - - if (ShredTimer <= diff) - { - DoCastVictim(SPELL_SHRED); - ShredTimer = urand(10000, 15000); - } - else - ShredTimer -= diff; - - if (ScreamTimer <= diff) - { - DoCastVictim(SPELL_FRIGHTENED_SCREAM); - ScreamTimer = urand(20000, 30000); - } - else - ScreamTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_strawman : public CreatureScript -{ -public: - boss_strawman() : CreatureScript("boss_strawman") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + }); } - struct boss_strawmanAI : public ScriptedAI + void Initialize() { - boss_strawmanAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 AggroTimer; - uint32 BrainBashTimer; - uint32 BrainWipeTimer; - - void Reset() override - { - AggroTimer = 26300; - BrainBashTimer = 5000; - BrainWipeTimer = 7000; - } - - void AttackStart(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - if(!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - me->DespawnOrUnsummon(); - } - } - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_STRAWMAN_AGGRO); - DoZoneInCombat(); - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* Spell) override - { - if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && (!(rand() % 10))) - { - /* - if (not direct damage(aoe, dot)) - return; - */ - - DoCast(me, SPELL_BURNING_STRAW, true); - } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_STRAWMAN_DEATH); - SummonCroneIfReady(instance, me); - me->DespawnOrUnsummon(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_STRAWMAN_SLAY); - } - - void UpdateAI(uint32 diff) override - { - if (AggroTimer) - { - if (AggroTimer <= diff) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToPC(false); - me->SetInCombatWithZone(); - AggroTimer = 0; - } - else - AggroTimer -= diff; - } - - if (!UpdateVictim()) - return; - - if (BrainBashTimer <= diff) - { - DoCastVictim(SPELL_BRAIN_BASH); - BrainBashTimer = 15000; - } - else - BrainBashTimer -= diff; - - if (BrainWipeTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_BRAIN_WIPE); - BrainWipeTimer = 20000; - } - else - BrainWipeTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_tinhead : public CreatureScript -{ -public: - boss_tinhead() : CreatureScript("boss_tinhead") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + titoDied = false; + _startIntro = false; } - struct boss_tinheadAI : public ScriptedAI + InstanceScript* instance; + bool titoDied; + + void Reset() override { - boss_tinheadAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 AggroTimer; - uint32 CleaveTimer; - uint32 RustTimer; - - uint8 RustCount; - - void Reset() override - { - AggroTimer = 34470; - CleaveTimer = 5000; - RustTimer = 15000; - - RustCount = 0; - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_TINHEAD_AGGRO); - DoZoneInCombat(); - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void AttackStart(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - if(!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - me->DespawnOrUnsummon(); - } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_TINHEAD_DEATH); - SummonCroneIfReady(instance, me); - me->DespawnOrUnsummon(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_TINHEAD_SLAY); - } - - void UpdateAI(uint32 diff) override - { - if (AggroTimer) - { - if (AggroTimer <= diff) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToPC(false); - me->SetInCombatWithZone(); - AggroTimer = 0; - } - else - AggroTimer -= diff; - } - - if (!UpdateVictim()) - return; - - if (CleaveTimer <= diff) - { - DoCastVictim(SPELL_CLEAVE); - CleaveTimer = 5000; - } - else - CleaveTimer -= diff; - - if (RustCount < 8) - { - if (RustTimer <= diff) - { - ++RustCount; - Talk(EMOTE_RUST); - DoCast(me, SPELL_RUST); - RustTimer = 6000; - } - else - RustTimer -= diff; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_crone : public CreatureScript -{ -public: - boss_crone() : CreatureScript("boss_crone") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); + Initialize(); } - struct boss_croneAI : public ScriptedAI + void JustEngagedWith(Unit* /*who*/) override { - boss_croneAI(Creature* creature) : ScriptedAI(creature) + _scheduler.Schedule(1ms, [this](TaskContext context) { - instance = creature->GetInstanceScript(); + DoCastRandomTarget(SPELL_WATERBOLT); + context.Repeat(1500ms); + }).Schedule(15s, [this](TaskContext context) + { + DoCastSelf(SPELL_SCREAM); + context.Repeat(30s); + }).Schedule(41s, [this](TaskContext) + { + SummonTito(); + }); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + } + + void SummonTito() + { + if (Creature* pTito = me->SummonCreature(CREATURE_TITO, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + { + Talk(SAY_DOROTHEE_SUMMON); + pTito->AI()->AttackStart(me->GetVictim()); + pTito->SetInCombatWithZone(); + titoDied = false; } + } - InstanceScript* instance; + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DOROTHEE_DEATH); + SummonCroneIfReady(instance, me); + me->DespawnOrUnsummon(); + } - uint32 CycloneTimer; - uint32 ChainLightningTimer; + void AttackStart(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; - void Reset() override + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - CycloneTimer = 22000; - ChainLightningTimer = 8000; - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_CRONE_SLAY); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_CRONE_AGGRO); - DoZoneInCombat(); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + DespawnAll(instance); } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_CRONE_DEATH); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (CycloneTimer <= diff) - { - if (Creature* Cyclone = DoSpawnCreature(CREATURE_CYCLONE, float(urand(0, 9)), float(urand(0, 9)), 0, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) - Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_VISUAL, true); - CycloneTimer = 22000; - } - else - CycloneTimer -= diff; - - if (ChainLightningTimer <= diff) - { - DoCastVictim(SPELL_CHAIN_LIGHTNING); - ChainLightningTimer = 8000; - } - else - ChainLightningTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_cyclone : public CreatureScript -{ -public: - npc_cyclone() : CreatureScript("npc_cyclone") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); } - struct npc_cycloneAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - npc_cycloneAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 MoveTimer; - - void Reset() override + if (!_startIntro) { - MoveTimer = 1000; + Talk(SAY_DOROTHEE_AGGRO); } - void JustEngagedWith(Unit* /*who*/) override { } - - void MoveInLineOfSight(Unit* /*who*/) override - + if (!_startIntro) { - } - - void UpdateAI(uint32 diff) override - { - if (!me->HasAura(SPELL_KNOCKBACK)) - DoCast(me, SPELL_KNOCKBACK, true); - - if (MoveTimer <= diff) + ScheduleActivation(); + _scheduler.Schedule(12s, [this](TaskContext) { - Position pos = me->GetRandomNearPosition(10); - me->GetMotionMaster()->MovePoint(0, pos); - MoveTimer = urand(3000, 5000); - } - else - MoveTimer -= diff; + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetImmuneToPC(false); + me->SetInCombatWithZone(); + }); + _startIntro = true; } - }; + DoMeleeAttackIfReady(); + + _scheduler.Update(diff); + } +private: + TaskScheduler _scheduler; + bool _startIntro; +}; + +struct npc_tito : public ScriptedAI +{ + npc_tito(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + void Reset() override { } + + void JustEngagedWith(Unit* /*who*/) override + { + _scheduler.Schedule(10s, [this](TaskContext context) + { + DoCastVictim(SPELL_YIPPING); + context.Repeat(10s); + }); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* Dorothee = instance->GetCreature(DATA_DOROTHEE)) + { + if (Dorothee->IsAlive()) + { + Talk(SAY_DOROTHEE_TITO_DEATH, Dorothee); + } + } + me->DespawnOrUnsummon(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } +private: + TaskScheduler _scheduler; +}; + +struct boss_roar : public ScriptedAI +{ + boss_roar(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + InstanceScript* instance; + + void Reset() override { } + + void MoveInLineOfSight(Unit* who) override + + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + DespawnAll(instance); + } + } + + void AttackStart(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_ROAR_AGGRO); + + _scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_MANGLE); + context.Repeat(5s, 8s); + }).Schedule(10s, [this](TaskContext context) + { + DoCastVictim(SPELL_SHRED); + context.Repeat(10s, 15s); + }).Schedule(15s, [this](TaskContext context) + { + //why is this also on roar??? same id + DoCastSelf(SPELL_FRIGHTENED_SCREAM); + context.Repeat(20s, 30s); + }); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_ROAR_DEATH); + SummonCroneIfReady(instance, me); + me->DespawnOrUnsummon(); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_ROAR_SLAY); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +private: + TaskScheduler _scheduler; +}; + +struct boss_strawman : public ScriptedAI +{ + boss_strawman(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + InstanceScript* instance; + + void Reset() override { } + + void AttackStart(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + DespawnAll(instance); + } + } + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_STRAWMAN_AGGRO); + + _scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_BRAIN_BASH); + context.Repeat(15s); + }).Schedule(7s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_BRAIN_WIPE); + context.Repeat(20s); + }); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* Spell) override + { + if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && (!(rand() % 10))) + { + /* + if (not direct damage(aoe, dot)) + return; + */ + + DoCast(me, SPELL_BURNING_STRAW, true); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_STRAWMAN_DEATH); + SummonCroneIfReady(instance, me); + me->DespawnOrUnsummon(); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_STRAWMAN_SLAY); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } +private: + TaskScheduler _scheduler; +}; + +struct boss_tinhead : public ScriptedAI +{ + boss_tinhead(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + InstanceScript* instance; + + void Reset() override + { + _rustCount = 0; + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_TINHEAD_AGGRO); + + _scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_CLEAVE); + context.Repeat(5s); + }).Schedule(15s, [this](TaskContext context) + { + if (_rustCount < 8) + { + ++_rustCount; + Talk(EMOTE_RUST); + DoCastSelf(SPELL_RUST); + context.Repeat(6s); + } + }); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + } + + void AttackStart(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + DespawnAll(instance); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_TINHEAD_DEATH); + SummonCroneIfReady(instance, me); + me->DespawnOrUnsummon(); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_TINHEAD_SLAY); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } +private: + TaskScheduler _scheduler; + uint8 _rustCount; +}; + +struct boss_crone : public ScriptedAI +{ + boss_crone(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + void Reset() override + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_CRONE_SLAY); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_CRONE_AGGRO); + DoZoneInCombat(); + + _scheduler.Schedule(22s, [this](TaskContext context) + { + if (Creature* Cyclone = DoSpawnCreature(CREATURE_CYCLONE, float(urand(0, 9)), float(urand(0, 9)), 0, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) + Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_VISUAL, true); + context.Repeat(22s); + }).Schedule(8s, [this](TaskContext context) + { + DoCastVictim(SPELL_CHAIN_LIGHTNING); + context.Repeat(8s); + }); + + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_CRONE_DEATH); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } +private: + TaskScheduler _scheduler; +}; + +struct npc_cyclone : public ScriptedAI +{ + npc_cyclone(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override { } + + void JustEngagedWith(Unit* /*who*/) override + { + _scheduler.Schedule(1s, [this](TaskContext context) + { + Position pos = me->GetRandomNearPosition(10); + me->GetMotionMaster()->MovePoint(0, pos); + context.Repeat(3s, 5s); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!me->HasAura(SPELL_KNOCKBACK)) + DoCast(me, SPELL_KNOCKBACK, true); + + _scheduler.Update(diff); + } +private: + TaskScheduler _scheduler; }; /**************************************/ @@ -875,9 +739,8 @@ enum RedRidingHood #define GOSSIP_GRANDMA "What phat lewtz you have grandmother?" -class npc_grandmother : public CreatureScript +struct npc_grandmother : public CreatureScript { -public: npc_grandmother() : CreatureScript("npc_grandmother") { } bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override @@ -903,139 +766,122 @@ public: } }; -class boss_bigbadwolf : public CreatureScript +struct boss_bigbadwolf : public ScriptedAI { -public: - boss_bigbadwolf() : CreatureScript("boss_bigbadwolf") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_bigbadwolf(Creature* creature) : ScriptedAI(creature) { - return GetKarazhanAI(creature); + instance = creature->GetInstanceScript(); + + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - struct boss_bigbadwolfAI : public ScriptedAI + InstanceScript* instance; + + ObjectGuid HoodGUID; + + void Reset() override { - boss_bigbadwolfAI(Creature* creature) : ScriptedAI(creature) + HoodGUID.Clear(); + _tempThreat = 0; + + _isChasing = false; + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_WOLF_AGGRO); + DoZoneInCombat(); + + _scheduler.Schedule(30s, [this](TaskContext context) { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 ChaseTimer; - uint32 FearTimer; - uint32 SwipeTimer; - - ObjectGuid HoodGUID; - float TempThreat; - - bool IsChasing; - - void Reset() override - { - ChaseTimer = 30000; - FearTimer = urand(25000, 35000); - SwipeTimer = 5000; - - HoodGUID.Clear(); - TempThreat = 0; - - IsChasing = false; - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_WOLF_AGGRO); - DoZoneInCombat(); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_WOLF_SLAY); - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - } - - void JustDied(Unit* /*killer*/) override - { - DoPlaySoundToSet(me, SOUND_WOLF_DEATH); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - - if (ChaseTimer <= diff) + if (!_isChasing) { - if (!IsChasing) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + Talk(SAY_WOLF_HOOD); + DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true); + _tempThreat = DoGetThreat(target); + if (_tempThreat) { - Talk(SAY_WOLF_HOOD); - DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true); - TempThreat = DoGetThreat(target); - if (TempThreat) - DoModifyThreatByPercent(target, -100); - HoodGUID = target->GetGUID(); - me->AddThreat(target, 1000000.0f); - ChaseTimer = 20000; - IsChasing = true; + DoModifyThreatByPercent(target, -100); } - } - else - { - IsChasing = false; - - if (Unit* target = ObjectAccessor::GetUnit(*me, HoodGUID)) - { - HoodGUID.Clear(); - if (DoGetThreat(target)) - DoModifyThreatByPercent(target, -100); - me->AddThreat(target, TempThreat); - TempThreat = 0; - } - - ChaseTimer = 40000; + HoodGUID = target->GetGUID(); + me->AddThreat(target, 1000000.0f); + _isChasing = true; + context.Repeat(20s); } } else - ChaseTimer -= diff; - - if (IsChasing) - return; - - if (FearTimer <= diff) { - DoCastVictim(SPELL_TERRIFYING_HOWL); - FearTimer = urand(25000, 35000); - } - else - FearTimer -= diff; + _isChasing = false; - if (SwipeTimer <= diff) - { - DoCastVictim(SPELL_WIDE_SWIPE); - SwipeTimer = urand(25000, 30000); + if (Unit* target = ObjectAccessor::GetUnit(*me, HoodGUID)) + { + HoodGUID.Clear(); + if (DoGetThreat(target)) + { + DoModifyThreatByPercent(target, -100); + } + me->AddThreat(target, _tempThreat); + _tempThreat = 0; + } + + context.Repeat(40s); } - else - SwipeTimer -= diff; - } - }; + }).Schedule(25s, 35s, [this](TaskContext context) + { + DoCastAOE(SPELL_TERRIFYING_HOWL); + context.Repeat(25s, 35s); + }).Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_WIDE_SWIPE); + context.Repeat(25s, 30s); + }); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_WOLF_SLAY); + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + } + + void JustDied(Unit* /*killer*/) override + { + DoPlaySoundToSet(me, SOUND_WOLF_DEATH); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + + if (_isChasing) + return; + + _scheduler.Update(diff); + } +private: + TaskScheduler _scheduler; + bool _isChasing; + float _tempThreat; }; /**********************************************/ @@ -1084,12 +930,31 @@ enum RAJPhase PHASE_BOTH = 2, }; +enum RAJGroups +{ + GROUP_COMBAT = 0, + GROUP_RP = 1 +}; + +enum RAJActions +{ + ACTION_DIED_ANNOUNCE = 0, + ACTION_PHASE_SET = 1, + ACTION_FAKING_DEATH = 2, + ACTION_COMBAT_SCHEDULE = 3, + ACTION_DO_RESURRECT = 4, + ACTION_EARLY_REVIVE = 5, + ACTION_CANCEL_COMBAT = 6 +}; + void PretendToDie(Creature* creature) { + creature->AI()->DoAction(ACTION_CANCEL_COMBAT); creature->InterruptNonMeleeSpells(true); creature->RemoveAllAuras(); creature->SetHealth(0); creature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + creature->SetReactState(REACT_PASSIVE); creature->GetMotionMaster()->MovementExpired(false); creature->GetMotionMaster()->MoveIdle(); creature->SetStandState(UNIT_STAND_STATE_DEAD); @@ -1098,9 +963,11 @@ void PretendToDie(Creature* creature) void Resurrect(Creature* target) { target->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + target->SetReactState(REACT_AGGRESSIVE); target->SetFullHealth(); target->SetStandState(UNIT_STAND_STATE_STAND); target->CastSpell(target, SPELL_RES_VISUAL, true); + target->AI()->DoAction(ACTION_COMBAT_SCHEDULE); if (target->GetVictim()) { target->GetMotionMaster()->MoveChase(target->GetVictim()); @@ -1110,563 +977,528 @@ void Resurrect(Creature* target) target->GetMotionMaster()->Initialize(); } -class boss_julianne : public CreatureScript +struct boss_julianne : public ScriptedAI { -public: - boss_julianne() : CreatureScript("boss_julianne") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_julianne(Creature* creature) : ScriptedAI(creature) { - return GetKarazhanAI(creature); + instance = creature->GetInstanceScript(); + isFakingDeath = false; } - struct boss_julianneAI : public ScriptedAI + InstanceScript* instance; + + uint32 phase; + + bool isFakingDeath; + bool summonedRomulo; + bool romuloDied; + + void Reset() override { - boss_julianneAI(Creature* creature) : ScriptedAI(creature) + phase = PHASE_JULIANNE; + + if (isFakingDeath) { - instance = creature->GetInstanceScript(); - EntryYellTimer = 1000; - AggroYellTimer = 10000; - IsFakingDeath = false; + Resurrect(me); + isFakingDeath = false; } - InstanceScript* instance; + summonedRomulo = false; + romuloDied = false; + me->SetImmuneToPC(true); - uint32 EntryYellTimer; - uint32 AggroYellTimer; - - ObjectGuid RomuloGUID; - - uint32 Phase; - - uint32 BlindingPassionTimer; - uint32 DevotionTimer; - uint32 EternalAffectionTimer; - uint32 PowerfulAttractionTimer; - uint32 SummonRomuloTimer; - uint32 ResurrectTimer; - uint32 DrinkPoisonTimer; - uint32 ResurrectSelfTimer; - - bool IsFakingDeath; - bool SummonedRomulo; - bool RomuloDead; - - void Reset() override - { - RomuloGUID.Clear(); - Phase = PHASE_JULIANNE; - - BlindingPassionTimer = 30000; - DevotionTimer = 15000; - EternalAffectionTimer = 25000; - PowerfulAttractionTimer = 5000; - SummonRomuloTimer = 10000; - DrinkPoisonTimer = 0; - ResurrectSelfTimer = 0; - - if (IsFakingDeath) - { - Resurrect(me); - IsFakingDeath = false; - } - - SummonedRomulo = false; - RomuloDead = false; - } - - void JustEngagedWith(Unit* /*who*/) override - { - DoZoneInCombat(); - } - - void AttackStart(Unit* who) override - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) override - - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* Spell) override - { - if (Spell->Id == SPELL_DRINK_POISON) - { - Talk(SAY_JULIANNE_DEATH01); - DrinkPoisonTimer = 2500; - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override; - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - } - - void JustDied(Unit*) override - { - Talk(SAY_JULIANNE_DEATH02); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_JULIANNE_SLAY); - } - - void UpdateAI(uint32 diff) override; - }; -}; - -class boss_romulo : public CreatureScript -{ -public: - boss_romulo() : CreatureScript("boss_romulo") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetKarazhanAI(creature); - } - - struct boss_romuloAI : public ScriptedAI - { - boss_romuloAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - EntryYellTimer = 8000; - AggroYellTimer = 15000; - } - - InstanceScript* instance; - - ObjectGuid JulianneGUID; - uint32 Phase; - - uint32 EntryYellTimer; - uint32 AggroYellTimer; - uint32 BackwardLungeTimer; - uint32 DaringTimer; - uint32 DeadlySwatheTimer; - uint32 PoisonThrustTimer; - uint32 ResurrectTimer; - - bool IsFakingDeath; - bool JulianneDead; - - void Reset() override - { - JulianneGUID.Clear(); - Phase = PHASE_ROMULO; - - BackwardLungeTimer = 15000; - DaringTimer = 20000; - DeadlySwatheTimer = 25000; - PoisonThrustTimer = 10000; - ResurrectTimer = 10000; - - IsFakingDeath = false; - JulianneDead = false; - } - - void JustReachedHome() override - { - me->DespawnOrUnsummon(); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage < me->GetHealth()) - return; - - //anything below only used if incoming damage will kill - - if (Phase == PHASE_ROMULO) - { - Talk(SAY_ROMULO_DEATH); - PretendToDie(me); - IsFakingDeath = true; - Phase = PHASE_BOTH; - - if (Creature* Julianne = (ObjectAccessor::GetCreature((*me), JulianneGUID))) - { - CAST_AI(boss_julianne::boss_julianneAI, Julianne->AI())->RomuloDead = true; - CAST_AI(boss_julianne::boss_julianneAI, Julianne->AI())->ResurrectSelfTimer = 10000; - } - - damage = 0; - return; - } - - if (Phase == PHASE_BOTH) - { - if (JulianneDead) - { - if (Creature* Julianne = (ObjectAccessor::GetCreature((*me), JulianneGUID))) - { - Julianne->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - Julianne->GetMotionMaster()->Clear(); - Julianne->setDeathState(JUST_DIED); - Julianne->CombatStop(true); - Julianne->GetThreatMgr().ClearAllThreat(); - Julianne->ReplaceAllDynamicFlags(UNIT_DYNFLAG_LOOTABLE); - } - return; - } - - if (Creature* Julianne = (ObjectAccessor::GetCreature((*me), JulianneGUID))) - { - PretendToDie(me); - IsFakingDeath = true; - CAST_AI(boss_julianne::boss_julianneAI, Julianne->AI())->ResurrectTimer = 10000; - CAST_AI(boss_julianne::boss_julianneAI, Julianne->AI())->RomuloDead = true; - damage = 0; - return; - } - } - - //LOG_ERROR("scripts", "boss_romuloAI: DamageTaken reach end of code, that should not happen."); - } - - void JustEngagedWith(Unit* /*who*/) override - { - DoZoneInCombat(); - Talk(SAY_ROMULO_AGGRO); - if (JulianneGUID) - { - Creature* Julianne = ObjectAccessor::GetCreature(*me, JulianneGUID); - if (Julianne && Julianne->GetVictim()) - { - me->AddThreat(Julianne->GetVictim(), 1.0f); - AttackStart(Julianne->GetVictim()); - } - } - } - - void MoveInLineOfSight(Unit* who) override - - { - if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void EnterEvadeMode(EvadeReason reason) override - { - ScriptedAI::EnterEvadeMode(reason); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_ROMULO_DEATH); - - instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_ROMULO_SLAY); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() || IsFakingDeath) - return; - - if (JulianneDead) - { - if (ResurrectTimer <= diff) - { - Creature* Julianne = (ObjectAccessor::GetCreature((*me), JulianneGUID)); - if (Julianne && CAST_AI(boss_julianne::boss_julianneAI, Julianne->AI())->IsFakingDeath) - { - Talk(SAY_ROMULO_RESURRECT); - Resurrect(Julianne); - CAST_AI(boss_julianne::boss_julianneAI, Julianne->AI())->IsFakingDeath = false; - JulianneDead = false; - ResurrectTimer = 10000; - } - } - else - ResurrectTimer -= diff; - } - - if (BackwardLungeTimer <= diff) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); - if (target && !me->HasInArc(M_PI, target)) - { - DoCast(target, SPELL_BACKWARD_LUNGE); - BackwardLungeTimer = urand(15000, 30000); - } - } - else - BackwardLungeTimer -= diff; - - if (DaringTimer <= diff) - { - DoCast(me, SPELL_DARING); - DaringTimer = urand(20000, 40000); - } - else - DaringTimer -= diff; - - if (DeadlySwatheTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_DEADLY_SWATHE); - DeadlySwatheTimer = urand(15000, 25000); - } - else - DeadlySwatheTimer -= diff; - - if (PoisonThrustTimer <= diff) - { - DoCastVictim(SPELL_POISON_THRUST); - PoisonThrustTimer = urand(10000, 20000); - } - else - PoisonThrustTimer -= diff; - - DoMeleeAttackIfReady(); - } - }; -}; - -void boss_julianne::boss_julianneAI::UpdateAI(uint32 diff) -{ - if (EntryYellTimer) - { - if (EntryYellTimer <= diff) + //intro sequence + _scheduler.Schedule(1s, [this](TaskContext) { Talk(SAY_JULIANNE_ENTER); - EntryYellTimer = 0; - } - else - EntryYellTimer -= diff; - } - - if (AggroYellTimer) - { - if (AggroYellTimer <= diff) + }).Schedule(10s, [this](TaskContext) { Talk(SAY_JULIANNE_AGGRO); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetFaction(FACTION_MONSTER_2); - AggroYellTimer = 0; - } - else - AggroYellTimer -= diff; + me->SetImmuneToPC(false); + me->SetInCombatWithZone(); + }); } - if (DrinkPoisonTimer) + void DoAction(int32 action) override { - //will do this 2secs after spell hit. this is time to display visual as expected - if (DrinkPoisonTimer <= diff) + switch(action) { - PretendToDie(me); - Phase = PHASE_ROMULO; - SummonRomuloTimer = 10000; - DrinkPoisonTimer = 0; + case ACTION_DIED_ANNOUNCE: + romuloDied = true; + break; + case ACTION_EARLY_REVIVE: + romuloDied = true; + _resurrectScheduler.Schedule(10s, [this](TaskContext) + { + Talk(SAY_JULIANNE_RESURRECT); + romuloDied = false; + }); + break; + case ACTION_PHASE_SET: + phase = PHASE_BOTH; + isFakingDeath = false; + break; + case ACTION_FAKING_DEATH: + isFakingDeath = false; + break; + case ACTION_COMBAT_SCHEDULE: + ScheduleCombat(); + break; + case ACTION_DO_RESURRECT: + _resurrectScheduler.Schedule(1s, [this](TaskContext) + { + if (Creature* Romulo = instance->GetCreature(DATA_ROMULO)) + { + Talk(SAY_JULIANNE_RESURRECT); + Resurrect(Romulo); + Romulo->AI()->DoAction(ACTION_FAKING_DEATH); + romuloDied = false; + } + }); + break; + case ACTION_CANCEL_COMBAT: + _scheduler.CancelGroup(GROUP_COMBAT); + break; } - else - DrinkPoisonTimer -= diff; } - if (Phase == PHASE_ROMULO && !SummonedRomulo) + void ScheduleCombat() { - if (SummonRomuloTimer <= diff) + _scheduler.Schedule(30s, GROUP_COMBAT, [this](TaskContext context) { - if (Creature* pRomulo = me->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR * 2 * IN_MILLISECONDS)) + DoCastRandomTarget(SPELL_BLINDING_PASSION); + context.Repeat(30s, 45s); + }).Schedule(15s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastSelf(SPELL_DEVOTION); + context.Repeat(15s, 45s); + }).Schedule(5s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_POWERFUL_ATTRACTION); + context.Repeat(5s, 30s); + }).Schedule(25s, GROUP_COMBAT, [this](TaskContext context) + { + if (urand(0, 1) && summonedRomulo) { - RomuloGUID = pRomulo->GetGUID(); - CAST_AI(boss_romulo::boss_romuloAI, pRomulo->AI())->JulianneGUID = me->GetGUID(); - CAST_AI(boss_romulo::boss_romuloAI, pRomulo->AI())->Phase = PHASE_ROMULO; - DoZoneInCombat(pRomulo); - - pRomulo->SetFaction(FACTION_MONSTER_2); + if (Creature* Romulo = instance->GetCreature(DATA_ROMULO)) + { + if (Romulo->IsAlive() && !romuloDied) + { + DoCast(Romulo, SPELL_ETERNAL_AFFECTION); + } + } } - SummonedRomulo = true; - } - else - SummonRomuloTimer -= diff; - } - - if (ResurrectSelfTimer) - { - if (ResurrectSelfTimer <= diff) - { - Resurrect(me); - Phase = PHASE_BOTH; - IsFakingDeath = false; - - if (me->GetVictim()) - AttackStart(me->GetVictim()); - - ResurrectSelfTimer = 0; - ResurrectTimer = 1000; - } - else - ResurrectSelfTimer -= diff; - } - - if (!UpdateVictim() || IsFakingDeath) - return; - - if (RomuloDead) - { - if (ResurrectTimer <= diff) - { - Creature* Romulo = (ObjectAccessor::GetCreature((*me), RomuloGUID)); - if (Romulo && CAST_AI(boss_romulo::boss_romuloAI, Romulo->AI())->IsFakingDeath) + else { - Talk(SAY_JULIANNE_RESURRECT); - Resurrect(Romulo); - CAST_AI(boss_romulo::boss_romuloAI, Romulo->AI())->IsFakingDeath = false; - RomuloDead = false; - ResurrectTimer = 10000; + DoCast(me, SPELL_ETERNAL_AFFECTION); } - } - else - ResurrectTimer -= diff; + context.Repeat(45s, 60s); + }); } - if (BlindingPassionTimer <= diff) + void JustEngagedWith(Unit* /*who*/) override { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_BLINDING_PASSION); - BlindingPassionTimer = urand(30000, 45000); + ScheduleCombat(); } - else - BlindingPassionTimer -= diff; - if (DevotionTimer <= diff) + void AttackStart(Unit* who) override { - DoCast(me, SPELL_DEVOTION); - DevotionTimer = urand(15000, 45000); - } - else - DevotionTimer -= diff; - - if (PowerfulAttractionTimer <= diff) - { - DoCast(SelectTarget(SelectTargetMethod::Random, 0), SPELL_POWERFUL_ATTRACTION); - PowerfulAttractionTimer = urand(5000, 30000); - } - else - PowerfulAttractionTimer -= diff; - - if (EternalAffectionTimer <= diff) - { - if (urand(0, 1) && SummonedRomulo) - { - Creature* Romulo = (ObjectAccessor::GetCreature((*me), RomuloGUID)); - if (Romulo && Romulo->IsAlive() && !RomuloDead) - DoCast(Romulo, SPELL_ETERNAL_AFFECTION); - } - else DoCast(me, SPELL_ETERNAL_AFFECTION); - - EternalAffectionTimer = urand(45000, 60000); - } - else - EternalAffectionTimer -= diff; - - DoMeleeAttackIfReady(); -} - -void boss_julianne::boss_julianneAI::DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType, SpellSchoolMask) -{ - if (damage < me->GetHealth()) - return; - - //anything below only used if incoming damage will kill - - if (Phase == PHASE_JULIANNE) - { - damage = 0; - - //this means already drinking, so return - if (IsFakingDeath) + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) return; - me->InterruptNonMeleeSpells(true); - DoCast(me, SPELL_DRINK_POISON); - - IsFakingDeath = true; - //IS THIS USEFULL? Creature* Julianne = (ObjectAccessor::GetCreature((*me), JulianneGUID)); - return; + ScriptedAI::AttackStart(who); } - if (Phase == PHASE_ROMULO) + void MoveInLineOfSight(Unit* who) override { - //LOG_ERROR("scripts", "boss_julianneAI: cannot take damage in PHASE_ROMULO, why was i here?"); - damage = 0; - return; + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); } - if (Phase == PHASE_BOTH) + void JustReachedHome() override { - //if this is true then we have to kill romulo too - if (RomuloDead) + me->DespawnOrUnsummon(); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* Spell) override + { + if (Spell->Id == SPELL_DRINK_POISON) { - if (Creature* Romulo = (ObjectAccessor::GetCreature((*me), RomuloGUID))) + Talk(SAY_JULIANNE_DEATH01); + _scheduler.CancelGroup(GROUP_COMBAT); + _scheduler.Schedule(2500ms, GROUP_RP, [this](TaskContext) { - Romulo->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - Romulo->GetMotionMaster()->Clear(); - Romulo->setDeathState(JUST_DIED); - Romulo->CombatStop(true); - Romulo->GetThreatMgr().ClearAllThreat(); - Romulo->ReplaceAllDynamicFlags(UNIT_DYNFLAG_LOOTABLE); - } + //will do this 2secs after spell hit. this is time to display visual as expected + PretendToDie(me); + phase = PHASE_ROMULO; + _scheduler.Schedule(10s, GROUP_RP, [this](TaskContext) + { + if (Creature* pRomulo = me->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR * 2 * IN_MILLISECONDS)) + { + pRomulo->AI()->DoAction(ACTION_PHASE_SET); + pRomulo->SetInCombatWithZone(); + } + summonedRomulo = true; + }); + }); + } + } + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage < me->GetHealth()) + { return; } - //if not already returned, then romulo is alive and we can pretend die - if (Creature* Romulo = (ObjectAccessor::GetCreature((*me), RomuloGUID))) + //anything below only used if incoming damage will kill + + if (phase == PHASE_JULIANNE) { - PretendToDie(me); - IsFakingDeath = true; - CAST_AI(boss_romulo::boss_romuloAI, Romulo->AI())->ResurrectTimer = 10000; - CAST_AI(boss_romulo::boss_romuloAI, Romulo->AI())->JulianneDead = true; + damage = 0; + + //this means already drinking, so return + if (isFakingDeath) + { + return; + } + + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_DRINK_POISON); + + me->GetMotionMaster()->Clear(); + + isFakingDeath = true; + return; + } + + if (phase == PHASE_ROMULO) + { + //LOG_ERROR("scripts", "boss_julianneAI: cannot take damage in PHASE_ROMULO, why was i here?"); damage = 0; return; } + + if (phase == PHASE_BOTH) + { + //if this is true then we have to kill romulo too + if (romuloDied) + { + if (Creature* Romulo = instance->GetCreature(DATA_ROMULO)) + { + _scheduler.CancelAll(); + _resurrectScheduler.CancelAll(); + Romulo->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + Romulo->GetMotionMaster()->Clear(); + Romulo->setDeathState(JUST_DIED); + Romulo->CombatStop(true); + Romulo->GetThreatMgr().ClearAllThreat(); + Romulo->ReplaceAllDynamicFlags(UNIT_DYNFLAG_LOOTABLE); + //this does not seem to really work - the lootable dynamic flags + } + + return; + } + + //if not already returned, then romulo is alive and we can pretend die + if (Creature* Romulo = instance->GetCreature(DATA_ROMULO)) + { + PretendToDie(me); + isFakingDeath = true; + Romulo->AI()->DoAction(ACTION_EARLY_REVIVE); + _scheduler.Schedule(10050ms, [this](TaskContext) + { + Resurrect(me); + isFakingDeath = false; + }); + damage = 0; + return; + } + } + //LOG_ERROR("scripts", "boss_julianneAI: DamageTaken reach end of code, that should not happen."); } - //LOG_ERROR("scripts", "boss_julianneAI: DamageTaken reach end of code, that should not happen."); -} + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + me->DespawnOrUnsummon(); + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + } + } + + void JustDied(Unit*) override + { + Talk(SAY_JULIANNE_DEATH02); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_JULIANNE_SLAY); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + _resurrectScheduler.Update(diff); + + if (!UpdateVictim()) + { + return; + } + + if (!isFakingDeath) + { + DoMeleeAttackIfReady(); + } + } +private: + TaskScheduler _scheduler; + TaskScheduler _resurrectScheduler; +}; + +struct boss_romulo : public ScriptedAI +{ + boss_romulo(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); //not necessary + } + + InstanceScript* instance; + + uint32 phase; + + bool isFakingDeath; + bool julianneDead; + + void Reset() override + { + phase = PHASE_ROMULO; + + isFakingDeath = false; + julianneDead = false; + } + + void DoAction(int32 action) override + { + switch(action) + { + case ACTION_DIED_ANNOUNCE: + julianneDead = true; + break; + case ACTION_EARLY_REVIVE: + julianneDead = true; + _resurrectScheduler.Schedule(10s, [this](TaskContext) + { + Talk(SAY_ROMULO_RESURRECT); + julianneDead = false; + }); + break; + case ACTION_PHASE_SET: + phase = PHASE_ROMULO; + break; + case ACTION_FAKING_DEATH: + isFakingDeath = false; + break; + case ACTION_COMBAT_SCHEDULE: + ScheduleCombat(); + break; + case ACTION_CANCEL_COMBAT: + _scheduler.CancelGroup(GROUP_COMBAT); + break; + } + } + + void JustReachedHome() override + { + me->DespawnOrUnsummon(); + if (Creature* julianne = instance->GetCreature(DATA_JULIANNE)) + { + julianne->DespawnOrUnsummon(); + } + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage < me->GetHealth()) + return; + + //anything below only used if incoming damage will kill + + if (phase == PHASE_ROMULO) + { + Talk(SAY_ROMULO_DEATH); + PretendToDie(me); + isFakingDeath = true; + phase = PHASE_BOTH; + + if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) + { + Julianne->AI()->DoAction(ACTION_DIED_ANNOUNCE); + //resurrect julianne + _scheduler.Schedule(10s, GROUP_RP, [this](TaskContext) + { + if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) + { + Resurrect(Julianne); + Julianne->AI()->DoAction(ACTION_PHASE_SET); + Julianne->AI()->DoAction(ACTION_DO_RESURRECT); + if (Julianne->GetVictim()) + { + AttackStart(Julianne->GetVictim()); + } + } + }); + } + + damage = 0; + return; + } + + if (phase == PHASE_BOTH) + { + if (julianneDead) + { + if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) + { + _scheduler.CancelAll(); + _resurrectScheduler.CancelAll(); + Julianne->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + Julianne->GetMotionMaster()->Clear(); + Julianne->setDeathState(JUST_DIED); + Julianne->CombatStop(true); + Julianne->GetThreatMgr().ClearAllThreat(); + Julianne->ReplaceAllDynamicFlags(UNIT_DYNFLAG_LOOTABLE); + //this does not seem to really work + } + return; + } + + if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) + { + PretendToDie(me); + isFakingDeath = true; + Julianne->AI()->DoAction(ACTION_EARLY_REVIVE); + _scheduler.Schedule(10050ms, [this](TaskContext) + { + Resurrect(me); + isFakingDeath = false; + }); + damage = 0; + return; + } + } + //LOG_ERROR("scripts", "boss_romuloAI: DamageTaken reach end of code, that should not happen."); + } + + void ScheduleCombat() + { + if (Creature* Julianne = instance->GetCreature(DATA_JULIANNE)) + { + if (Julianne->GetVictim()) + { + me->AddThreat(Julianne->GetVictim(), 1.0f); + AttackStart(Julianne->GetVictim()); + } + } + + _scheduler.Schedule(15s, GROUP_COMBAT, [this](TaskContext context) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true)) + { + if (target && !me->HasInArc(M_PI, target)) + { + DoCast(target, SPELL_BACKWARD_LUNGE); + context.Repeat(15s, 30s); + } + } + }).Schedule(20s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastSelf(SPELL_DARING); + context.Repeat(20s, 40s); + }).Schedule(25s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_DEADLY_SWATHE); + context.Repeat(15s, 25s); + }).Schedule(10s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastVictim(SPELL_POISON_THRUST); + context.Repeat(10s, 20s); + }); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_ROMULO_AGGRO); + + ScheduleCombat(); + } + + void MoveInLineOfSight(Unit* who) override + { + if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void EnterEvadeMode(EvadeReason reason) override + { + ScriptedAI::EnterEvadeMode(reason); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, FAIL); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_ROMULO_DEATH); + + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); + } + + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_ROMULO_SLAY); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + _resurrectScheduler.Update(diff); + + if (!UpdateVictim()) + { + return; + } + + if (!isFakingDeath) + { + DoMeleeAttackIfReady(); + } + } +private: + TaskScheduler _scheduler; + TaskScheduler _resurrectScheduler; +}; void AddSC_bosses_opera() { - new boss_dorothee(); - new boss_strawman(); - new boss_tinhead(); - new boss_roar(); - new boss_crone(); - new npc_tito(); - new npc_cyclone(); + RegisterKarazhanCreatureAI(boss_dorothee); + RegisterKarazhanCreatureAI(boss_strawman); + RegisterKarazhanCreatureAI(boss_tinhead); + RegisterKarazhanCreatureAI(boss_roar); + RegisterKarazhanCreatureAI(boss_crone); + RegisterKarazhanCreatureAI(npc_tito); + RegisterKarazhanCreatureAI(npc_cyclone); new npc_grandmother(); - new boss_bigbadwolf(); - new boss_julianne(); - new boss_romulo(); + RegisterKarazhanCreatureAI(boss_bigbadwolf); + RegisterKarazhanCreatureAI(boss_julianne); + RegisterKarazhanCreatureAI(boss_romulo); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index f5aa16bf1..4c98ae614 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -35,7 +35,14 @@ const Position OptionalSpawn[] = ObjectData const creatureData[] = { { NPC_ATTUMEN_THE_HUNTSMAN, DATA_ATTUMEN }, - { NPC_MIDNIGHT, DATA_MIDNIGHT } + { NPC_MIDNIGHT, DATA_MIDNIGHT }, + { NPC_DOROTHEE, DATA_DOROTHEE }, + { NPC_TITO, DATA_TITO }, + { NPC_ROAR, DATA_ROAR }, + { NPC_STRAWMAN, DATA_STRAWMAN }, + { NPC_TINHEAD, DATA_TINHEAD }, + { NPC_ROMULO, DATA_ROMULO }, + { NPC_JULIANNE, DATA_JULIANNE }, }; class instance_karazhan : public InstanceMapScript diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h index dd71b2b8b..86cf16fbe 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h @@ -40,11 +40,10 @@ enum KZDataTypes DATA_MALCHEZZAR = 10, DATA_NIGHTBANE = 11, DATA_SERVANT_QUARTERS = 12, - DATA_SELECTED_RARE = 13, - DATA_OPERA_OZ_DEATHCOUNT = 14, - DATA_KILREK = 15, + DATA_OPERA_OZ_DEATHCOUNT = 13, + DATA_KILREK = 14, - MAX_ENCOUNTERS = 16, + MAX_ENCOUNTERS = 15, DATA_GO_CURTAINS = 18, DATA_GO_STAGEDOORLEFT = 19, @@ -67,7 +66,17 @@ enum KZDataTypes DATA_CHESS_REINIT_PIECES = 34, DATA_CHESS_GAME_PHASE = 35, DATA_ECHO_OF_MEDIVH = 36, - DATA_DUST_COVERED_CHEST = 37 + DATA_DUST_COVERED_CHEST = 37, + + // Specific Opera Data + DATA_DOROTHEE = 38, + DATA_ROMULO = 39, + DATA_JULIANNE = 40, + + DATA_ROAR = 41, + DATA_STRAWMAN = 42, + DATA_TINHEAD = 43, + DATA_TITO = 44 }; enum KZOperaEvents @@ -101,6 +110,13 @@ enum KZCreatures NPC_KILREK = 17229, NPC_RELAY = 17645, NPC_BARNES = 16812, + NPC_DOROTHEE = 17535, + NPC_TITO = 17548, + NPC_ROMULO = 17533, + NPC_JULIANNE = 17534, + NPC_ROAR = 17546, + NPC_STRAWMAN = 17543, + NPC_TINHEAD = 17547, // Chess Event NPC_ECHO_OF_MEDIVH = 16816, diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_lieutenant_drake.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_lieutenant_drake.cpp index afa6f6eb8..196393abd 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_lieutenant_drake.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_lieutenant_drake.cpp @@ -112,10 +112,6 @@ struct boss_lieutenant_drake : public BossAI { _JustDied(); Talk(SAY_DEATH); - if (InstanceScript* instance = me->GetInstanceScript()) - { - instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_DRAKE_KILLED); - } } void MovementInform(uint32 type, uint32 point) override diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp index 00725de54..5d698d960 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp @@ -257,7 +257,7 @@ public: { switch (param) { - case ENCOUNTER_PROGRESS_DRAKE_KILLED: + case ENCOUNTER_PROGRESS_BARRELS: events.ScheduleEvent(EVENT_OPEN_DOORS, 0); events.ScheduleEvent(EVENT_START_WP, 3000); break; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.h b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.h index 343453a0b..57a692b1a 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.h @@ -74,7 +74,7 @@ enum MiscIds ENCOUNTER_PROGRESS_NONE = 0, ENCOUNTER_PROGRESS_BARRELS = 1, - ENCOUNTER_PROGRESS_DRAKE_KILLED = 2, + //ENCOUNTER_PROGRESS_DRAKE_KILLED = 2, No longer used. Kept as reference as DB might rely on the existing order. ENCOUNTER_PROGRESS_THRALL_ARMORED = 3, ENCOUNTER_PROGRESS_AMBUSHES_1 = 4, ENCOUNTER_PROGRESS_SKARLOC_KILLED = 5, diff --git a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp index 3bc60dbe4..dc7bb1607 100644 --- a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp +++ b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp @@ -39,6 +39,8 @@ EndContentData */ #include "ScriptedCreature.h" #include "ScriptedEscortAI.h" #include "ScriptedGossip.h" +#include "SpellAuras.h" +#include "SpellScript.h" /*###### ## npc_draenei_survivor @@ -522,6 +524,55 @@ public: } }; +enum NestlewoodOwlkin +{ + NPC_NESTLEWOOD_OWLKIN_ENTRY = 16518, + NPC_INOCULATED_OWLKIN_ENTRY = 16534, + + TALK_OWLKIN = 0 +}; + +class spell_inoculate_nestlewood_owlkin : public AuraScript +{ +public: + PrepareAuraScript(spell_inoculate_nestlewood_owlkin) + + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* owlkin = GetTarget()->ToCreature()) + if (owlkin->GetEntry() == NPC_NESTLEWOOD_OWLKIN_ENTRY) + owlkin->SetFacingToObject(GetCaster()); + } + + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + return; + + if (Creature* owlkin = GetTarget()->ToCreature()) + { + if (owlkin->GetEntry() == NPC_NESTLEWOOD_OWLKIN_ENTRY) + { + Player* caster = GetCaster()->ToPlayer(); + if (owlkin->UpdateEntry(NPC_INOCULATED_OWLKIN_ENTRY)) + { + owlkin->AI()->Talk(TALK_OWLKIN); + owlkin->GetMotionMaster()->MoveRandom(15.0f); + owlkin->SetUnitFlag(UnitFlags(UNIT_FLAG_IMMUNE_TO_PC)); + owlkin->DespawnOrUnsummon(15s, 0s); + caster->RewardPlayerAndGroupAtEvent(NPC_INOCULATED_OWLKIN_ENTRY, caster); + } + } + } + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_inoculate_nestlewood_owlkin::HandleEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_inoculate_nestlewood_owlkin::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } +}; + void AddSC_azuremyst_isle() { new npc_draenei_survivor(); @@ -531,4 +582,5 @@ void AddSC_azuremyst_isle() new go_ravager_cage(); new npc_stillpine_capitive(); new go_bristlelimb_cage(); + RegisterSpellScript(spell_inoculate_nestlewood_owlkin); } diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index e35224093..dcf3418b3 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -702,7 +702,6 @@ public: } } - me->RemoveVehicleKit(); // not Crash (; events.ScheduleEvent(EVENT_TAKE_OFF, 2s); me->CastSpell(passenger, VEHICLE_SPELL_PARACHUTE, true); } diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp index 08f71aa9f..0c740520e 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp @@ -73,6 +73,13 @@ struct boss_harbinger_skyriss : public BossAI }); } + void EnterEvadeMode(EvadeReason why) override + { + BossAI::EnterEvadeMode(why); + instance->DoRespawnCreature(DATA_WARDEN_MELLICHAR, true); + me->DespawnOrUnsummon(); + } + void JustEngagedWith(Unit* /*who*/) override { Talk(SAY_AGGRO); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 6a24eb84f..822e05a88 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4917,6 +4917,87 @@ class spell_gen_curse_of_pain : public AuraScript } }; +enum SpiritofCompetition +{ + // Spells + SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT_EFFECT = 48056, + SPELL_SPIRIT_OF_COMPETITION_WINNER_EFFECT = 48057, + // Mail + MAIL_THE_COMPETITIORS_TABARD = 195, + MAIL_A_GOLD_MEDALLION = 196, + // NPC + NPC_SPIRIT_OF_COMPETITION = 27217, + // Items + ITEM_COMPETITORS_TABARD = 36941, + ITEM_GOLD_MEDALLION = 37297, +}; + +class spell_gen_spirit_of_competition_participant : public SpellScript +{ + PrepareSpellScript(spell_gen_spirit_of_competition_participant); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT_EFFECT }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Player* player = GetHitPlayer()) + { + player->CastSpell(player, SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT_EFFECT, true); + + Item* item = Item::CreateItem(ITEM_COMPETITORS_TABARD, 1); + if (!item) + return; + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + MailDraft(MAIL_THE_COMPETITIORS_TABARD) + .AddItem(item) + .SendMailTo(trans, player, MailSender(NPC_SPIRIT_OF_COMPETITION), MAIL_CHECK_MASK_HAS_BODY); + CharacterDatabase.CommitTransaction(trans); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_spirit_of_competition_participant::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +class spell_gen_spirit_of_competition_winner : public SpellScript +{ + PrepareSpellScript(spell_gen_spirit_of_competition_winner); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SPIRIT_OF_COMPETITION_WINNER_EFFECT }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Player* player = GetHitPlayer()) + { + player->CastSpell(player, SPELL_SPIRIT_OF_COMPETITION_WINNER_EFFECT, true); + + Item* item = Item::CreateItem(ITEM_GOLD_MEDALLION, 1); + if (!item) + return; + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + MailDraft(MAIL_A_GOLD_MEDALLION) + .AddItem(item) + .SendMailTo(trans, player, MailSender(NPC_SPIRIT_OF_COMPETITION), MAIL_CHECK_MASK_HAS_BODY); + CharacterDatabase.CommitTransaction(trans); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gen_spirit_of_competition_winner::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + void AddSC_generic_spell_scripts() { RegisterSpellScript(spell_silithyst); @@ -5063,4 +5144,6 @@ void AddSC_generic_spell_scripts() RegisterSpellScript(spell_gen_threshalisk_charge); RegisterSpellScript(spell_gen_shriveling_gaze); RegisterSpellScript(spell_gen_curse_of_pain); + RegisterSpellScript(spell_gen_spirit_of_competition_participant); + RegisterSpellScript(spell_gen_spirit_of_competition_winner); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 8a5393942..a1cc175c8 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -2975,8 +2975,9 @@ class spell_item_nigh_invulnerability : public SpellScript enum Poultryzer { - SPELL_POULTRYIZER_SUCCESS = 30501, - SPELL_POULTRYIZER_BACKFIRE = 30504, + SPELL_POULTRYIZER_SUCCESS_1 = 30501, + SPELL_POULTRYIZER_SUCCESS_2 = 30504, // malfunction + SPELL_POULTRYIZER_BACKFIRE = 30506, // Not removed on damage }; class spell_item_poultryizer : public SpellScript @@ -2985,13 +2986,22 @@ class spell_item_poultryizer : public SpellScript bool Validate(SpellInfo const* /*spell*/) override { - return ValidateSpellInfo({ SPELL_POULTRYIZER_SUCCESS, SPELL_POULTRYIZER_BACKFIRE }); + return ValidateSpellInfo({ SPELL_POULTRYIZER_SUCCESS_1, SPELL_POULTRYIZER_SUCCESS_2, SPELL_POULTRYIZER_BACKFIRE }); } void HandleDummy(SpellEffIndex /* effIndex */) { if (GetCastItem() && GetHitUnit()) - GetCaster()->CastSpell(GetHitUnit(), roll_chance_i(80) ? SPELL_POULTRYIZER_SUCCESS : SPELL_POULTRYIZER_BACKFIRE, true, GetCastItem()); + { + if (roll_chance_i(80)) + { + GetCaster()->CastSpell(GetHitUnit(), roll_chance_i(80) ? SPELL_POULTRYIZER_SUCCESS_1 : SPELL_POULTRYIZER_SUCCESS_2, true, GetCastItem()); + } + else + { + GetCaster()->CastSpell(GetCaster(), SPELL_POULTRYIZER_BACKFIRE, true, GetCastItem()); + } + } } void Register() override diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index c42d4e84d..4c87c887a 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -2451,6 +2451,27 @@ class spell_q4735_collect_rookery_egg : public SpellScript } }; +enum BookOfFelNames +{ + SPELL_METAMORPHOSIS = 36298 +}; + +class spell_q10651_q10692_book_of_fel_names : public SpellScript +{ + PrepareSpellScript(spell_q10651_q10692_book_of_fel_names); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetHitUnit()->HasAura(SPELL_METAMORPHOSIS)) + GetHitUnit()->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_q10651_q10692_book_of_fel_names::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + void AddSC_quest_spell_scripts() { RegisterSpellAndAuraScriptPair(spell_q11065_wrangle_some_aether_rays, spell_q11065_wrangle_some_aether_rays_aura); @@ -2522,4 +2543,5 @@ void AddSC_quest_spell_scripts() RegisterSpellScript(spell_q12919_gymers_throw); RegisterSpellScript(spell_q5056_summon_shy_rotam); RegisterSpellScript(spell_q4735_collect_rookery_egg); + RegisterSpellScript(spell_q10651_q10692_book_of_fel_names); } diff --git a/src/test/common/Configuration/Config.cpp b/src/test/common/Configuration/Config.cpp new file mode 100644 index 000000000..c3c1e67d3 --- /dev/null +++ b/src/test/common/Configuration/Config.cpp @@ -0,0 +1,125 @@ +/* + * 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 . + */ + +#include "Config.h" +#include "gtest/gtest.h" + +#include +#include +#include +#include + +std::string CreateConfigWithMap(std::map const& map) +{ + auto mTempFileRel = boost::filesystem::unique_path("deleteme.ini"); + auto mTempFileAbs = boost::filesystem::temp_directory_path() / mTempFileRel; + std::ofstream iniStream; + iniStream.open(mTempFileAbs.c_str()); + + iniStream << "[test]\n"; + for (auto const& itr : map) + iniStream << itr.first << " = " << itr.second << "\n"; + + iniStream.close(); + + return mTempFileAbs.native(); +} + +class ConfigEnvTest : public testing::Test { +protected: + void SetUp() override { + std::map config; + config["Int.Nested"] = "4242"; + config["lower"] = "simpleString"; + config["UPPER"] = "simpleString"; + config["SomeLong.NestedNameWithNumber.Like1"] = "1"; + config["GM.InGMList.Level"] = "50"; + + confFilePath = CreateConfigWithMap(config); + + sConfigMgr->Configure(confFilePath, std::vector()); + sConfigMgr->LoadAppConfigs(); + } + + void TearDown() override { + std::remove(confFilePath.c_str()); + } + + std::string confFilePath; +}; + +TEST_F(ConfigEnvTest, NestedInt) +{ + EXPECT_EQ(sConfigMgr->GetOption("Int.Nested", 10), 4242); + setenv("AC_INT_NESTED", "8080", 1); + EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false); + EXPECT_EQ(sConfigMgr->GetOption("Int.Nested", 10), 8080); +} + +TEST_F(ConfigEnvTest, SimpleLowerString) +{ + EXPECT_EQ(sConfigMgr->GetOption("lower", ""), "simpleString"); + setenv("AC_LOWER", "envstring", 1); + EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false); + EXPECT_EQ(sConfigMgr->GetOption("lower", ""), "envstring"); +} + +TEST_F(ConfigEnvTest, SimpleUpperString) +{ + EXPECT_EQ(sConfigMgr->GetOption("UPPER", ""), "simpleString"); + setenv("AC_UPPER", "envupperstring", 1); + EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false); + EXPECT_EQ(sConfigMgr->GetOption("UPPER", ""), "envupperstring"); +} + +TEST_F(ConfigEnvTest, LongNestedNameWithNumber) +{ + EXPECT_EQ(sConfigMgr->GetOption("SomeLong.NestedNameWithNumber.Like1", 0), 1); + setenv("AC_SOME_LONG_NESTED_NAME_WITH_NUMBER_LIKE_1", "42", 1); + EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false); + EXPECT_EQ(sConfigMgr->GetOption("SomeLong.NestedNameWithNumber.Like1", 0), 42); +} + +TEST_F(ConfigEnvTest, ValueWithSeveralUpperlLaters) +{ + EXPECT_EQ(sConfigMgr->GetOption("GM.InGMList.Level", 1), 50); + setenv("AC_GM_IN_GMLIST_LEVEL", "42", 1); + EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false); + EXPECT_EQ(sConfigMgr->GetOption("GM.InGMList.Level", 0), 42); +} + +TEST_F(ConfigEnvTest, StringThatNotExistInConfig) +{ + setenv("AC_UNIQUE_STRING", "somevalue", 1); + EXPECT_EQ(sConfigMgr->GetOption("Unique.String", ""), "somevalue"); +} + +TEST_F(ConfigEnvTest, IntThatNotExistInConfig) +{ + setenv("AC_UNIQUE_INT", "100", 1); + EXPECT_EQ(sConfigMgr->GetOption("Unique.Int", 1), 100); +} + +TEST_F(ConfigEnvTest, NotExistingString) +{ + EXPECT_EQ(sConfigMgr->GetOption("NotFound.String", "none"), "none"); +} + +TEST_F(ConfigEnvTest, NotExistingInt) +{ + EXPECT_EQ(sConfigMgr->GetOption("NotFound.Int", 1), 1); +} diff --git a/src/tools/dbimport/Main.cpp b/src/tools/dbimport/Main.cpp index 0f4ddf5ff..0ab64be72 100644 --- a/src/tools/dbimport/Main.cpp +++ b/src/tools/dbimport/Main.cpp @@ -62,6 +62,8 @@ int main(int argc, char** argv) if (!sConfigMgr->LoadAppConfigs()) return 1; + std::vector overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny(); + // Init logging sLog->Initialize(); @@ -78,6 +80,9 @@ int main(int argc, char** argv) } ); + for (std::string const& key : overriddenKeys) + LOG_INFO("dbimport", "Configuration field {} was overridden with environment variable.", key); + OpenSSLCrypto::threadsSetup(); std::shared_ptr opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });