From e054ef324931e6db9c37f0e50678a66f7bef6c1b Mon Sep 17 00:00:00 2001 From: bash Date: Tue, 6 Jan 2026 16:32:49 +0100 Subject: [PATCH] Squashed playerbot custom changes --- .github/ISSUE_TEMPLATE/bb_crash_issues.yml | 2 +- .github/README.md | 3 +- .github/workflows/codestyle.yml | 2 +- .github/workflows/core-build-nopch.yml | 2 +- .github/workflows/core-build-pch.yml | 6 +- .github/workflows/core-build-playerbots.yml | 100 +++++ .github/workflows/core-build.yml | 99 +++++ .github/workflows/core_modules_build.yml | 2 +- .github/workflows/docker_build.yml | 4 +- .github/workflows/macos_build.yml | 11 +- .github/workflows/tools_build.yml | 8 +- .github/workflows/windows_build.yml | 11 +- .gitignore | 4 + AUTHORS | 5 + apps/ci/mac/ci-compile.sh | 6 +- apps/docker/Dockerfile | 2 +- conf/dist/config.cmake | 2 +- data/sql/updates/db_world/2025_11_10_00.sql | 5 - data/sql/updates/db_world/2025_11_10_01.sql | 4 - data/sql/updates/db_world/2025_11_10_02.sql | 4 - data/sql/updates/db_world/2025_11_10_03.sql | 15 - data/sql/updates/db_world/2025_11_11_00.sql | 4 - data/sql/updates/db_world/2025_11_11_01.sql | 10 - data/sql/updates/db_world/2025_11_11_02.sql | 45 --- data/sql/updates/db_world/2025_11_11_03.sql | 21 -- data/sql/updates/db_world/2025_11_12_00.sql | 4 - data/sql/updates/db_world/2025_11_12_01.sql | 10 - data/sql/updates/db_world/2025_11_12_02.sql | 64 ---- data/sql/updates/db_world/2025_11_12_03.sql | 3 - data/sql/updates/db_world/2025_11_12_04.sql | 36 -- data/sql/updates/db_world/2025_11_12_05.sql | 5 - data/sql/updates/db_world/2025_11_12_06.sql | 11 - data/sql/updates/db_world/2025_11_13_00.sql | 8 - data/sql/updates/db_world/2025_11_13_01.sql | 5 - data/sql/updates/db_world/2025_11_13_02.sql | 5 - data/sql/updates/db_world/2025_11_13_03.sql | 5 - data/sql/updates/db_world/2025_11_13_04.sql | 53 --- data/sql/updates/db_world/2025_11_13_05.sql | 4 - data/sql/updates/db_world/2025_11_14_00.sql | 9 - data/sql/updates/db_world/2025_11_14_01.sql | 6 - data/sql/updates/db_world/2025_11_14_02.sql | 5 - data/sql/updates/db_world/2025_11_14_03.sql | 5 - data/sql/updates/db_world/2025_11_15_00.sql | 5 - data/sql/updates/db_world/2025_11_15_01.sql | 3 - data/sql/updates/db_world/2025_11_15_02.sql | 6 - data/sql/updates/db_world/2025_11_15_03.sql | 3 - data/sql/updates/db_world/2025_11_15_04.sql | 3 - data/sql/updates/db_world/2025_11_15_05.sql | 6 - data/sql/updates/db_world/2025_11_15_06.sql | 9 - data/sql/updates/db_world/2025_11_15_07.sql | 5 - data/sql/updates/db_world/2025_11_15_08.sql | 69 ---- data/sql/updates/db_world/2025_11_15_09.sql | 3 - data/sql/updates/db_world/2025_11_15_10.sql | 9 - data/sql/updates/db_world/2025_11_15_11.sql | 14 - data/sql/updates/db_world/2025_11_15_12.sql | 3 - data/sql/updates/db_world/2025_11_15_13.sql | 5 - data/sql/updates/db_world/2025_11_15_14.sql | 3 - data/sql/updates/db_world/2025_11_15_15.sql | 31 -- data/sql/updates/db_world/2025_11_16_00.sql | 10 - data/sql/updates/db_world/2025_11_16_01.sql | 3 - data/sql/updates/db_world/2025_11_16_02.sql | 3 - data/sql/updates/db_world/2025_11_17_00.sql | 19 - data/sql/updates/db_world/2025_11_17_01.sql | 5 - data/sql/updates/db_world/2025_11_17_02.sql | 22 -- data/sql/updates/db_world/2025_11_17_03.sql | 8 - deps/boost/CMakeLists.txt | 2 +- deps/recastnavigation/Detour/CMakeLists.txt | 2 +- deps/recastnavigation/Recast/CMakeLists.txt | 2 +- doc/changelog/master.md | 2 +- .../pendings/changes_1647137971165231200.md | 7 + docker-compose.yml | 1 + modules/CMakeLists.txt | 18 + .../Collision/BoundingIntervalHierarchy.h | 2 - src/common/Collision/DynamicTree.cpp | 49 ++- src/common/Collision/DynamicTree.h | 4 +- src/common/Collision/Management/IVMapMgr.h | 25 +- src/common/Collision/Management/MMapMgr.cpp | 3 +- src/common/Collision/Management/VMapMgr2.cpp | 82 ++++- src/common/Collision/Management/VMapMgr2.h | 4 +- src/common/Collision/Maps/MapTree.cpp | 32 ++ src/common/Collision/Maps/MapTree.h | 7 +- .../Collision/Models/GameObjectModel.cpp | 25 +- src/common/Collision/Models/GameObjectModel.h | 1 + src/common/Collision/Models/ModelInstance.cpp | 44 ++- src/common/Collision/Models/ModelInstance.h | 1 + src/common/Collision/Models/WorldModel.cpp | 125 +++---- src/common/Collision/Models/WorldModel.h | 10 +- src/common/Utilities/CircularBuffer.h | 2 +- src/common/Utilities/DataMap.h | 2 +- src/common/Utilities/EventMap.h | 26 ++ src/common/Utilities/EventProcessor.h | 2 +- src/common/Utilities/Util.h | 1 + src/server/apps/worldserver/Main.cpp | 11 + .../apps/worldserver/worldserver.conf.dist | 2 + src/server/database/Database/DatabaseEnv.cpp | 4 + src/server/database/Database/DatabaseEnv.h | 9 + src/server/database/Database/DatabaseEnvFwd.h | 16 + .../database/Database/DatabaseLoader.cpp | 5 + src/server/database/Database/DatabaseLoader.h | 13 +- .../database/Database/DatabaseWorkerPool.cpp | 8 + .../Implementation/CharacterDatabase.cpp | 3 +- .../Implementation/CharacterDatabase.h | 1 + .../Database/Implementation/LoginDatabase.cpp | 3 +- .../Database/Implementation/LoginDatabase.h | 1 + .../Implementation/PlayerbotsDatabase.cpp | 129 +++++++ .../Implementation/PlayerbotsDatabase.h | 120 ++++++ src/server/database/Updater/DBUpdater.cpp | 78 +++- src/server/database/Updater/DBUpdater.h | 1 + src/server/database/Updater/UpdateFetcher.cpp | 2 +- src/server/game/AI/CreatureAI.cpp | 12 +- .../game/AI/SmartScripts/SmartScriptMgr.cpp | 3 - .../game/Achievements/AchievementMgr.cpp | 9 - src/server/game/Battlegrounds/ArenaTeam.cpp | 19 + src/server/game/Battlegrounds/ArenaTeam.h | 4 + src/server/game/Battlegrounds/Battleground.h | 1 + .../game/Battlegrounds/Zones/BattlegroundAB.h | 31 +- .../game/Battlegrounds/Zones/BattlegroundAV.h | 4 + .../game/Battlegrounds/Zones/BattlegroundEY.h | 42 ++- .../game/Battlegrounds/Zones/BattlegroundIC.h | 3 + src/server/game/Chat/Channels/ChannelMgr.h | 1 + src/server/game/Chat/Chat.cpp | 72 ++++ src/server/game/Chat/Chat.h | 18 + src/server/game/Combat/UnitEvents.h | 22 +- src/server/game/DataStores/DBCStores.cpp | 90 +++++ src/server/game/DataStores/DBCStores.h | 12 + src/server/game/DungeonFinding/LFGMgr.h | 2 +- src/server/game/DungeonFinding/LFGQueue.cpp | 6 + .../game/Entities/Creature/Creature.cpp | 3 +- .../game/Entities/Creature/CreatureData.h | 1 + src/server/game/Entities/Item/Item.cpp | 16 +- src/server/game/Entities/Item/Item.h | 2 +- src/server/game/Entities/Item/ItemTemplate.h | 4 +- src/server/game/Entities/Player/Player.cpp | 65 +++- src/server/game/Entities/Player/Player.h | 18 +- .../game/Entities/Player/PlayerStorage.cpp | 25 ++ .../game/Entities/Player/PlayerUpdates.cpp | 4 +- src/server/game/Entities/Unit/Unit.cpp | 49 ++- src/server/game/Entities/Unit/Unit.h | 6 + .../game/Entities/Vehicle/VehicleDefines.h | 1 + src/server/game/Globals/ObjectMgr.h | 1 + src/server/game/Grids/GridTerrainData.cpp | 6 +- src/server/game/Grids/GridTerrainData.h | 4 +- src/server/game/Groups/Group.h | 4 + src/server/game/Guilds/Guild.cpp | 86 ++++- src/server/game/Guilds/Guild.h | 20 +- src/server/game/Handlers/CharacterHandler.cpp | 26 +- src/server/game/Handlers/ChatHandler.cpp | 59 ++- src/server/game/Handlers/PetitionsHandler.cpp | 2 + src/server/game/Maps/Map.cpp | 81 ++-- src/server/game/Maps/Map.h | 10 +- src/server/game/Misc/GameGraveyard.cpp | 7 +- src/server/game/Misc/GameGraveyard.h | 1 + src/server/game/Movement/MotionMaster.cpp | 42 +++ src/server/game/Movement/MotionMaster.h | 5 +- .../MovementGenerators/PathGenerator.cpp | 6 +- .../PointMovementGenerator.cpp | 13 +- .../WaypointMovementGenerator.cpp | 12 +- .../ScriptDefines/DatabaseScript.cpp | 55 +++ .../Scripting/ScriptDefines/DatabaseScript.h | 7 + .../Scripting/ScriptDefines/PlayerScript.cpp | 31 ++ .../Scripting/ScriptDefines/PlayerScript.h | 17 + .../ScriptDefines/PlayerbotsScript.cpp | 105 ++++++ .../Scripting/ScriptDefines/ServerScript.cpp | 9 + .../Scripting/ScriptDefines/ServerScript.h | 2 + src/server/game/Scripting/ScriptMgr.cpp | 7 + src/server/game/Scripting/ScriptMgr.h | 46 ++- src/server/game/Server/WorldSession.cpp | 46 ++- src/server/game/Server/WorldSession.h | 34 +- src/server/game/Server/WorldSessionMgr.cpp | 5 + src/server/game/Spells/Spell.cpp | 2 +- src/server/game/World/IWorld.h | 5 + src/server/game/World/World.cpp | 11 + src/server/game/World/World.h | 10 + src/server/scripts/Commands/cs_cheat.cpp | 4 +- src/server/scripts/Commands/cs_misc.cpp | 2 +- src/server/scripts/Commands/cs_npc.cpp | 1 + src/server/scripts/Commands/cs_server.cpp | 8 + .../Northrend/DraktharonKeep/boss_dred.cpp | 139 +++---- .../Northrend/DraktharonKeep/boss_novos.cpp | 345 +++++++++--------- .../DraktharonKeep/drak_tharon_keep.h | 1 - .../instance_drak_tharon_keep.cpp | 63 ++-- .../Nexus/Oculus/instance_oculus.cpp | 16 +- .../Ulduar/HallsOfLightning/boss_loken.cpp | 95 +++-- .../Ulduar/HallsOfStone/brann_bronzebeard.cpp | 12 + .../scripts/Northrend/isle_of_conquest.cpp | 10 +- .../scripts/Northrend/zone_borean_tundra.cpp | 35 -- .../scripts/Northrend/zone_grizzly_hills.cpp | 112 ++++++ .../scripts/Northrend/zone_sholazar_basin.cpp | 104 ++++++ .../scripts/Northrend/zone_storm_peaks.cpp | 25 +- src/server/scripts/Northrend/zone_zuldrak.cpp | 6 +- .../BlackTemple/boss_reliquary_of_souls.cpp | 6 +- src/server/scripts/Spells/spell_generic.cpp | 7 +- .../scripts/World/areatrigger_scripts.cpp | 2 +- src/server/scripts/World/chat_log.cpp | 36 +- .../shared/DataStores/DBCDatabaseLoader.cpp | 17 +- src/server/shared/DataStores/DBCStructure.h | 36 ++ src/server/shared/DataStores/DBCfmt.h | 2 + src/server/shared/SharedDefines.h | 6 +- 198 files changed, 2774 insertions(+), 1387 deletions(-) create mode 100644 .github/workflows/core-build-playerbots.yml create mode 100644 .github/workflows/core-build.yml delete mode 100644 data/sql/updates/db_world/2025_11_10_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_10_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_10_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_10_03.sql delete mode 100644 data/sql/updates/db_world/2025_11_11_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_11_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_11_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_11_03.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_03.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_04.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_05.sql delete mode 100644 data/sql/updates/db_world/2025_11_12_06.sql delete mode 100644 data/sql/updates/db_world/2025_11_13_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_13_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_13_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_13_03.sql delete mode 100644 data/sql/updates/db_world/2025_11_13_04.sql delete mode 100644 data/sql/updates/db_world/2025_11_13_05.sql delete mode 100644 data/sql/updates/db_world/2025_11_14_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_14_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_14_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_14_03.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_03.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_04.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_05.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_06.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_07.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_08.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_09.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_10.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_11.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_12.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_13.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_14.sql delete mode 100644 data/sql/updates/db_world/2025_11_15_15.sql delete mode 100644 data/sql/updates/db_world/2025_11_16_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_16_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_16_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_17_00.sql delete mode 100644 data/sql/updates/db_world/2025_11_17_01.sql delete mode 100644 data/sql/updates/db_world/2025_11_17_02.sql delete mode 100644 data/sql/updates/db_world/2025_11_17_03.sql create mode 100644 doc/changelog/pendings/changes_1647137971165231200.md create mode 100644 src/server/database/Database/Implementation/PlayerbotsDatabase.cpp create mode 100644 src/server/database/Database/Implementation/PlayerbotsDatabase.h create mode 100644 src/server/game/Scripting/ScriptDefines/PlayerbotsScript.cpp diff --git a/.github/ISSUE_TEMPLATE/bb_crash_issues.yml b/.github/ISSUE_TEMPLATE/bb_crash_issues.yml index 9e94e5bbc..43b07bf79 100644 --- a/.github/ISSUE_TEMPLATE/bb_crash_issues.yml +++ b/.github/ISSUE_TEMPLATE/bb_crash_issues.yml @@ -31,7 +31,7 @@ body: description: | Do you have any logs or screenshots that can be useful? Crash logs in text are preffered over screenshots. - DO NOT POST THE FULL CRASH LOG IN THE ISSUE BODY. DO NOT UPLOAD TEXT FILES. USE [GITHUB GIST](https://gist.github.com/), PASTEBIN, OR ANY SIMILAR SERVICE INSTEAD. + If you have logs in text form please upload them to [Gist](https://gist.github.com/) or PasteBin and upload the link. validations: required: false - type: input diff --git a/.github/README.md b/.github/README.md index 3a9e654d6..995688155 100644 --- a/.github/README.md +++ b/.github/README.md @@ -82,7 +82,8 @@ You can check the [authors](https://github.com/azerothcore/azerothcore-wotlk/blo ## License -- The AzerothCore source code is released under the [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) +- The new AzerothCore source components are released under the [GNU AGPL v3](https://www.gnu.org/licenses/agpl-3.0.en.html) +- The old sources based on MaNGOS/TrinityCore are released under the [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) 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. diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 643593a0c..4fc3f97ef 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -14,7 +14,7 @@ jobs: triage: runs-on: ubuntu-latest name: C++ - if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft + if: github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft steps: - uses: actions/checkout@v4 - name: Setup python diff --git a/.github/workflows/core-build-nopch.yml b/.github/workflows/core-build-nopch.yml index e67e9463c..171159e2e 100644 --- a/.github/workflows/core-build-nopch.yml +++ b/.github/workflows/core-build-nopch.yml @@ -37,7 +37,7 @@ jobs: CXX: g++-14 runs-on: ${{ matrix.os }} name: ${{ matrix.os }}-${{ matrix.compiler.CC }}-nopch - if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft + if: github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft steps: - uses: actions/checkout@v4 - uses: ./.github/actions/linux-build diff --git a/.github/workflows/core-build-pch.yml b/.github/workflows/core-build-pch.yml index 8a752e450..05afbfe6f 100644 --- a/.github/workflows/core-build-pch.yml +++ b/.github/workflows/core-build-pch.yml @@ -32,8 +32,10 @@ jobs: CC: clang-18 CXX: clang++-18 runs-on: ${{ matrix.os }} - name: ${{ matrix.os }}-${{ matrix.compiler.CC }}-pch - if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft + name: ${{ matrix.os }}-${{ matrix.compiler }}-pch + env: + COMPILER: ${{ matrix.compiler }} + if: github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft steps: - uses: actions/checkout@v4 - uses: ./.github/actions/linux-build diff --git a/.github/workflows/core-build-playerbots.yml b/.github/workflows/core-build-playerbots.yml new file mode 100644 index 000000000..0d7bf98f7 --- /dev/null +++ b/.github/workflows/core-build-playerbots.yml @@ -0,0 +1,100 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: ubuntu-build + +on: + push: + branches: [ "Playerbot" ] + pull_request: + branches: [ "Playerbot" ] + +jobs: + build: + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + matrix: + # the result of the matrix will be the combination of all attributes, so we get os*compiler builds + include: + - os: ubuntu-22.04 + c_compiler: clang + cpp_compiler: clang++ + build_type: Release + - os: ubuntu-22.04 + c_compiler: gcc + cpp_compiler: g++ + build_type: Release + - os: ubuntu-24.04 + c_compiler: gcc + cpp_compiler: g++ + build_type: Release + + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }}-${{ matrix.cpp_compiler }} + + steps: + - name: Checkout AzerothCore + uses: actions/checkout@v3 + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + # - name: Clone Playerbot Module + # run: git clone --depth=1 --branch=master https://github.com/mod-playerbots/mod-playerbots.git modules/mod-playerbots + + - name: Checkout Playerbot Module + uses: actions/checkout@v3 + with: + repository: 'mod-playerbots/mod-playerbots' + #ref: 'feature/core_update_10_2025' #used on core merge conflicts builds + path: 'modules/mod-playerbots' + + - name: Install Requirements + run: sudo apt-get update && sudo apt-get install git cmake make gcc g++ clang libmysqlclient-dev libssl-dev libbz2-dev libreadline-dev libncurses-dev mysql-server libboost-all-dev + + # - name: Cache + # uses: actions/cache@v3 + # with: + # path: var/ccache + # key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules:${{ github.ref }}:${{ github.sha }} + # restore-keys: | + # ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules:${{ github.ref }} + # ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules + + # - name: Configure OS + # run: source ./acore.sh install-deps + # env: + # CONTINUOUS_INTEGRATION: true + + # - name: Create conf/config.sh + # run: source ./apps/ci/ci-conf-core.sh + + # - name: Process pending sql + # run: bash bin/acore-db-pendings + + # - name: Build + # run: source ./apps/ci/ci-compile.sh + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -S ${{ github.workspace }} + + - name: Build + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + # - name: Test + # working-directory: ${{ steps.strings.outputs.build-output-dir }} + # # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + # # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + # run: ctest --build-config ${{ matrix.build_type }} diff --git a/.github/workflows/core-build.yml b/.github/workflows/core-build.yml new file mode 100644 index 000000000..7f1c06572 --- /dev/null +++ b/.github/workflows/core-build.yml @@ -0,0 +1,99 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: ubuntu-build + +on: + push: + branches: [ "Playerbot" ] + pull_request: + branches: [ "Playerbot" ] + +jobs: + build: + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + matrix: + # the result of the matrix will be the combination of all attributes, so we get os*compiler builds + include: + - os: ubuntu-22.04 + c_compiler: clang + cpp_compiler: clang++ + build_type: Release + - os: ubuntu-22.04 + c_compiler: gcc + cpp_compiler: g++ + build_type: Release + - os: ubuntu-24.04 + c_compiler: gcc + cpp_compiler: g++ + build_type: Release + + runs-on: ${{ matrix.os }} + name: ${{ matrix.os }}-${{ matrix.cpp_compiler }} + + steps: + - name: Checkout AzerothCore + uses: actions/checkout@v3 + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + # - name: Clone Playerbot Module + # run: git clone --depth=1 --branch=master https://github.com/mod-playerbots/mod-playerbots.git modules/mod-playerbots + + # - name: Checkout Playerbot Module + # uses: actions/checkout@v3 + # with: + # repository: 'mod-playerbots/mod-playerbots' + # path: 'modules/mod-playerbots' + + - name: Install Requirements + run: sudo apt-get update && sudo apt-get install git cmake make gcc g++ clang libmysqlclient-dev libssl-dev libbz2-dev libreadline-dev libncurses-dev mysql-server libboost-all-dev + + # - name: Cache + # uses: actions/cache@v3 + # with: + # path: var/ccache + # key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules:${{ github.ref }}:${{ github.sha }} + # restore-keys: | + # ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules:${{ github.ref }} + # ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules + + # - name: Configure OS + # run: source ./acore.sh install-deps + # env: + # CONTINUOUS_INTEGRATION: true + + # - name: Create conf/config.sh + # run: source ./apps/ci/ci-conf-core.sh + + # - name: Process pending sql + # run: bash bin/acore-db-pendings + + # - name: Build + # run: source ./apps/ci/ci-compile.sh + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -S ${{ github.workspace }} + + - name: Build + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + # - name: Test + # working-directory: ${{ steps.strings.outputs.build-output-dir }} + # # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + # # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + # run: ctest --build-config ${{ matrix.build_type }} diff --git a/.github/workflows/core_modules_build.yml b/.github/workflows/core_modules_build.yml index 1ae3a1c02..26528dcb7 100644 --- a/.github/workflows/core_modules_build.yml +++ b/.github/workflows/core_modules_build.yml @@ -39,7 +39,7 @@ jobs: CXX: clang++-18 runs-on: ${{ matrix.os }} name: ${{ matrix.os }}-${{ matrix.compiler.CC }}-nopch-modules - if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft + if: github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft steps: - uses: actions/checkout@v4 # This script installs a general list of modules to compile with diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index eee506a14..c3151e067 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -16,13 +16,13 @@ env: COMPOSE_DOCKER_CLI_BUILD: 1 DOCKER_BUILDKIT: 1 RUNNING_ON_PRIMARY_BRANCH: | - ${{ (github.repository == 'azerothcore/azerothcore-wotlk' && github.ref_name == 'master') && 'true' || 'false' }} + ${{ (github.repository == 'mod-playerbots/azerothcore-wotlk' && github.ref_name == 'master') && 'true' || 'false' }} jobs: build-containers: runs-on: "ubuntu-latest" if: | - github.repository == 'azerothcore/azerothcore-wotlk' + github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft && (github.ref_name == 'master' || contains(github.event.pull_request.labels.*.name, 'run-build') || github.event.label.name == 'run-build') steps: diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index 09ae976a2..03974bca6 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -1,12 +1,9 @@ name: macos-build on: push: - branches: - - 'master' + branches: [ "Playerbot" ] pull_request: - types: - - labeled - - synchronize + branches: [ "Playerbot" ] concurrency: group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }}) @@ -25,10 +22,6 @@ jobs: - macos-14 runs-on: ${{ matrix.os }} name: ${{ matrix.os }} - if: | - github.repository == 'azerothcore/azerothcore-wotlk' - && !github.event.pull_request.draft - && (github.ref == 'refs/heads/master' || contains(github.event.pull_request.labels.*.name, 'run-build') || github.event.label.name == 'run-build') steps: - uses: actions/checkout@v4 - name: Cache diff --git a/.github/workflows/tools_build.yml b/.github/workflows/tools_build.yml index 5ad3bf3bf..8d1906297 100644 --- a/.github/workflows/tools_build.yml +++ b/.github/workflows/tools_build.yml @@ -25,9 +25,11 @@ jobs: runs-on: ${{ matrix.os }} name: ${{ matrix.os }}-${{ matrix.compiler.CC }} if: | - github.repository == 'azerothcore/azerothcore-wotlk' - && !github.event.pull_request.draft - && (github.ref == 'refs/heads/master' || contains(github.event.pull_request.labels.*.name, 'run-build') || github.event.label.name == 'run-build') + github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft + && ( + contains(github.event.pull_request.labels.*.name, 'run-build') + || github.event.label.name == 'run-build' + ) steps: - uses: actions/checkout@v4 - uses: ./.github/actions/linux-build diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml index c01e3ff3c..eb3b5999b 100644 --- a/.github/workflows/windows_build.yml +++ b/.github/workflows/windows_build.yml @@ -1,12 +1,9 @@ name: windows-build on: push: - branches: - - 'master' + branches: [ "Playerbot" ] pull_request: - types: - - labeled - - synchronize + branches: [ "Playerbot" ] concurrency: group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }}) @@ -22,10 +19,6 @@ jobs: name: ${{ matrix.os }} env: BOOST_ROOT: C:\local\boost_1_82_0 - if: | - github.repository == 'azerothcore/azerothcore-wotlk' - && !github.event.pull_request.draft - && (github.ref == 'refs/heads/master' || contains(github.event.pull_request.labels.*.name, 'run-build') || github.event.label.name == 'run-build') steps: - uses: actions/checkout@v4 - name: ccache diff --git a/.gitignore b/.gitignore index 548213a63..a25db2997 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,8 @@ CMakeLists.txt.user # /.settings/ /.externalToolBuilders/* +/.vs +/out # exclude in all levels nbproject/ .sync.ffs_db @@ -102,3 +104,5 @@ local.properties # !modules/yourmodule # # ================== +.cache +compile_commands.json \ No newline at end of file diff --git a/AUTHORS b/AUTHORS index c9155fdca..63425cea7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,10 @@ # List of AUTHORS who contributed over time to the AzerothCore project +## Warning +The code of AzerothCore is shipped as it is without any form of warranty, +and - except for third party libraries licensed under the AGPL 3, +which you can read from the file "LICENSE". + ## Point of current development The project is currently hosted at https://www.azerothcore.org/ and developed under https://github.com/azerothcore diff --git a/apps/ci/mac/ci-compile.sh b/apps/ci/mac/ci-compile.sh index 79507bc9f..10dfbc4b6 100755 --- a/apps/ci/mac/ci-compile.sh +++ b/apps/ci/mac/ci-compile.sh @@ -22,8 +22,7 @@ if [ ! -d "$mysql_include_path" ]; then fi time cmake ../../../ \ --DTOOLS=1 \ --DBUILD_TESTING=1 \ +-DTOOLS_BUILD=all \ -DSCRIPTS=static \ -DCMAKE_BUILD_TYPE=Release \ -DMYSQL_ADD_INCLUDE_PATH=$mysql_include_path \ @@ -33,9 +32,6 @@ time cmake ../../../ \ -DOPENSSL_INCLUDE_DIR="$OPENSSL_ROOT_DIR/include" \ -DOPENSSL_SSL_LIBRARIES="$OPENSSL_ROOT_DIR/lib/libssl.dylib" \ -DOPENSSL_CRYPTO_LIBRARIES="$OPENSSL_ROOT_DIR/lib/libcrypto.dylib" \ --DWITH_WARNINGS=1 \ --DCMAKE_C_FLAGS="-Werror" \ --DCMAKE_CXX_FLAGS="-Werror" \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DUSE_SCRIPTPCH=0 \ diff --git a/apps/docker/Dockerfile b/apps/docker/Dockerfile index 0fdee45ce..b96f11b6e 100644 --- a/apps/docker/Dockerfile +++ b/apps/docker/Dockerfile @@ -258,4 +258,4 @@ COPY --chown=$DOCKER_USER:$DOCKER_USER --from=build \ /azerothcore/env/dist/bin/vmap4_assembler /azerothcore/env/dist/bin/vmap4_assembler COPY --chown=$DOCKER_USER:$DOCKER_USER --from=build \ - /azerothcore/env/dist/bin/vmap4_extractor /azerothcore/env/dist/bin/vmap4_extractor + /azerothcore/env/dist/bin/vmap4_extractor /azerothcore/env/dist/bin/vmap4_extractor \ No newline at end of file diff --git a/conf/dist/config.cmake b/conf/dist/config.cmake index ce2e079f3..d1a32cf14 100644 --- a/conf/dist/config.cmake +++ b/conf/dist/config.cmake @@ -1,5 +1,5 @@ # -# Copyright (C) 2016+ AzerothCore +# Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE # Copyright (C) 2021+ WarheadCore # # This file is free software; as a special exception the author gives diff --git a/data/sql/updates/db_world/2025_11_10_00.sql b/data/sql/updates/db_world/2025_11_10_00.sql deleted file mode 100644 index a3f3213d6..000000000 --- a/data/sql/updates/db_world/2025_11_10_00.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_09_05 -> 2025_11_10_00 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 24539) AND (`source_type` = 0) AND (`id` IN (5)); -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 -(24539, 0, 5, 0, 2, 1, 100, 513, 0, 50, 0, 0, 0, 0, 80, 2453900, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '"Silvermoon" Harry - Between 0-50% Health - Run Script (Phase 1) (No Repeat)'); diff --git a/data/sql/updates/db_world/2025_11_10_01.sql b/data/sql/updates/db_world/2025_11_10_01.sql deleted file mode 100644 index caa15f098..000000000 --- a/data/sql/updates/db_world/2025_11_10_01.sql +++ /dev/null @@ -1,4 +0,0 @@ --- DB update 2025_11_10_00 -> 2025_11_10_01 --- -UPDATE `quest_template` SET `RewardFactionValue1` = 5 WHERE (`ID` = 11472); -UPDATE `quest_template` SET `RewardFactionValue1` = 5, `RewardFactionOverride1` = 0 WHERE (`ID` = 11945); diff --git a/data/sql/updates/db_world/2025_11_10_02.sql b/data/sql/updates/db_world/2025_11_10_02.sql deleted file mode 100644 index cb1d4aad5..000000000 --- a/data/sql/updates/db_world/2025_11_10_02.sql +++ /dev/null @@ -1,4 +0,0 @@ --- DB update 2025_11_10_01 -> 2025_11_10_02 --- -DELETE FROM `game_event_gameobject` WHERE `eventEntry`=1 AND `guid`=5; -INSERT INTO `game_event_gameobject` (`eventEntry`, `guid`) VALUES(1, 5); diff --git a/data/sql/updates/db_world/2025_11_10_03.sql b/data/sql/updates/db_world/2025_11_10_03.sql deleted file mode 100644 index ff79a0774..000000000 --- a/data/sql/updates/db_world/2025_11_10_03.sql +++ /dev/null @@ -1,15 +0,0 @@ --- DB update 2025_11_10_02 -> 2025_11_10_03 --- --- Increase grid searches to 60 from 40 -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2572900) AND (`source_type` = 9) AND (`id` IN (2, 5)); -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 -(2572900, 9, 2, 0, 0, 0, 100, 0, 8000, 8000, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 19, 25749, 60, 0, 0, 0, 0, 0, 0, 'Shadowstalker Getry - Actionlist - Say Line 7'), -(2572900, 9, 5, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 19, 25749, 60, 0, 0, 0, 0, 0, 0, 'Shadowstalker Getry - Actionlist - Despawn Instant'); -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 25618) AND (`source_type` = 0) AND (`id` IN (3, 4)); -INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES -(25618, 0, 3, 4, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 15, 11705, 0, 0, 0, 0, 0, 18, 60, 0, 0, 0, 0, 0, 0, 0, 'Varidus the Flenser - On Just Died - Quest Credit \'Foolish Endeavors\''), -(25618, 0, 4, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 19, 25729, 60, 0, 0, 0, 0, 0, 0, 'Varidus the Flenser - On Just Died - Set Data 1 1'); --- Increase despawn time from 3 to 4 minutes -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2561800) AND (`source_type` = 9) AND (`id` IN (25)); -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 -(2561800, 9, 25, 0, 0, 0, 100, 0, 240000, 240000, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 19, 25729, 100, 0, 0, 0, 0, 0, 0, 'Varidus the Flenser - Actionlist - Despawn Instant'); diff --git a/data/sql/updates/db_world/2025_11_11_00.sql b/data/sql/updates/db_world/2025_11_11_00.sql deleted file mode 100644 index 5b3a208d6..000000000 --- a/data/sql/updates/db_world/2025_11_11_00.sql +++ /dev/null @@ -1,4 +0,0 @@ --- DB update 2025_11_10_03 -> 2025_11_11_00 --- -DELETE FROM `areatrigger_scripts` WHERE `entry`=5338; -INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES(5338, 'at_last_rites'); diff --git a/data/sql/updates/db_world/2025_11_11_01.sql b/data/sql/updates/db_world/2025_11_11_01.sql deleted file mode 100644 index 58d10ecc1..000000000 --- a/data/sql/updates/db_world/2025_11_11_01.sql +++ /dev/null @@ -1,10 +0,0 @@ --- DB update 2025_11_11_00 -> 2025_11_11_01 --- --- Update comments, remove action On Init AI set combat distance to 100 -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 32767) AND (`source_type` = 0) AND (`id` IN (0, 1, 2, 3, 4, 5)); -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 -(32767, 0, 0, 0, 1, 0, 100, 0, 5000, 10000, 3000, 6000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 31406, 80, 0, 0, 0, 0, 0, 0, 'Frostbrood Sentry - Out of Combat - Start Attacking'), -(32767, 0, 1, 0, 1, 0, 100, 0, 5000, 10000, 3000, 6000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 32512, 80, 0, 0, 0, 0, 0, 0, 'Frostbrood Sentry - Out of Combat - Start Attacking'), -(32767, 0, 2, 0, 1, 0, 100, 0, 5000, 10000, 3000, 6000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 31838, 80, 0, 0, 0, 0, 0, 0, 'Frostbrood Sentry - Out of Combat - Start Attacking'), -(32767, 0, 3, 0, 1, 0, 100, 0, 5000, 10000, 3000, 6000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 19, 32513, 80, 0, 0, 0, 0, 0, 0, 'Frostbrood Sentry - Out of Combat - Start Attacking'), -(32767, 0, 4, 0, 9, 0, 100, 0, 0, 0, 2000, 3000, 0, 40, 11, 60542, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Frostbrood Sentry - Within 0-40 Range - Cast \'Bitter Blast\''); diff --git a/data/sql/updates/db_world/2025_11_11_02.sql b/data/sql/updates/db_world/2025_11_11_02.sql deleted file mode 100644 index ad2bcbebf..000000000 --- a/data/sql/updates/db_world/2025_11_11_02.sql +++ /dev/null @@ -1,45 +0,0 @@ --- DB update 2025_11_11_01 -> 2025_11_11_02 --- Update gameobject 'Wild Mustard' with sniffed values --- updated spawns -DELETE FROM `gameobject` WHERE (`id` IN (192827)) AND (`guid` IN (100121, 100244, 100245, 100246, 100247, 100248, 100249, 100411, 100412, 57471, 57472, 57473, 57475, 57476, 57477, 57478, 57479, 57480, 57481, 57482, 57483)); -INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES -(100121, 192827, 571, 0, 0, 1, 1, 5985.08349609375, 664.72296142578125, 642.370849609375, 4.799657344818115234, 0, 0, -0.67558956146240234, 0.737277925014495849, 120, 255, 1, "", 45942, NULL), -(100244, 192827, 571, 0, 0, 1, 1, 5934.06103515625, 660.3663330078125, 642.92462158203125, 5.6897735595703125, 0, 0, -0.29237174987792968, 0.956304728984832763, 120, 255, 1, "", 46158, NULL), -(100245, 192827, 571, 0, 0, 1, 1, 5846.48681640625, 490.76507568359375, 657.25555419921875, 5.515241622924804687, 0, 0, -0.37460613250732421, 0.927184045314788818, 120, 255, 1, "", 46158, NULL), -(100246, 192827, 571, 0, 0, 1, 1, 5831.59619140625, 763.8204345703125, 640.30194091796875, 1.762782454490661621, 0, 0, 0.771624565124511718, 0.636078238487243652, 120, 255, 1, "", 46248, NULL), -(100247, 192827, 571, 0, 0, 1, 1, 5767.6494140625, 770.37530517578125, 640.4595947265625, 4.537858963012695312, 0, 0, -0.76604366302490234, 0.642788589000701904, 120, 255, 1, "", 46248, NULL), -(100248, 192827, 571, 0, 0, 1, 1, 5675.63232421875, 737.062744140625, 641.646484375, 6.265733242034912109, 0, 0, -0.00872611999511718, 0.999961912631988525, 120, 255, 1, "", 46158, NULL), -(100249, 192827, 571, 0, 0, 1, 1, 5666.18994140625, 708.8232421875, 641.72613525390625, 4.136432647705078125, 0, 0, -0.87881660461425781, 0.477159708738327026, 120, 255, 1, "", 46248, NULL), -(100411, 192827, 571, 0, 0, 1, 1, 5781.63525390625, 755.59454345703125, 640.60955810546875, 2.478367090225219726, 0, 0, 0.94551849365234375, 0.325568377971649169, 120, 255, 1, "", 45327, NULL), -(100412, 192827, 571, 0, 0, 1, 1, 5852.45068359375, 453.083984375, 657.54180908203125, 4.956737518310546875, 0, 0, -0.61566066741943359, 0.788011372089385986, 120, 255, 1, "", 46158, NULL), -(57471, 192827, 571, 0, 0, 1, 1, 5647.09130859375, 735.65777587890625, 641.70587158203125, 0.349065244197845458, 0, 0, 0.173647880554199218, 0.984807789325714111, 120, 255, 1, "", 46368, NULL), -(57472, 192827, 571, 0, 0, 1, 1, 5638.42333984375, 752.54632568359375, 641.62371826171875, 4.188792228698730468, 0, 0, -0.86602497100830078, 0.50000077486038208, 120, 255, 1, "", 46158, NULL), -(57473, 192827, 571, 0, 0, 1, 1, 5752.2802734375, 780.19390869140625, 640.46044921875, 4.852017402648925781, 0, 0, -0.65605831146240234, 0.754710197448730468, 120, 255, 1, "", 46248, NULL), -(57475, 192827, 571, 0, 0, 1, 1, 5989.67138671875, 648.40582275390625, 642.70916748046875, 5.235987663269042968, 0, 0, -0.5, 0.866025388240814208, 120, 255, 1, "", 46158, NULL), -(57476, 192827, 571, 0, 0, 1, 1, 5756.24072265625, 758.174072265625, 642.0474853515625, 1.884953022003173828, 0, 0, 0.809016227722167968, 0.587786316871643066, 120, 255, 1, "", 46248, NULL), -(57477, 192827, 571, 0, 0, 1, 1, 5865.57666015625, 774.6185302734375, 640.53057861328125, 3.194002151489257812, 0, 0, -0.99965667724609375, 0.026201646775007247, 120, 255, 1, "", 45327, NULL), -(57478, 192827, 571, 0, 0, 1, 1, 5824.08251953125, 493.727813720703125, 656.93402099609375, 4.729844093322753906, 0, 0, -0.70090866088867187, 0.713251054286956787, 120, 255, 1, "", 46158, NULL), -(57479, 192827, 571, 0, 0, 1, 1, 5797.42138671875, 480.68121337890625, 657.57318115234375, 0.453785061836242675, 0, 0, 0.224950790405273437, 0.974370121955871582, 120, 255, 1, "", 46158, NULL), -(57480, 192827, 571, 0, 0, 1, 1, 5826.56494140625, 738.85418701171875, 640.9478759765625, 4.363324165344238281, 0, 0, -0.81915187835693359, 0.573576688766479492, 120, 255, 1, "", 46158, NULL), -(57481, 192827, 571, 0, 0, 1, 1, 5950.203125, 696.5841064453125, 641.10589599609375, 5.166176319122314453, 0, 0, -0.52991867065429687, 0.84804844856262207, 120, 255, 1, "", 45327, NULL), -(57482, 192827, 571, 0, 0, 1, 1, 5810.0791015625, 620.439208984375, 647.71026611328125, 0.034906249493360519, 0, 0, 0.017452239990234375, 0.999847710132598876, 120, 255, 1, "", 45327, NULL), -(57483, 192827, 571, 0, 0, 1, 1, 5804.63623046875, 661.78125, 647.7073974609375, 4.014260292053222656, 0, 0, -0.90630722045898437, 0.422619491815567016, 120, 255, 1, "", 45327, NULL); - --- new spawns -DELETE FROM `gameobject` WHERE (`id` IN (192827)) AND (`guid` BETWEEN 1747 AND 1761); -INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`, `Comment`) VALUES -(1747, 192827, 571, 0, 0, 1, 1, 5629.560546875, 725.41082763671875, 641.70721435546875, 2.356194972991943359, 0, 0, 0.923879623413085937, 0.382683247327804565, 120, 255, 1, "", 46158, NULL), -(1748, 192827, 571, 0, 0, 1, 1, 5657.634765625, 742.97552490234375, 641.5999755859375, 4.9218292236328125, 0, 0, -0.62932014465332031, 0.77714616060256958, 120, 255, 1, "", 46158, NULL), -(1749, 192827, 571, 0, 0, 1, 1, 5731.98681640625, 780.482666015625, 641.66925048828125, 3.926995515823364257, 0, 0, -0.92387866973876953, 0.38268551230430603, 120, 255, 1, "", 46158, NULL), -(1750, 192827, 571, 0, 0, 1, 1, 5742.24658203125, 770.8905029296875, 641.83380126953125, 5.567600727081298828, 0, 0, -0.35020732879638671, 0.936672210693359375, 120, 255, 1, "", 46158, NULL), -(1751, 192827, 571, 0, 0, 1, 1, 5778.017578125, 463.560821533203125, 657.8570556640625, 4.677483558654785156, 0, 0, -0.71933937072753906, 0.694658815860748291, 120, 255, 1, "", 46158, NULL), -(1752, 192827, 571, 0, 0, 1, 1, 5784.9462890625, 631.62530517578125, 647.66748046875, 5.131268978118896484, 0, 0, -0.54463863372802734, 0.838670849800109863, 120, 255, 1, "", 46158, NULL), -(1753, 192827, 571, 0, 0, 1, 1, 5787.90966796875, 646.6329345703125, 647.23504638671875, 4.59021615982055664, 0, 0, -0.74895572662353515, 0.662620067596435546, 120, 255, 1, "", 46158, NULL), -(1754, 192827, 571, 0, 0, 1, 1, 5803.4375, 745.01226806640625, 640.465087890625, 6.248279094696044921, 0, 0, -0.01745223999023437, 0.999847710132598876, 120, 255, 1, "", 45327, NULL), -(1755, 192827, 571, 0, 0, 1, 1, 5822.33203125, 652.23858642578125, 647.3056640625, 4.537858963012695312, 0, 0, -0.76604366302490234, 0.642788589000701904, 120, 255, 1, "", 45327, NULL), -(1756, 192827, 571, 0, 0, 1, 1, 5823.8359375, 637.7987060546875, 647.76348876953125, 3.001946926116943359, 0, 0, 0.997563362121582031, 0.069766148924827575, 120, 255, 1, "", 45327, NULL), -(1757, 192827, 571, 0, 0, 1, 1, 5842.37451171875, 750.66656494140625, 640.692626953125, 1.727874636650085449, 0, 0, 0.760405540466308593, 0.649448513984680175, 120, 255, 1, "", 46158, NULL), -(1758, 192827, 571, 0, 0, 1, 1, 5845.6962890625, 463.094573974609375, 657.62591552734375, 1.623155713081359863, 0, 0, 0.725374221801757812, 0.688354730606079101, 120, 255, 1, "", 46158, NULL), -(1759, 192827, 571, 0, 0, 1, 1, 5847.68603515625, 772.54559326171875, 640.36090087890625, 1.256635904312133789, 0, 0, 0.587784767150878906, 0.809017360210418701, 120, 255, 1, "", 46158, NULL), -(1760, 192827, 571, 0, 0, 1, 1, 5934.53369140625, 682.52099609375, 642.21148681640625, 3.682650327682495117, 0, 0, -0.96362972259521484, 0.26724100112915039, 120, 255, 1, "", 45327, NULL), -(1761, 192827, 571, 0, 0, 1, 1, 5972.26416015625, 648.7425537109375, 642.43182373046875, 1.919861555099487304, 0, 0, 0.819151878356933593, 0.573576688766479492, 120, 255, 1, "", 46158, NULL); diff --git a/data/sql/updates/db_world/2025_11_11_03.sql b/data/sql/updates/db_world/2025_11_11_03.sql deleted file mode 100644 index b91c8b621..000000000 --- a/data/sql/updates/db_world/2025_11_11_03.sql +++ /dev/null @@ -1,21 +0,0 @@ --- DB update 2025_11_11_02 -> 2025_11_11_03 --- -SET @ARGENT_CRUSADE := 1106; -SET @KIRIN_TOR := 1090; -SET @KNIGHTS_OF_THE_EBON_BLADE := 1098; -SET @WYRMREST_ACCORD := 1091; -SET @ALLIANCE_VANGUARD := 1037; -SET @HORDE_EXPEDITION := 1052; -SET @SONS_OF_HODIR := 1119; - -UPDATE `quest_template` SET `RewardFactionOverride1`=2200000 WHERE `ID` IN (12915, 12956); -UPDATE `quest_template` SET `RewardFactionOverride1`=0 WHERE `ID` IN (12924, 12975, 12976, 12977, 12981, 12985, 12987, 12994, 13001, 13003, 13010, 13011, 13046, 13108, 13420, 13421, 13559); -UPDATE `quest_template` SET `RewardFactionID1` = 0, `RewardFactionValue1` = 0, `RewardFactionOverride1` = 0 WHERE `ID` IN (12966, 12967); - -UPDATE `reputation_reward_rate` SET `quest_rate`=1.3,`quest_daily_rate`=1.3,`quest_weekly_rate`=1.3,`quest_monthly_rate`=1.3,`quest_repeatable_rate`=1.3 WHERE `faction` IN (@ARGENT_CRUSADE, @KNIGHTS_OF_THE_EBON_BLADE, @KIRIN_TOR, @WYRMREST_ACCORD); - -DELETE FROM `reputation_reward_rate` WHERE `faction` IN (@SONS_OF_HODIR, @ALLIANCE_VANGUARD, @HORDE_EXPEDITION); -INSERT INTO `reputation_reward_rate` (`faction`, `quest_rate`, `quest_daily_rate`, `quest_weekly_rate`, `quest_monthly_rate`, `quest_repeatable_rate`, `creature_rate`, `spell_rate`) VALUES -(@SONS_OF_HODIR, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3), -(@ALLIANCE_VANGUARD, 1.0, 1.0, 1.0, 1.0, 1.0, 1.3, 1.3), -(@HORDE_EXPEDITION, 1.0, 1.0, 1.0, 1.0, 1.0, 1.3, 1.3); diff --git a/data/sql/updates/db_world/2025_11_12_00.sql b/data/sql/updates/db_world/2025_11_12_00.sql deleted file mode 100644 index 42608948a..000000000 --- a/data/sql/updates/db_world/2025_11_12_00.sql +++ /dev/null @@ -1,4 +0,0 @@ --- DB update 2025_11_11_03 -> 2025_11_12_00 --- --- remove `DISABLE_MOVE` -UPDATE `creature_template` SET `unit_flags` = `unit_flags` & ~4 WHERE (`entry` = 28998); diff --git a/data/sql/updates/db_world/2025_11_12_01.sql b/data/sql/updates/db_world/2025_11_12_01.sql deleted file mode 100644 index 0846cc5d1..000000000 --- a/data/sql/updates/db_world/2025_11_12_01.sql +++ /dev/null @@ -1,10 +0,0 @@ --- DB update 2025_11_12_00 -> 2025_11_12_01 --- --- Unliving Chocker -UPDATE `conditions` SET `ConditionTypeOrReference` = 8, `NegativeCondition` = 1, `Comment` = 'must not have completed quest \'Cleansing Drak\'Tharon\'' WHERE (`SourceTypeOrReferenceId` = 1) AND (`SourceGroup` = 28519) AND (`SourceEntry` = 38660) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 14) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 12238) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0); --- Writhing Choker -DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 1) AND (`SourceGroup` = 28519) AND (`SourceEntry` = 38673) AND (`SourceId` = 0) AND (`ElseGroup` = 0); -INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES -(1, 28519, 38673, 0, 0, 8, 0, 12238, 0, 0, 0, 0, 0, '', 'must have completed quest \'Cleansing Drak\'Tharon\''), -(1, 28519, 38673, 0, 0, 2, 0, 38660, 1, 1, 1, 0, 0, '', 'must not have item \'Unliving Chocker\''), -(1, 28519, 38673, 0, 0, 8, 0, 12631, 0, 0, 1, 0, 0, '', 'must not have completed quest \'An Invitation, of Sorts...\''); diff --git a/data/sql/updates/db_world/2025_11_12_02.sql b/data/sql/updates/db_world/2025_11_12_02.sql deleted file mode 100644 index 7daec40ee..000000000 --- a/data/sql/updates/db_world/2025_11_12_02.sql +++ /dev/null @@ -1,64 +0,0 @@ --- DB update 2025_11_12_01 -> 2025_11_12_02 --- -SET @PLANE := 28710; -SET @PILOT := 28646; -UPDATE `creature_template` SET `AIName`='SmartAI',`ScriptName`='', `speed_walk`=10, `speed_run`=1 WHERE `entry`=@PLANE; -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28710); -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 -(28710, 0, 1, 0, 60, 0, 100, 513, 1000, 1000, 0, 0, 0, 0, 53, 1, 28710, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Update - Start Waypoint Path 28710 (No Repeat)'), -(28710, 0, 2, 0, 40, 0, 100, 512, 5, 28710, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 5 of Path 28710 Reached - Say Line 0'), -(28710, 0, 3, 0, 40, 0, 100, 512, 11, 28710, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 11 of Path 28710 Reached - Say Line 1'), -(28710, 0, 4, 0, 40, 0, 100, 512, 12, 28710, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 12 of Path 28710 Reached - Say Line 2'), -(28710, 0, 5, 0, 40, 0, 100, 512, 14, 28710, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 14 of Path 28710 Reached - Say Line 3'), -(28710, 0, 6, 0, 40, 0, 100, 512, 15, 28710, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 15 of Path 28710 Reached - Say Line 4'), -(28710, 0, 7, 0, 40, 0, 100, 512, 17, 28710, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 17 of Path 28710 Reached - Say Line 5'), -(28710, 0, 8, 0, 40, 0, 100, 512, 21, 28710, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 19, 28646, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 21 of Path 28710 Reached - Say Line 6'), -(28710, 0, 9, 10, 40, 0, 100, 512, 25, 28710, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 25 of Path 28710 Reached - Say Line 0'), -(28710, 0, 10, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 52255, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 25 of Path 28710 Reached - Cast \'Engine on Fire\''), -(28710, 0, 11, 0, 28, 0, 100, 512, 0, 0, 0, 0, 0, 0, 134, 44795, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Passenger Removed - Invoker Cast \'Parachute\''), -(28710, 0, 12, 13, 8, 0, 100, 512, 52226, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Spellhit \'Land Flying Machine\' - Set Event Phase 2'), -(28710, 0, 13, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 50630, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Spellhit \'Land Flying Machine\' - Cast \'Eject All Passengers\''), -(28710, 0, 14, 0, 40, 0, 100, 512, 26, 28710, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Point 26 of Path 28710 Reached - Set Run On'), -(28710, 0, 15, 0, 28, 2, 100, 512, 0, 0, 0, 0, 0, 0, 134, 53328, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Passenger Removed - Invoker Cast \'Land Flying Machine Credit\' (Phase 2)'), -(28710, 0, 16, 0, 11, 0, 100, 512, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Respawn - Set Event Phase 1'), -(28710, 0, 17, 0, 28, 1, 100, 512, 0, 0, 0, 0, 0, 0, 6, 12671, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Vic\'s Flying Machine - On Passenger Removed - Fail Quest \'Reconnaissance Flight\' (Phase 1)'); - -DELETE FROM `waypoint_data` WHERE `id`=@PLANE; -DELETE FROM `waypoints` WHERE `entry`=@PLANE; -INSERT INTO `waypoints` (`entry`,`pointid`,`position_x`,`position_y`,`position_z`,`point_comment`) VALUES -(@PLANE,1,5494.87,4747.031,-187.8783, 'Vic''s Flying Machine'), -(@PLANE,2,5485.906,4740.681,-184.5172, 'Vic''s Flying Machine'), -(@PLANE,3,5472.882,4732.441,-172.1562, 'Vic''s Flying Machine'), -(@PLANE,4,5460.913,4712.542,-157.8784, 'Vic''s Flying Machine'), -(@PLANE,5,5452.147,4673.518,-137.8906, 'Vic''s Flying Machine'), -(@PLANE,6,5449.777,4630.711,-126.6684, 'Vic''s Flying Machine'), -(@PLANE,7,5507.432,4506.089,-126.6684, 'Vic''s Flying Machine'), -(@PLANE,8,5586.811,4465.319,-126.6684, 'Vic''s Flying Machine'), -(@PLANE,9,5676.111,4437.874,-126.6684, 'Vic''s Flying Machine'), -(@PLANE,10,5756.449,4391.051,-91.25155, 'Vic''s Flying Machine'), -(@PLANE,11,5817.163,4269.269,-91.25155, 'Vic''s Flying Machine'), -(@PLANE,12,5856.145,4202.824,-68.29334, 'Vic''s Flying Machine'), -(@PLANE,13,5921.523,4105.534,-68.29334, 'Vic''s Flying Machine'), -(@PLANE,14,5995.021,4029.883,-13.97897, 'Vic''s Flying Machine'), -(@PLANE,15,6118.298,3883.733,94.11866, 'Vic''s Flying Machine'), -(@PLANE,16,6132.932,3750.75,176.5123, 'Vic''s Flying Machine'), -(@PLANE,17,6165.863,3748.196,198.9567, 'Vic''s Flying Machine'), -(@PLANE,18,6208.277,3782.189,196.8455, 'Vic''s Flying Machine'), -(@PLANE,19,6227.615,3836.871,191.6234, 'Vic''s Flying Machine'), -(@PLANE,20,6218.483,3885.17,191.6234, 'Vic''s Flying Machine'), -(@PLANE,21,6197.045,3890.053,191.6234, 'Vic''s Flying Machine'), -(@PLANE,22,6168.752,3864.161,191.6234, 'Vic''s Flying Machine'), -(@PLANE,23,6204.037,3807.239,191.6234, 'Vic''s Flying Machine'), -(@PLANE,24,6232.975,3820.852,191.6234, 'Vic''s Flying Machine'), -(@PLANE,25,6219.879,3854.341,166.6234, 'Vic''s Flying Machine'), -(@PLANE,26,6210.428,3855.185,154.4848, 'Vic''s Flying Machine'); - -UPDATE `creature_template_movement` SET `Swim`=1,`Ground`=1,`Flight`=2 WHERE `CreatureId`=@PLANE; -DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` =14 AND `SourceGroup`=9750; -INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES -(14, 9750, 13376, 0, 0, 8, 0, 12671, 0, 0, 0, 0, 0, '', 'Pilot Vic Show different gossip if player has rewarded quest 12671 '), -(14, 9750, 13375, 0, 0, 8, 0, 12671, 0, 0, 1, 0, 0, '', 'Pilot Vic Show different gossip if player is not rewarded quest 12671'); - -DELETE FROM `vehicle_template_accessory` WHERE `entry` IN (@PLANE); -INSERT INTO `vehicle_template_accessory` (`entry`,`accessory_entry`, `seat_id`, `minion`, `description`) VALUES -(@PLANE, @PILOT, 0, 1, 'Vics Flying Machine'); diff --git a/data/sql/updates/db_world/2025_11_12_03.sql b/data/sql/updates/db_world/2025_11_12_03.sql deleted file mode 100644 index b99ae0a58..000000000 --- a/data/sql/updates/db_world/2025_11_12_03.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_12_02 -> 2025_11_12_03 --- -UPDATE `quest_offer_reward` SET `RewardText` = 'Aw yes, these will do nicely.$b$bJust plop them down anywhere. You can have some of my leftover stew from last night.' WHERE (`ID` = 11564); diff --git a/data/sql/updates/db_world/2025_11_12_04.sql b/data/sql/updates/db_world/2025_11_12_04.sql deleted file mode 100644 index d1e6b2da4..000000000 --- a/data/sql/updates/db_world/2025_11_12_04.sql +++ /dev/null @@ -1,36 +0,0 @@ --- DB update 2025_11_12_03 -> 2025_11_12_04 --- -DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 1) AND (`SourceEntry` = 5440) AND (`SourceId` = 2) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 1) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 47219) AND (`ConditionValue2` = 0) AND (`ConditionValue3` = 0); -INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES -(22, 1, 5440, 2, 0, 1, 0, 47219, 0, 0, 0, 0, 0, '', 'Areatrigger 5440 require Cleared for Teleport (47219) '); - -UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 26619; - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 26619); -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 -(26619, 0, 0, 1, 62, 0, 100, 0, 9415, 0, 0, 0, 0, 0, 11, 47219, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Paratrooper - On Gossip Option 0 Selected - Cast \'Cleared for Teleport\''), -(26619, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Paratrooper - On Gossip Option 0 Selected - Close Gossip'), -(26619, 0, 2, 0, 64, 0, 100, 0, 0, 0, 0, 0, 0, 0, 98, 9429, 12687, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Paratrooper - On Gossip Hello - Send Gossip'), -(26619, 0, 3, 4, 62, 0, 100, 0, 9429, 1, 0, 0, 0, 0, 11, 47326, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Paratrooper - On Gossip Option 1 Selected - Cast \'Create Item - Fizzcrank Practice Parachute\''), -(26619, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Fizzcrank Paratrooper - On Gossip Option 1 Selected - Close Gossip'); - -DELETE FROM `areatrigger_scripts` WHERE `entry` = 5440; -INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES (5440, 'SmartTrigger'); - -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 5440) AND (`source_type` = 2) AND (`id` IN (0)); -INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES -(5440, 2, 0, 0, 46, 0, 100, 0, 5440, 0, 0, 0, 0, 0, 62, 571, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 4240.04, 5259.05, 72.3396, 2.274780035018921, 'Areatrigger - On Trigger - Teleport'); - -DELETE FROM `gossip_menu` WHERE `MenuID` = 9429; -INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES -(9429, 12687); - -DELETE FROM `gossip_menu_option` WHERE (`OptionID`=1 AND `MenuID`=9429); -INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES -(9429, 1, 0, 'I\'ll show you! Give me that practice parachute!', 25923, 1, 1, 0, 0, 0, 0, NULL, 0, 64270); - -DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 3) AND (`SourceEntry` = 26619) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 30) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 188420) AND (`ConditionValue2` = 20) AND (`ConditionValue3` = 0); -INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES -(22, 3, 26619, 0, 0, 30, 0, 188420, 20, 0, 0, 0, 0, '', 'Requires Fizzcrank Parachute spell focus'); - -UPDATE `gameobject` SET `position_x` = 4227.6616, `position_y` = 5270.674, `position_z` = 71.928215 WHERE `guid` = 99767 AND `id` = 188420; diff --git a/data/sql/updates/db_world/2025_11_12_05.sql b/data/sql/updates/db_world/2025_11_12_05.sql deleted file mode 100644 index 4895bf0c2..000000000 --- a/data/sql/updates/db_world/2025_11_12_05.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_12_04 -> 2025_11_12_05 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 27292) AND (`source_type` = 0) AND (`id` IN (0, 1)); -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 -(27292, 0, 1, 2, 62, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 48606, 3, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Flamebringer - On Gossip Option 0 Selected - Cast \'Flamebringer Summon Cue\''); diff --git a/data/sql/updates/db_world/2025_11_12_06.sql b/data/sql/updates/db_world/2025_11_12_06.sql deleted file mode 100644 index df18f9dbc..000000000 --- a/data/sql/updates/db_world/2025_11_12_06.sql +++ /dev/null @@ -1,11 +0,0 @@ --- DB update 2025_11_12_05 -> 2025_11_12_06 - --- Update AI -UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 27254; - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 27254); -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 -(27254, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 0, 90, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Emerald Lasher - On Reset - Set Flag Standstate Submerged'), -(27254, 0, 1, 2, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 91, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Emerald Lasher - On Aggro - Remove FlagStandstate Submerged'), -(27254, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 37752, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Emerald Lasher - On Aggro - Cast \'Stand\''), -(27254, 0, 3, 0, 0, 0, 100, 0, 4000, 7000, 9000, 13000, 0, 0, 11, 51901, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Emerald Lasher - In Combat - Cast \'Dream Lash\''); diff --git a/data/sql/updates/db_world/2025_11_13_00.sql b/data/sql/updates/db_world/2025_11_13_00.sql deleted file mode 100644 index 45f7a2fcb..000000000 --- a/data/sql/updates/db_world/2025_11_13_00.sql +++ /dev/null @@ -1,8 +0,0 @@ --- DB update 2025_11_12_06 -> 2025_11_13_00 - --- Update SmartAI -UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 27358; - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 27358); -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 -(27358, 0, 0, 0, 0, 0, 100, 0, 0, 0, 7000, 10000, 0, 0, 11, 51431, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Burning Depths Necromancer - In Combat - Cast \'Power Release\''); diff --git a/data/sql/updates/db_world/2025_11_13_01.sql b/data/sql/updates/db_world/2025_11_13_01.sql deleted file mode 100644 index 722fb7277..000000000 --- a/data/sql/updates/db_world/2025_11_13_01.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_13_00 -> 2025_11_13_01 - --- Delete SmartAI -UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 30066; -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 30066) AND (`source_type` = 0); diff --git a/data/sql/updates/db_world/2025_11_13_02.sql b/data/sql/updates/db_world/2025_11_13_02.sql deleted file mode 100644 index 05b71f6cc..000000000 --- a/data/sql/updates/db_world/2025_11_13_02.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_13_01 -> 2025_11_13_02 --- -DELETE FROM `creature_template_movement` WHERE `CreatureId` = 27821; -INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Flight`) VALUES -(27821, 1, 1); diff --git a/data/sql/updates/db_world/2025_11_13_03.sql b/data/sql/updates/db_world/2025_11_13_03.sql deleted file mode 100644 index c04b81fa5..000000000 --- a/data/sql/updates/db_world/2025_11_13_03.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_13_02 -> 2025_11_13_03 --- -DELETE FROM `spell_custom_attr` WHERE `spell_id` = 53094; -INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES -(53094, 0x00400000); diff --git a/data/sql/updates/db_world/2025_11_13_04.sql b/data/sql/updates/db_world/2025_11_13_04.sql deleted file mode 100644 index ddabdc449..000000000 --- a/data/sql/updates/db_world/2025_11_13_04.sql +++ /dev/null @@ -1,53 +0,0 @@ --- DB update 2025_11_13_03 -> 2025_11_13_04 - --- Set Sniffed Unit_flag (Vrykul Harpoon Gun) -UPDATE `creature_template` SET `unit_flags` = `unit_flags` &~ 4 WHERE (`entry` = 27992); -UPDATE `creature_template` SET `unit_flags` = `unit_flags` |33554432 WHERE (`entry` = 27992); - --- Set Sniffed Movement Flags (Vrykul Harpoon Gun & Dragonflayer Defender) -DELETE FROM `creature_template_movement` WHERE (`CreatureId` IN (24533, 27992)); -INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES -(24533, 0, 0, 1, 0, 0, 0, 0), -(27992, 0, 0, 0, 1, 0, 0, 0); - --- Update SmartAI (Vrykul Harpoon Gun) -UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 27992; - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 27992); -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 -(27992, 0, 0, 0, 27, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 33554432, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Passenger Boarded - Remove Flags Not Selectable'), -(27992, 0, 1, 0, 28, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 33554432, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Passenger Removed - Set Flags Not Selectable'), -(27992, 0, 2, 3, 38, 0, 100, 512, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Data Set 1 1 - Say Line 0'), -(27992, 0, 3, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2799200, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Data Set 1 1 - Run Script'), -(27992, 0, 4, 5, 38, 0, 100, 512, 1, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Data Set 1 2 - Say Line 1'), -(27992, 0, 5, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2799201, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Data Set 1 2 - Run Script'), -(27992, 0, 6, 7, 38, 0, 100, 512, 1, 3, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Data Set 1 3 - Say Line 2'), -(27992, 0, 7, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 80, 2799202, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Data Set 1 3 - Run Script'), -(27992, 0, 8, 0, 31, 0, 100, 512, 43997, 0, 0, 0, 0, 0, 11, 43998, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vrykul Harpoon Gun - On Target Spellhit \'Fiery Lance\' - Cast \'Fiery Lance\''); - --- Update Action Lists (sniffed Spawn Points) -DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` IN (2799200, 2799201, 2799202)); -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 -(2799200, 9, 0, 0, 0, 0, 100, 512, 3000, 3000, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1055.92, -5139.29, 177.646, 4.2569, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799200, 9, 1, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1011.96, -5124.65, 185.217, 4.2505, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799200, 9, 2, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1073.53, -5130.63, 209.704, 4.0369, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799200, 9, 3, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1127.55, -5177.06, 212.394, 4.1176, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799201, 9, 0, 0, 0, 0, 100, 512, 3000, 3000, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1091.66, -5150.43, 121.44, 4.0841, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799201, 9, 1, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1024.17, -5117.84, 141.756, 4.1904, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799201, 9, 2, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 964.811, -5123.2, 111.064, 3.997, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799202, 9, 0, 0, 0, 0, 100, 512, 3000, 3000, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1132.96, -5170, 261.992, 3.9751, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799202, 9, 1, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1115.01, -5161.58, 207.852, 4.3169, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''), -(2799202, 9, 2, 0, 0, 0, 100, 512, 0, 0, 0, 0, 0, 0, 12, 24533, 4, 60000, 0, 1, 0, 8, 0, 0, 0, 0, 1168.37, -5220.4, 243.869, 3.7683, 'Vrykul Harpoon Gun - Actionlist - Summon Creature \'Dragonflayer Defender\''); - --- Set SmartAI (Dragonflayer Defender) -UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 24533; - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24533); -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 -(24533, 0, 0, 0, 0, 0, 100, 0, 500, 1000, 2000, 2000, 0, 0, 11, 44188, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - In Combat - Cast \'Harpoon Toss\''), -(24533, 0, 1, 0, 8, 0, 100, 0, 43997, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - On Spellhit \'Fiery Lance\' - Kill Self'), -(24533, 0, 2, 3, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - On Just Summoned - Disable Evade'), -(24533, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 69, 25, 0, 1, 0, 1, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - On Just Summoned - Move To Owner Or Summoner'), -(24533, 0, 4, 5, 34, 0, 100, 0, 0, 25, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - On Reached Point 25 - Set Home Position'), -(24533, 0, 5, 6, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 117, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - On Reached Point 25 - Enable Evade'), -(24533, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Dragonflayer Defender - On Reached Point 25 - Start Attacking'); diff --git a/data/sql/updates/db_world/2025_11_13_05.sql b/data/sql/updates/db_world/2025_11_13_05.sql deleted file mode 100644 index 205f572e9..000000000 --- a/data/sql/updates/db_world/2025_11_13_05.sql +++ /dev/null @@ -1,4 +0,0 @@ --- DB update 2025_11_13_04 -> 2025_11_13_05 --- Makes sure the Shaman player gets the required ritual toch item and that requires the quest to drop -UPDATE `item_loot_template` SET `Chance` = 0, `QuestRequired` = 1, `GroupId` = 1 WHERE `Entry` = 24336 AND `Item` = 23682; -UPDATE `item_loot_template` SET `Chance` = 0, `GroupId` = 2 WHERE `Entry` = 24336 AND `Item` = 24335; diff --git a/data/sql/updates/db_world/2025_11_14_00.sql b/data/sql/updates/db_world/2025_11_14_00.sql deleted file mode 100644 index ede32e340..000000000 --- a/data/sql/updates/db_world/2025_11_14_00.sql +++ /dev/null @@ -1,9 +0,0 @@ --- DB update 2025_11_13_05 -> 2025_11_14_00 --- -DELETE FROM `spell_script_names` WHERE `spell_id` = 50380; -INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES -(50380, 'spell_bloodspore_haze'); - -DELETE FROM `spell_custom_attr` WHERE `spell_id` = 50380; -INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES -(50380, 0x00400000); diff --git a/data/sql/updates/db_world/2025_11_14_01.sql b/data/sql/updates/db_world/2025_11_14_01.sql deleted file mode 100644 index 7e0fa266f..000000000 --- a/data/sql/updates/db_world/2025_11_14_01.sql +++ /dev/null @@ -1,6 +0,0 @@ --- DB update 2025_11_14_00 -> 2025_11_14_01 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29445) AND (`source_type` = 0) AND (`id` IN (0, 1)); -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 -(29445, 0, 0, 0, 62, 0, 100, 0, 9926, 0, 0, 0, 0, 0, 134, 56940, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Thorim - On Gossip Option 0 Selected - Invoker Cast \'Thorim Story Kill Credit\''), -(29445, 0, 1, 0, 19, 0, 100, 0, 12924, 0, 0, 0, 0, 0, 134, 56518, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Thorim - On Quest \'Forging an Alliance\' Taken - Invoker Cast \'Clearquests\''); diff --git a/data/sql/updates/db_world/2025_11_14_02.sql b/data/sql/updates/db_world/2025_11_14_02.sql deleted file mode 100644 index f9dc1bc72..000000000 --- a/data/sql/updates/db_world/2025_11_14_02.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_14_01 -> 2025_11_14_02 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2943400) AND (`source_type` = 9) AND (`id` IN (2)); -INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES -(2943400, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 26, 12832, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 0, 'Injured Goblin Miner - On Script - Quest Credit \'Bitter Departure\' (Stored Target)'); diff --git a/data/sql/updates/db_world/2025_11_14_03.sql b/data/sql/updates/db_world/2025_11_14_03.sql deleted file mode 100644 index 562a42a8d..000000000 --- a/data/sql/updates/db_world/2025_11_14_03.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_14_02 -> 2025_11_14_03 --- -DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 55046) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 1) AND (`ConditionTarget` = 1) AND (`ConditionValue1` = 54894) 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 -(17, 0, 55046, 0, 0, 1, 1, 54894, 0, 0, 0, 0, 0, '', 'Ice Shard require Icy Imprisionment'); diff --git a/data/sql/updates/db_world/2025_11_15_00.sql b/data/sql/updates/db_world/2025_11_15_00.sql deleted file mode 100644 index e6431368f..000000000 --- a/data/sql/updates/db_world/2025_11_15_00.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_14_03 -> 2025_11_15_00 --- -DELETE FROM `creature_loot_template` WHERE (`Entry` = 31231) AND (`Item` IN (42108)); -INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES -(31231, 42108, 0, 33, 1, 1, 0, 1, 1, 'Lost Shandaral Spirit - Scourge Curio'); diff --git a/data/sql/updates/db_world/2025_11_15_01.sql b/data/sql/updates/db_world/2025_11_15_01.sql deleted file mode 100644 index ae1732468..000000000 --- a/data/sql/updates/db_world/2025_11_15_01.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_15_00 -> 2025_11_15_01 --- fix spell focus location for quest 'Will of the Titans' -UPDATE `gameobject` SET `position_x` = 5110.11, `position_y` = 5471.22, `position_z` = -91.84 WHERE `id` = 190781 AND `guid` = 99745; diff --git a/data/sql/updates/db_world/2025_11_15_02.sql b/data/sql/updates/db_world/2025_11_15_02.sql deleted file mode 100644 index 66aad02a8..000000000 --- a/data/sql/updates/db_world/2025_11_15_02.sql +++ /dev/null @@ -1,6 +0,0 @@ --- DB update 2025_11_15_01 -> 2025_11_15_02 --- -DELETE FROM `creature_template_spell` WHERE (`CreatureID` = 35415); -INSERT INTO `creature_template_spell` (`CreatureID`, `Index`, `Spell`, `VerifiedBuild`) VALUES -(35415, 0, 68068, 0), -(35415, 1, 67442, 0); diff --git a/data/sql/updates/db_world/2025_11_15_03.sql b/data/sql/updates/db_world/2025_11_15_03.sql deleted file mode 100644 index b55a0aa0c..000000000 --- a/data/sql/updates/db_world/2025_11_15_03.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_15_02 -> 2025_11_15_03 --- -UPDATE `creature_template` SET `npcflag` = `npcflag` |65536 WHERE `entry` = 29944; diff --git a/data/sql/updates/db_world/2025_11_15_04.sql b/data/sql/updates/db_world/2025_11_15_04.sql deleted file mode 100644 index d0c7e3db7..000000000 --- a/data/sql/updates/db_world/2025_11_15_04.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_15_03 -> 2025_11_15_04 --- -UPDATE `creature_template` SET `unit_flags` = `unit_flags` &~ 256 WHERE `entry` = 24787; diff --git a/data/sql/updates/db_world/2025_11_15_05.sql b/data/sql/updates/db_world/2025_11_15_05.sql deleted file mode 100644 index 110691e3a..000000000 --- a/data/sql/updates/db_world/2025_11_15_05.sql +++ /dev/null @@ -1,6 +0,0 @@ --- DB update 2025_11_15_04 -> 2025_11_15_05 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 26841) AND (`source_type` = 0) AND (`id` IN (0, 1)); -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 -(26841, 0, 0, 0, 0, 0, 100, 0, 0, 0, 5000, 7000, 0, 0, 11, 47425, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Frost Wyrm - In Combat - Cast \'Frost Breath\''), -(26841, 0, 1, 0, 8, 0, 100, 0, 49587, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Reanimated Frost Wyrm - On Spellhit \'Seeds of Nature`s Wrath\' - Start Attacking'); diff --git a/data/sql/updates/db_world/2025_11_15_06.sql b/data/sql/updates/db_world/2025_11_15_06.sql deleted file mode 100644 index afeb1844d..000000000 --- a/data/sql/updates/db_world/2025_11_15_06.sql +++ /dev/null @@ -1,9 +0,0 @@ --- DB update 2025_11_15_05 -> 2025_11_15_06 --- -DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceEntry` = 49765); -INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES -(13, 7, 49765, 0, 0, 31, 0, 3, 27713, 0, 0, 0, 0, '', 'Fordragon Resolve target 7th Legion Elite'), -(13, 7, 49765, 0, 1, 31, 0, 3, 26780, 0, 0, 0, 0, '', 'Fordragon Resolve target 7th Legion Cleric'), -(13, 7, 49765, 0, 2, 31, 0, 3, 27587, 0, 0, 0, 0, '', 'Fordragon Resolve target Legion Commander Yorik'), -(13, 7, 49765, 0, 3, 31, 0, 3, 27858, 0, 0, 0, 0, '', 'Fordragon Resolve target Highlord Bolvar Fordragon'), -(13, 7, 49765, 0, 4, 32, 0, 16, 0, 0, 0, 0, 0, '', 'Fordragon Resolve target players'); diff --git a/data/sql/updates/db_world/2025_11_15_07.sql b/data/sql/updates/db_world/2025_11_15_07.sql deleted file mode 100644 index 459cf6f26..000000000 --- a/data/sql/updates/db_world/2025_11_15_07.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_15_06 -> 2025_11_15_07 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 2583500) AND (`source_type` = 9) AND (`id` IN (19)); -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 -(2583500, 9, 19, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 5000, 6, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Nesingwary Trapper - Actionlist - Despawn In 5000 ms'); diff --git a/data/sql/updates/db_world/2025_11_15_08.sql b/data/sql/updates/db_world/2025_11_15_08.sql deleted file mode 100644 index 6e2a4c416..000000000 --- a/data/sql/updates/db_world/2025_11_15_08.sql +++ /dev/null @@ -1,69 +0,0 @@ --- DB update 2025_11_15_07 -> 2025_11_15_08 - --- Set Creature Template Addon (Amberpine Woodsman) -DELETE FROM `creature_template_addon` WHERE (`entry` = 27293); -INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES -(27293, 0, 0, 0, 1, 0, 0, ''); - --- Update Spawn Points (Amberpine Woodsman) -UPDATE `creature` SET `position_x` = 3499.0676, `position_y` = -2838.0798, `position_z` = 202.27922, `orientation` = 2.89724, `Comment` = 'Has Guid SAI' WHERE (`id1` = 27293) AND (`guid` = 110578); -UPDATE `creature` SET `position_x` = 3497.1128, `position_y` = -2836.0088, `position_z` = 202.26859, `orientation` = 4.55530 WHERE (`id1` = 27293) AND (`guid` = 110579); -UPDATE `creature` SET `position_x` = 3474.6736, `position_y` = -2776.7188, `position_z` = 201.02751, `orientation` = 2.56563, `Comment` = 'Has Guid SAI' WHERE (`id1` = 27293) AND (`guid` = 110580); -UPDATE `creature` SET `position_x` = 3475.1519, `position_y` = -2774.3525, `position_z` = 200.75826, `orientation` = 3.59537 WHERE (`id1` = 27293) AND (`guid` = 110581); -UPDATE `creature` SET `position_x` = 3374.5999, `position_y` = -2805.997, `position_z` = 199.0484, `orientation` = 1.34390, `Comment` = 'Has Guid SAI' WHERE (`id1` = 27293) AND (`guid` = 110582); -UPDATE `creature` SET `position_x` = 3375.972, `position_y` = -2803.756, `position_z` = 199.01216, `orientation` = 3.99680 WHERE (`id1` = 27293) AND (`guid` = 110583); -UPDATE `creature` SET `position_x` = 3460.5964, `position_y` = -2902.6494, `position_z` = 201.07785, `orientation` = 5.89921, `Comment` = 'Has Guid SAI' WHERE (`id1` = 27293) AND (`guid` = 110602); -UPDATE `creature` SET `position_x` = 3460.07, `position_y` = -2904.9836, `position_z` = 201.10063, `orientation` = 0.52359 WHERE (`id1` = 27293) AND (`guid` = 110603); -UPDATE `creature` SET `position_x` = 3390.5305, `position_y` = -2862.014, `position_z` = 199.62068, `orientation` = 3.24631 WHERE (`id1` = 27293) AND (`guid` = 110604); -UPDATE `creature` SET `position_x` = 3390.0286, `position_y` = -2864.7012, `position_z` = 200.0756, `orientation` = 2.56563, `Comment` = 'Has Guid SAI' WHERE (`id1` = 27293) AND (`guid` = 110605); - --- Set Creature Addon (Amberpine Woodsman) -DELETE FROM `creature_addon` WHERE (`guid` IN (110578, 110579, 110580, 110581, 110582, 110583, 110602, 110603, 110604, 110605)); -INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES -(110578, 0, 0, 8, 0, 0, 0, NULL), -(110579, 0, 0, 0, 0, 133, 0, NULL), -(110580, 0, 0, 8, 0, 0, 0, NULL), -(110581, 0, 0, 0, 0, 133, 0, NULL), -(110582, 0, 0, 8, 0, 0, 0, NULL), -(110583, 0, 0, 0, 0, 133, 0, NULL), -(110602, 0, 0, 8, 0, 0, 0, NULL), -(110603, 0, 0, 0, 0, 133, 0, NULL), -(110604, 0, 0, 0, 0, 133, 0, NULL), -(110605, 0, 0, 8, 0, 0, 0, NULL); - --- Remove Script Name and set SmartAI (Amberpine Woodsman) -UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE (`entry` = 27293); - --- Set Guid SmartAI -DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (-110578, -110580, -110582, -110602, -110605)); -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 -(-110578, 0, 0, 0, 1, 0, 100, 0, 1000, 3000, 500, 3000, 0, 0, 5, 36, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Amberpine Woodsman - Out of Combat - Play Emote 36'), -(-110580, 0, 0, 0, 1, 0, 100, 0, 1000, 3000, 500, 3000, 0, 0, 5, 36, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Amberpine Woodsman - Out of Combat - Play Emote 36'), -(-110582, 0, 0, 0, 1, 0, 100, 0, 1000, 3000, 500, 3000, 0, 0, 5, 36, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Amberpine Woodsman - Out of Combat - Play Emote 36'), -(-110602, 0, 0, 0, 1, 0, 100, 0, 1000, 3000, 500, 3000, 0, 0, 5, 36, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Amberpine Woodsman - Out of Combat - Play Emote 36'), -(-110605, 0, 0, 0, 1, 0, 100, 0, 1000, 3000, 500, 3000, 0, 0, 5, 36, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Amberpine Woodsman - Out of Combat - Play Emote 36'); - --- Remove Script Name and set SmartAI (Tallhorn Stag) -UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE (`entry` = 26363); - --- Set Comments (Tallhorn Stag) -UPDATE `creature` SET `Comment` = 'Has Personal SAI' WHERE (`id1` = 26363) AND (`guid` IN (119621, 119622, 119642, 119643, 119656)); - --- Set Guid Sai (Tallhorn Stag) -DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (-119621, -119622, -119642, -119643, -119656)); -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 -(-119621, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 537166592, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Immune To Players & Immune To NPC\'s & Stunned & Prevent Emotes From Chat Text'), -(-119621, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Feign Death'), -(-119621, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 29266, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Cast \'Permanent Feign Death\''), -(-119622, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 537166592, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Immune To Players & Immune To NPC\'s & Stunned & Prevent Emotes From Chat Text'), -(-119622, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Feign Death'), -(-119622, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 29266, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Cast \'Permanent Feign Death\''), -(-119642, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 537166592, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Immune To Players & Immune To NPC\'s & Stunned & Prevent Emotes From Chat Text'), -(-119642, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Feign Death'), -(-119642, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 29266, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Cast \'Permanent Feign Death\''), -(-119643, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 537166592, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Immune To Players & Immune To NPC\'s & Stunned & Prevent Emotes From Chat Text'), -(-119643, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Feign Death'), -(-119643, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 29266, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Cast \'Permanent Feign Death\''), -(-119656, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 537166592, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Immune To Players & Immune To NPC\'s & Stunned & Prevent Emotes From Chat Text'), -(-119656, 0, 1, 2, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 18, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Set Flags Feign Death'), -(-119656, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 29266, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tallhorn Stag - On Respawn - Cast \'Permanent Feign Death\''); diff --git a/data/sql/updates/db_world/2025_11_15_09.sql b/data/sql/updates/db_world/2025_11_15_09.sql deleted file mode 100644 index f86f64964..000000000 --- a/data/sql/updates/db_world/2025_11_15_09.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_15_08 -> 2025_11_15_09 - -UPDATE `creature_template` SET `flags_extra` = `flags_extra` |128 WHERE (`entry` = 25739); diff --git a/data/sql/updates/db_world/2025_11_15_10.sql b/data/sql/updates/db_world/2025_11_15_10.sql deleted file mode 100644 index 63a030b74..000000000 --- a/data/sql/updates/db_world/2025_11_15_10.sql +++ /dev/null @@ -1,9 +0,0 @@ --- DB update 2025_11_15_09 -> 2025_11_15_10 --- -DELETE FROM `spell_linked_spell` WHERE `spell_trigger` = 54076; -INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES -(54076, 49511, 0, 'Taxi validate - Gryphon to Star Rest'); - -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 26878) AND (`source_type` = 0) AND (`id` IN (3)); -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 -(26878, 0, 3, 0, 19, 0, 100, 0, 12440, 0, 0, 0, 0, 0, 11, 54076, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Rodney Wells - On Quest \'To Stars\' Rest!\' Taken - Cast \'Taxi to Stars` Rest Validate\''); diff --git a/data/sql/updates/db_world/2025_11_15_11.sql b/data/sql/updates/db_world/2025_11_15_11.sql deleted file mode 100644 index 6350fbdb8..000000000 --- a/data/sql/updates/db_world/2025_11_15_11.sql +++ /dev/null @@ -1,14 +0,0 @@ --- DB update 2025_11_15_10 -> 2025_11_15_11 - --- Add Immune To PC, Immune To Npc, Stunned, Prevent Emotes, Feign Death and remove All Dynamic Flags (Sniffed) -UPDATE `creature_template` SET `unit_flags` = `unit_flags` |256|512|262144|536870912, `unit_flags2` = `unit_flags2` |1, `dynamicflags` = 0 WHERE (`entry` = 26514); - --- Add Aura (Sniffed) -DELETE FROM `creature_template_addon` WHERE (`entry` = 26514); -INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES -(26514, 0, 0, 0, 0, 0, 0, '29266'); - --- Add Disable Gravity and Rooted (Sniffed) -DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 26514); -INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES -(26514, 0, 0, 1, 1, 0, 0, 0); diff --git a/data/sql/updates/db_world/2025_11_15_12.sql b/data/sql/updates/db_world/2025_11_15_12.sql deleted file mode 100644 index cb70c3834..000000000 --- a/data/sql/updates/db_world/2025_11_15_12.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_15_11 -> 2025_11_15_12 --- -UPDATE `creature_loot_template` SET `Chance` = 100 WHERE `item` = 43159 AND `entry` = 30746; diff --git a/data/sql/updates/db_world/2025_11_15_13.sql b/data/sql/updates/db_world/2025_11_15_13.sql deleted file mode 100644 index 69bb6ab04..000000000 --- a/data/sql/updates/db_world/2025_11_15_13.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_15_12 -> 2025_11_15_13 --- -DELETE FROM `spell_proc_event` WHERE `entry`= 45278; -INSERT INTO `spell_proc_event` (`entry`, `procFlags`) VALUES -(45278, 0x00004400|0x00010000); diff --git a/data/sql/updates/db_world/2025_11_15_14.sql b/data/sql/updates/db_world/2025_11_15_14.sql deleted file mode 100644 index 18691bf41..000000000 --- a/data/sql/updates/db_world/2025_11_15_14.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_15_13 -> 2025_11_15_14 -DELETE FROM `smart_scripts` WHERE `entryorguid` = 27598 AND `source_type` = 0; -UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 27598; diff --git a/data/sql/updates/db_world/2025_11_15_15.sql b/data/sql/updates/db_world/2025_11_15_15.sql deleted file mode 100644 index c0e0fce5b..000000000 --- a/data/sql/updates/db_world/2025_11_15_15.sql +++ /dev/null @@ -1,31 +0,0 @@ --- DB update 2025_11_15_14 -> 2025_11_15_15 --- -SET @MAXSTANDING := 7; -SET @REPSUMMONS := 1; -SET @REPREGULAR := 4; -SET @REPHULK := 10; -SET @REPBOSS := 50; -DELETE FROM `creature_onkill_reputation` WHERE `creature_id` IN (26553, 26554, 26550, 26555, 26668, 26669, 26670, 26672, 26685, 26683, 26684, -26686, 26687, 26692, 26690, 26691, 26693, 28368, 26696, 26694, 26861); -INSERT INTO `creature_onkill_reputation` (`creature_id`, `RewOnKillRepFaction1`, `RewOnKillRepFaction2`, `MaxStanding1`, `RewOnKillRepValue1`, `MaxStanding2`, `RewOnKillRepValue2`, `TeamDependent`) VALUES -(26550, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Dragonflayer Deathseeker -(26553, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Dragonflayer Fanatic -(26554, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Dragonflayer Seer -(26555, 1037, 1052, @MAXSTANDING, @REPHULK, @MAXSTANDING, @REPHULK, 1), -- Scourge Hulk -(26668, 1037, 1052, @MAXSTANDING, @REPBOSS, @MAXSTANDING, @REPBOSS, 1), -- Svala -(26669, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ymirjar Savage -(26670, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ymirjar Flesh Hunter -(26672, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Bloodthirsty Tundra Wolf -(26685, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Massive Jormungar -(26683, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Frenzied Worgen -(26684, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ravenous Furbog -(26686, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ferocious Rhino -(26687, 1037, 1052, @MAXSTANDING, @REPBOSS, @MAXSTANDING, @REPBOSS, 1), -- Gortok -(26692, 1037, 1052, @MAXSTANDING, @REPSUMMONS, @MAXSTANDING, @REPSUMMONS, 1), -- Ymirjar Harpooner (Skadi) -(26690, 1037, 1052, @MAXSTANDING, @REPSUMMONS, @MAXSTANDING, @REPSUMMONS, 1), -- Ymirjar Warrior (Skadi) -(26691, 1037, 1052, @MAXSTANDING, @REPSUMMONS, @MAXSTANDING, @REPSUMMONS, 1), -- Ymirjar Shaman (Skadi) -(26693, 1037, 1052, @MAXSTANDING, @REPBOSS, @MAXSTANDING, @REPBOSS, 1), -- Skadi -(28368, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ymirjar Necromancer -(26696, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ymirjar Berserker -(26694, 1037, 1052, @MAXSTANDING, @REPREGULAR, @MAXSTANDING, @REPREGULAR, 1), -- Ymirjar Dark Shaman -(26861, 1037, 1052, @MAXSTANDING, @REPBOSS, @MAXSTANDING, @REPBOSS, 1); -- Ymiron diff --git a/data/sql/updates/db_world/2025_11_16_00.sql b/data/sql/updates/db_world/2025_11_16_00.sql deleted file mode 100644 index 517458edd..000000000 --- a/data/sql/updates/db_world/2025_11_16_00.sql +++ /dev/null @@ -1,10 +0,0 @@ --- DB update 2025_11_15_15 -> 2025_11_16_00 --- -SET @REPTRASH := 1; -SET @REPREGULAR := 5; -SET @REPHULK := 10; -SET @REPBOSS := 50; -UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPTRASH, `RewOnKillRepValue2` = @REPTRASH WHERE `creature_id` IN (27636, 27638); -UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPREGULAR, `RewOnKillRepValue2` = @REPREGULAR WHERE `creature_id` IN (26550, 26553, 26554, 26669, 26670, 26672, 26685, 26683, 26684, 26686, 28368, 26696, 26694); -- UP -UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPREGULAR, `RewOnKillRepValue2` = @REPREGULAR WHERE `creature_id` IN (27635, 27633, 27641, 27639, 27640, 27653, 27651, 27650, 27648, 27647, 27649, 27645, 27644, 27642); -- Oculus -UPDATE `creature_onkill_reputation` SET `RewOnKillRepValue1` = @REPBOSS, `RewOnKillRepValue2` = @REPBOSS WHERE `creature_id` IN (27654, 27447, 27655, 27656); diff --git a/data/sql/updates/db_world/2025_11_16_01.sql b/data/sql/updates/db_world/2025_11_16_01.sql deleted file mode 100644 index ddd2f9424..000000000 --- a/data/sql/updates/db_world/2025_11_16_01.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_16_00 -> 2025_11_16_01 --- -UPDATE `quest_template_addon` SET `PrevQuestID` = 12611 WHERE (`ID` = 12805); diff --git a/data/sql/updates/db_world/2025_11_16_02.sql b/data/sql/updates/db_world/2025_11_16_02.sql deleted file mode 100644 index 5730eeb0f..000000000 --- a/data/sql/updates/db_world/2025_11_16_02.sql +++ /dev/null @@ -1,3 +0,0 @@ --- DB update 2025_11_16_01 -> 2025_11_16_02 --- -UPDATE `quest_template_addon` SET `PrevQuestID` = 0 WHERE (`ID` = 12827); diff --git a/data/sql/updates/db_world/2025_11_17_00.sql b/data/sql/updates/db_world/2025_11_17_00.sql deleted file mode 100644 index 524b3c133..000000000 --- a/data/sql/updates/db_world/2025_11_17_00.sql +++ /dev/null @@ -1,19 +0,0 @@ --- DB update 2025_11_16_02 -> 2025_11_17_00 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 24825) AND (`source_type` = 0) AND (`id` IN (2, 3, 4, 5, 6, 7)); -INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES -(24825, 0, 2, 0, 72, 0, 100, 512, 1, 0, 0, 0, 0, 0, 53, 2, 24826, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Action 1 Done - Start Waypoint Path 24826'), -(24825, 0, 3, 0, 72, 0, 100, 512, 2, 0, 0, 0, 0, 0, 53, 2, 24827, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Action 2 Done - Start Waypoint Path 24827'), -(24825, 0, 4, 0, 72, 0, 100, 512, 3, 0, 0, 0, 0, 0, 53, 2, 24828, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Action 3 Done - Start Waypoint Path 24828'), -(24825, 0, 5, 0, 72, 0, 100, 512, 4, 0, 0, 0, 0, 0, 53, 2, 24831, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Action 4 Done - Start Waypoint Path 24831'), -(24825, 0, 6, 0, 72, 0, 100, 512, 5, 0, 0, 0, 0, 0, 53, 2, 24829, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Action 5 Done - Start Waypoint Path 24829'), -(24825, 0, 7, 0, 72, 0, 100, 512, 6, 0, 0, 0, 0, 0, 53, 2, 24832, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Action 6 Done - Start Waypoint Path 24832'); - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (24826, 24827, 24828, 24829, 24831, 24832)); -INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES -(24826, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Do Action 1'), -(24827, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 223, 2, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Do Action 2'), -(24828, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 223, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Do Action 3'), -(24831, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 223, 4, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Do Action 4'), -(24829, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 223, 5, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Do Action 5'), -(24832, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 223, 6, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Do Action 6'); diff --git a/data/sql/updates/db_world/2025_11_17_01.sql b/data/sql/updates/db_world/2025_11_17_01.sql deleted file mode 100644 index 4631988b5..000000000 --- a/data/sql/updates/db_world/2025_11_17_01.sql +++ /dev/null @@ -1,5 +0,0 @@ --- DB update 2025_11_17_00 -> 2025_11_17_01 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 27292) AND (`source_type` = 0) AND (`id` IN (1)); -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 -(27292, 0, 1, 2, 62, 0, 100, 512, 9512, 0, 0, 0, 0, 0, 11, 48606, 3, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Flamebringer - On Gossip Option 0 Selected - Cast \'Flamebringer Summon Cue\''); diff --git a/data/sql/updates/db_world/2025_11_17_02.sql b/data/sql/updates/db_world/2025_11_17_02.sql deleted file mode 100644 index de286ebd9..000000000 --- a/data/sql/updates/db_world/2025_11_17_02.sql +++ /dev/null @@ -1,22 +0,0 @@ --- DB update 2025_11_17_01 -> 2025_11_17_02 - --- Set Spelldifficulty -DELETE FROM `spelldifficulty_dbc` WHERE (`ID` IN (52534, 52535)); -INSERT INTO `spelldifficulty_dbc` (`ID`,`DifficultySpellID_1`,`DifficultySpellID_2`,`DifficultySpellID_3`,`DifficultySpellID_4`) VALUES -(52534, 52534, 59357, 0, 0), -(52535, 52535, 59358, 0, 0); - --- Update SmartAIs (call for help and comments). -UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (28732, 28733, 28734)); - -DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (28732, 28733, 28734)); -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 -(28732, 0, 0, 0, 0, 0, 100, 0, 2000, 5000, 6000, 8000, 0, 0, 11, 52532, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Warrior - In Combat - Cast \'Strike\''), -(28732, 0, 1, 0, 0, 0, 100, 0, 2000, 10000, 15000, 15000, 0, 0, 11, 49806, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Warrior - In Combat - Cast \'Cleave\''), -(28732, 0, 2, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 39, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Warrior - On Aggro - Call For Help'), -(28733, 0, 0, 0, 0, 0, 100, 0, 0, 0, 2000, 2500, 0, 0, 11, 52534, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Shadowcaster - In Combat - Cast \'Shadow Bolt\''), -(28733, 0, 1, 0, 0, 0, 100, 0, 6000, 12000, 12000, 20000, 0, 0, 11, 52535, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Shadowcaster - In Combat - Cast \'Shadow Nova\''), -(28733, 0, 2, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 39, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Shadowcaster - On Aggro - Call For Help'), -(28734, 0, 0, 0, 67, 0, 100, 0, 7000, 7000, 7000, 7000, 0, 5, 11, 52540, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Skirmisher - On Behind Target - Cast \'Backstab\''), -(28734, 0, 1, 0, 0, 0, 100, 0, 5000, 10000, 15000, 15000, 0, 0, 11, 52536, 0, 0, 0, 0, 0, 5, 40, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Skirmisher - In Combat - Cast \'Fixate Trigger\''), -(28734, 0, 2, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 39, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Skirmisher - On Aggro - Call For Help'); diff --git a/data/sql/updates/db_world/2025_11_17_03.sql b/data/sql/updates/db_world/2025_11_17_03.sql deleted file mode 100644 index dd3e4e34f..000000000 --- a/data/sql/updates/db_world/2025_11_17_03.sql +++ /dev/null @@ -1,8 +0,0 @@ --- DB update 2025_11_17_02 -> 2025_11_17_03 --- -DELETE FROM `smart_scripts` WHERE (`entryorguid` = 26814) AND (`source_type` = 0) AND (`id` IN (2, 4, 21, 32)); -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 -(26814, 0, 2, 32, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 71, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Harrison Jones - On Respawn - Change Equipment'), -(26814, 0, 4, 21, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 'Harrison Jones - On Quest \'Dun-da-Dun-tah!\' Taken - Store Targetlist'), -(26814, 0, 21, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 83, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Harrison Jones - On Quest \'Dun-da-Dun-tah!\' Taken - Remove Npc Flags Questgiver'), -(26814, 0, 32, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 82, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Harrison Jones - On Respawn - Add Npc Flags Questgiver'); diff --git a/deps/boost/CMakeLists.txt b/deps/boost/CMakeLists.txt index c41ce041a..783356283 100644 --- a/deps/boost/CMakeLists.txt +++ b/deps/boost/CMakeLists.txt @@ -32,7 +32,7 @@ else() endif() # Boost.System is header-only since 1.69; do not require it explicitly. -find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED COMPONENTS filesystem program_options iostreams regex) +find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED COMPONENTS filesystem program_options iostreams regex thread) if(NOT Boost_FOUND) if(NOT DEFINED ENV{Boost_ROOT} AND NOT DEFINED Boost_DIR AND NOT DEFINED BOOST_ROOT AND NOT DEFINED BOOSTROOT) diff --git a/deps/recastnavigation/Detour/CMakeLists.txt b/deps/recastnavigation/Detour/CMakeLists.txt index e1294b0e0..e658bef15 100644 --- a/deps/recastnavigation/Detour/CMakeLists.txt +++ b/deps/recastnavigation/Detour/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright (C) 2008-2016 TrinityCore -# Copyright (C) 2016+ AzerothCore +# Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without diff --git a/deps/recastnavigation/Recast/CMakeLists.txt b/deps/recastnavigation/Recast/CMakeLists.txt index c54d570c3..ab1641bad 100644 --- a/deps/recastnavigation/Recast/CMakeLists.txt +++ b/deps/recastnavigation/Recast/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright (C) 2008-2016 TrinityCore -# Copyright (C) 2016+ AzerothCore +# Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without diff --git a/doc/changelog/master.md b/doc/changelog/master.md index 59b9f7bb9..3cd001b8d 100644 --- a/doc/changelog/master.md +++ b/doc/changelog/master.md @@ -414,7 +414,7 @@ minimal-dynamic - builds commands and spells dynamically. Now don't support - Example loader script for modules: ```cpp /* - * Copyright (C) 2016+ AzerothCore + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ // From SC diff --git a/doc/changelog/pendings/changes_1647137971165231200.md b/doc/changelog/pendings/changes_1647137971165231200.md new file mode 100644 index 000000000..86f51b9af --- /dev/null +++ b/doc/changelog/pendings/changes_1647137971165231200.md @@ -0,0 +1,7 @@ +### Added + +- New hook for OnQuestComputeXP(). The intended use is to change the XP values for certain quests programmatically. The hook is triggered after XP calculation and before rewarding XP or gold to the player. + +### How to upgrade + +- No special changes needed. The new hook is available for use and should not interfere with any existing hooks or logic. diff --git a/docker-compose.yml b/docker-compose.yml index 4c6525df0..f14f6dac8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -75,6 +75,7 @@ services: 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_PLAYERBOTS_DATABASE_INFO: "ac-database;3306;root;${DOCKER_DB_ROOT_PASSWORD:-password};acore_playerbots" ports: - ${DOCKER_WORLD_EXTERNAL_PORT:-8085}:8085 - ${DOCKER_SOAP_EXTERNAL_PORT:-7878}:7878 diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index fd36c5068..a4b8c14c6 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -37,6 +37,7 @@ set("AC_MODULE_LIST" "") set("AC_SCRIPTS_LIST" "") set(MOD_ALE_FOUND 0) set(MOD_ALE_PATH "") +set(MOD_PLAYERBOTS_FOUND 0) foreach(include ${AC_ADD_SCRIPTS_INCLUDE}) set("AC_SCRIPTS_INCLUDES" "#include \"${include}\"\n${AC_SCRIPTS_INCLUDES}") @@ -81,6 +82,16 @@ foreach(SOURCE_MODULE ${MODULES_MODULE_LIST}) ConfigureALEModule(${SOURCE_MODULE}) endif() + if (SOURCE_MODULE MATCHES "mod-playerbots") + set(MOD_PLAYERBOTS_FOUND 1) + target_compile_options(database + PRIVATE + -DMOD_PLAYERBOTS) + target_compile_options(game-interface + INTERFACE + -DMOD_PLAYERBOTS) + endif() + # Build the Graph values if(${MODULE_MODULE_VARIABLE} MATCHES "dynamic") GetProjectNameOfModuleName(${SOURCE_MODULE} MODULE_SOURCE_PROJECT_NAME) @@ -289,6 +300,7 @@ endif() target_link_libraries(modules PRIVATE acore-core-interface + mysql PUBLIC game-interface) @@ -363,6 +375,12 @@ target_compile_options(modules INTERFACE -DCONFIG_FILE_LIST=$<1:"${CONFIG_LIST}">) +if (MOD_PLAYERBOTS_FOUND) + target_compile_options(modules + PRIVATE + -DMOD_PLAYERBOTS) +endif() + if (MOD_ALE_FOUND) if (APPLE) target_compile_definitions(modules diff --git a/src/common/Collision/BoundingIntervalHierarchy.h b/src/common/Collision/BoundingIntervalHierarchy.h index 84aa01139..d9fcc17b5 100644 --- a/src/common/Collision/BoundingIntervalHierarchy.h +++ b/src/common/Collision/BoundingIntervalHierarchy.h @@ -70,7 +70,6 @@ private: { tree.clear(); objects.clear(); - bounds = G3D::AABox::empty(); // create space for the first node tree.push_back(3u << 30u); // dummy leaf tree.insert(tree.end(), 2, 0); @@ -117,7 +116,6 @@ public: delete[] dat.indices; } [[nodiscard]] uint32 primCount() const { return objects.size(); } - G3D::AABox const& bound() const { return bounds; } template void intersectRay(const G3D::Ray& r, RayCallback& intersectCallback, float& maxDist, bool stopAtFirstHit) const diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp index 0025bf998..08ccac79d 100644 --- a/src/common/Collision/DynamicTree.cpp +++ b/src/common/Collision/DynamicTree.cpp @@ -170,6 +170,25 @@ private: VMAP::ModelIgnoreFlags _ignoreFlags; }; +struct DynamicTreeAreaInfoCallback +{ + DynamicTreeAreaInfoCallback(uint32 phaseMask) : _phaseMask(phaseMask) { } + + void operator()(G3D::Vector3 const& p, GameObjectModel const& obj) + { + obj.IntersectPoint(p, _areaInfo, _phaseMask); + } + + VMAP::AreaInfo const& GetAreaInfo() const + { + return _areaInfo; + } + +private: + uint32 _phaseMask; + VMAP::AreaInfo _areaInfo; +}; + struct DynamicTreeLocationInfoCallback { DynamicTreeLocationInfoCallback(uint32 phaseMask) @@ -289,7 +308,24 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, } } -bool DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, Optional reqLiquidType, VMAP::AreaAndLiquidData& data) const +bool DynamicMapTree::GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const +{ + G3D::Vector3 v(x, y, z + 0.5f); + DynamicTreeAreaInfoCallback intersectionCallBack(phasemask); + impl->intersectPoint(v, intersectionCallBack); + if (intersectionCallBack.GetAreaInfo().result) + { + flags = intersectionCallBack.GetAreaInfo().flags; + adtId = intersectionCallBack.GetAreaInfo().adtId; + rootId = intersectionCallBack.GetAreaInfo().rootId; + groupId = intersectionCallBack.GetAreaInfo().groupId; + z = intersectionCallBack.GetAreaInfo().ground_Z; + return true; + } + return false; +} + +void DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const { G3D::Vector3 v(x, y, z + 0.5f); DynamicTreeLocationInfoCallback intersectionCallBack(phasemask); @@ -299,16 +335,13 @@ bool DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phas data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z; uint32 liquidType = intersectionCallBack.GetLocationInfo().hitModel->GetLiquidType(); float liquidLevel; - if (!reqLiquidType || (dynamic_cast(VMAP::VMapFactory::createOrGetVMapMgr())->GetLiquidFlagsPtr(liquidType) & *reqLiquidType)) + if (!reqLiquidType || (dynamic_cast(VMAP::VMapFactory::createOrGetVMapMgr())->GetLiquidFlagsPtr(liquidType) & reqLiquidType)) if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), liquidLevel)) data.liquidInfo.emplace(liquidType, liquidLevel); - data.areaInfo.emplace(intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(), - 0, + data.areaInfo.emplace(0, intersectionCallBack.GetLocationInfo().rootId, - intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags(), - 0); - return true; + intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(), + intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags()); } - return false; } diff --git a/src/common/Collision/DynamicTree.h b/src/common/Collision/DynamicTree.h index e2ddca550..62bd7a85d 100644 --- a/src/common/Collision/DynamicTree.h +++ b/src/common/Collision/DynamicTree.h @@ -19,7 +19,6 @@ #define _DYNTREE_H #include "Define.h" -#include "Optional.h" namespace G3D { @@ -48,7 +47,8 @@ public: bool GetIntersectionTime(uint32 phasemask, const G3D::Ray& ray, const G3D::Vector3& endPos, float& maxDist) const; - bool GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, Optional reqLiquidType, VMAP::AreaAndLiquidData& data) const; + bool GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const; + void GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const; bool GetObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1, const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos, diff --git a/src/common/Collision/Management/IVMapMgr.h b/src/common/Collision/Management/IVMapMgr.h index 410743f76..f99c957c3 100644 --- a/src/common/Collision/Management/IVMapMgr.h +++ b/src/common/Collision/Management/IVMapMgr.h @@ -52,23 +52,20 @@ namespace VMAP { struct AreaInfo { - AreaInfo() = default; - AreaInfo(int32 _groupId, int32 _adtId, int32 _rootId, uint32 _mogpFlags, uint32 _uniqueId) - : groupId(_groupId), adtId(_adtId), rootId(_rootId), mogpFlags(_mogpFlags), uniqueId(_uniqueId) { } - int32 groupId = 0; - int32 adtId = 0; - int32 rootId = 0; - uint32 mogpFlags = 0; - uint32 uniqueId = 0; + AreaInfo(int32 _adtId, int32 _rootId, int32 _groupId, uint32 _flags) + : adtId(_adtId), rootId(_rootId), groupId(_groupId), mogpFlags(_flags) { } + int32 const adtId; + int32 const rootId; + int32 const groupId; + uint32 const mogpFlags; }; struct LiquidInfo { - LiquidInfo() = default; LiquidInfo(uint32 _type, float _level) : type(_type), level(_level) {} - uint32 type = 0; - float level = 0.0f; + uint32 const type; + float const level; }; float floorZ = VMAP_INVALID_HEIGHT; @@ -123,12 +120,14 @@ namespace VMAP [[nodiscard]] bool isMapLoadingEnabled() const { return (iEnableLineOfSightCalc || iEnableHeightCalc ); } [[nodiscard]] virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const = 0; - /** Query world model area info. \param z gets adjusted to the ground height for which this are info is valid */ - virtual bool GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional reqLiquidType, AreaAndLiquidData& data) const = 0; + virtual bool GetAreaInfo(uint32 pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const = 0; + virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const = 0; + // get both area + liquid data in a single vmap lookup + virtual void GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const = 0; }; } diff --git a/src/common/Collision/Management/MMapMgr.cpp b/src/common/Collision/Management/MMapMgr.cpp index d3c450097..77db7fbbc 100644 --- a/src/common/Collision/Management/MMapMgr.cpp +++ b/src/common/Collision/Management/MMapMgr.cpp @@ -138,7 +138,8 @@ namespace MMAP uint32 packedGridPos = packTileID(x, y); if (mmap->loadedTileRefs.find(packedGridPos) != mmap->loadedTileRefs.end()) { - LOG_ERROR("maps", "MMAP:loadMap: Asked to load already loaded navmesh tile. {:03}{:02}{:02}.mmtile", mapId, x, y); + // Peiru: Commented out for now because Playerbots system uses this method to load or check loaded maps and will spam logs +// LOG_ERROR("maps", "MMAP:loadMap: Asked to load already loaded navmesh tile. {:03}{:02}{:02}.mmtile", mapId, x, y); return false; } diff --git a/src/common/Collision/Management/VMapMgr2.cpp b/src/common/Collision/Management/VMapMgr2.cpp index 7639c9c6b..46df0b330 100644 --- a/src/common/Collision/Management/VMapMgr2.cpp +++ b/src/common/Collision/Management/VMapMgr2.cpp @@ -253,8 +253,70 @@ namespace VMAP return VMAP_INVALID_HEIGHT_VALUE; } - bool VMapMgr2::GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional reqLiquidType, AreaAndLiquidData& data) const + bool VMapMgr2::GetAreaInfo(uint32 mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const { +#if defined(ENABLE_VMAP_CHECKS) + if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) +#endif + { + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); + if (instanceTree != iInstanceMapTrees.end()) + { + Vector3 pos = convertPositionToInternalRep(x, y, z); + bool result = instanceTree->second->GetAreaInfo(pos, flags, adtId, rootId, groupId); + // z is not touched by convertPositionToInternalRep(), so just copy + z = pos.z; + return result; + } + } + + return false; + } + + bool VMapMgr2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const + { +#if defined(ENABLE_VMAP_CHECKS) + if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) +#endif + { + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); + if (instanceTree != iInstanceMapTrees.end()) + { + LocationInfo info; + Vector3 pos = convertPositionToInternalRep(x, y, z); + if (instanceTree->second->GetLocationInfo(pos, info)) + { + floor = info.ground_Z; + ASSERT(floor < std::numeric_limits::max()); + type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc + mogpFlags = info.hitModel->GetMogpFlags(); + if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType)) + { + return false; + } + if (info.hitInstance->GetLiquidLevel(pos, info, level)) + { + return true; + } + } + } + } + + return false; + } + + void VMapMgr2::GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const + { + if (IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) + { + data.floorZ = z; + int32 adtId, rootId, groupId; + uint32 flags; + if (GetAreaInfo(mapId, x, y, data.floorZ, flags, adtId, rootId, groupId)) + data.areaInfo.emplace(adtId, rootId, groupId, flags); + return; + } + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); if (instanceTree != iInstanceMapTrees.end()) { @@ -263,22 +325,16 @@ namespace VMAP if (instanceTree->second->GetLocationInfo(pos, info)) { data.floorZ = info.ground_Z; - if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) - { - uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc - float liquidLevel; - if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & *reqLiquidType)) - if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel)) - data.liquidInfo.emplace(liquidType, liquidLevel); - } + uint32 liquidType = info.hitModel->GetLiquidType(); + float liquidLevel; + if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & reqLiquidType)) + if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel)) + data.liquidInfo.emplace(liquidType, liquidLevel); if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) - data.areaInfo.emplace(info.hitModel->GetWmoID(), info.hitInstance->adtId, info.rootId, info.hitModel->GetMogpFlags(), info.hitInstance->ID); - return true; + data.areaInfo.emplace(info.hitInstance->adtId, info.rootId, info.hitModel->GetWmoID(), info.hitModel->GetMogpFlags()); } } - - return false; } WorldModel* VMapMgr2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */) diff --git a/src/common/Collision/Management/VMapMgr2.h b/src/common/Collision/Management/VMapMgr2.h index 5fc4106d2..8eb7ff823 100644 --- a/src/common/Collision/Management/VMapMgr2.h +++ b/src/common/Collision/Management/VMapMgr2.h @@ -115,7 +115,9 @@ namespace VMAP bool processCommand(char* /*command*/) override { return false; } // for debug and extensions - bool GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional reqLiquidType, AreaAndLiquidData& data) const override; + bool GetAreaInfo(uint32 pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override; + bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const override; + void GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const override; WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags); void releaseModelInstance(const std::string& filename); diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index bb9577d4e..66c711c9c 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -51,6 +51,22 @@ namespace VMAP bool hit; }; + class AreaInfoCallback + { + public: + AreaInfoCallback(ModelInstance* val): prims(val) {} + void operator()(const Vector3& point, uint32 entry) + { +#if defined(VMAP_DEBUG) + LOG_DEBUG("maps", "AreaInfoCallback: trying to intersect '{}'", prims[entry].name); +#endif + prims[entry].intersectPoint(point, aInfo); + } + + ModelInstance* prims; + AreaInfo aInfo; + }; + class LocationInfoCallback { public: @@ -83,6 +99,22 @@ namespace VMAP return tilefilename.str(); } + bool StaticMapTree::GetAreaInfo(Vector3& pos, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const + { + AreaInfoCallback intersectionCallBack(iTreeValues); + iTree.intersectPoint(pos, intersectionCallBack); + if (intersectionCallBack.aInfo.result) + { + flags = intersectionCallBack.aInfo.flags; + adtId = intersectionCallBack.aInfo.adtId; + rootId = intersectionCallBack.aInfo.rootId; + groupId = intersectionCallBack.aInfo.groupId; + pos.z = intersectionCallBack.aInfo.ground_Z; + return true; + } + return false; + } + bool StaticMapTree::GetLocationInfo(const Vector3& pos, LocationInfo& info) const { LocationInfoCallback intersectionCallBack(iTreeValues, info); diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index 09e426e3f..1a5db5693 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -30,12 +30,6 @@ namespace VMAP enum class ModelIgnoreFlags : uint32; enum class LoadResult : uint8; - struct GroupLocationInfo - { - const GroupModel* hitModel = nullptr; - int32 rootId = -1; - }; - struct LocationInfo { LocationInfo(): ground_Z(-G3D::inf()) { } @@ -79,6 +73,7 @@ namespace VMAP [[nodiscard]] bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2, ModelIgnoreFlags ignoreFlags) const; bool GetObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const; [[nodiscard]] float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const; + bool GetAreaInfo(G3D::Vector3& pos, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const; bool GetLocationInfo(const G3D::Vector3& pos, LocationInfo& info) const; bool InitMap(const std::string& fname, VMapMgr2* vm); diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index eebc7e62d..dacca121d 100644 --- a/src/common/Collision/Models/GameObjectModel.cpp +++ b/src/common/Collision/Models/GameObjectModel.cpp @@ -203,6 +203,27 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto return hit; } +void GameObjectModel::IntersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, uint32 ph_mask) const +{ + if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject()) + return; + + if (!iBound.contains(point)) + return; + + // child bounds are defined in object space: + Vector3 pModel = iInvRot * (point - iPos) * iInvScale; + Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); + float zDist; + if (iModel->IntersectPoint(pModel, zDirModel, zDist, info)) + { + Vector3 modelGround = pModel + zDist * zDirModel; + float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; + if (info.ground_Z < world_Z) + info.ground_Z = world_Z; + } +} + bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const { if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject()) @@ -215,9 +236,7 @@ bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationI Vector3 pModel = iInvRot * (point - iPos) * iInvScale; Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); float zDist; - - VMAP::GroupLocationInfo groupInfo; - if (iModel->GetLocationInfo(pModel, zDirModel, zDist, groupInfo)) + if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info)) { Vector3 modelGround = pModel + zDist * zDirModel; float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; diff --git a/src/common/Collision/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h index 5938a5c1d..204d114e2 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -70,6 +70,7 @@ public: [[nodiscard]] bool IsMapObject() const { return isWmo; } bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask, VMAP::ModelIgnoreFlags ignoreFlags) const; + void IntersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, uint32 ph_mask) const; bool GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const; bool GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const; diff --git a/src/common/Collision/Models/ModelInstance.cpp b/src/common/Collision/Models/ModelInstance.cpp index c5b6fbfdb..deba465d6 100644 --- a/src/common/Collision/Models/ModelInstance.cpp +++ b/src/common/Collision/Models/ModelInstance.cpp @@ -63,6 +63,44 @@ namespace VMAP return hit; } + void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo& info) const + { + if (!iModel) + { +#ifdef VMAP_DEBUG + std::cout << "\n"; +#endif + return; + } + + // M2 files don't contain area info, only WMO files + if (flags & MOD_M2) + { + return; + } + if (!iBound.contains(p)) + { + return; + } + // child bounds are defined in object space: + Vector3 pModel = iInvRot * (p - iPos) * iInvScale; + Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); + float zDist; + if (iModel->IntersectPoint(pModel, zDirModel, zDist, info)) + { + Vector3 modelGround = pModel + zDist * zDirModel; + // Transform back to world space. Note that: + // Mat * vec == vec * Mat.transpose() + // and for rotation matrices: Mat.inverse() == Mat.transpose() + float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; + if (info.ground_Z < world_Z) + { + info.ground_Z = world_Z; + info.adtId = adtId; + } + } + } + bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const { if (!iModel) @@ -86,9 +124,7 @@ namespace VMAP Vector3 pModel = iInvRot * (p - iPos) * iInvScale; Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); float zDist; - - GroupLocationInfo groupInfo; - if (iModel->GetLocationInfo(pModel, zDirModel, zDist, groupInfo)) + if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info)) { Vector3 modelGround = pModel + zDist * zDirModel; // Transform back to world space. Note that: @@ -97,8 +133,6 @@ namespace VMAP float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection? { - info.rootId = groupInfo.rootId; - info.hitModel = groupInfo.hitModel; info.ground_Z = world_Z; info.hitInstance = this; return true; diff --git a/src/common/Collision/Models/ModelInstance.h b/src/common/Collision/Models/ModelInstance.h index 3476a514d..8cadb4197 100644 --- a/src/common/Collision/Models/ModelInstance.h +++ b/src/common/Collision/Models/ModelInstance.h @@ -66,6 +66,7 @@ namespace VMAP ModelInstance(const ModelSpawn& spawn, WorldModel* model); void setUnloaded() { iModel = nullptr; } bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool StopAtFirstHit, ModelIgnoreFlags ignoreFlags) const; + void intersectPoint(const G3D::Vector3& p, AreaInfo& info) const; bool GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const; bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const; WorldModel* getWorldModel() { return iModel; } diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp index 53bd55a2d..0c29124a7 100644 --- a/src/common/Collision/Models/WorldModel.cpp +++ b/src/common/Collision/Models/WorldModel.cpp @@ -20,9 +20,9 @@ #include "ModelIgnoreFlags.h" #include "ModelInstance.h" #include "VMapDefinitions.h" -#include using G3D::Vector3; +using G3D::Ray; template<> struct BoundsTrait { @@ -451,46 +451,21 @@ namespace VMAP return callback.hit; } - inline bool IsInsideOrAboveBound(G3D::AABox const& bounds, const G3D::Point3& point) + bool GroupModel::IsInsideObject(const Vector3& pos, const Vector3& down, float& z_dist) const { - return point.x >= bounds.low().x - && point.y >= bounds.low().y - && point.z >= bounds.low().z - && point.x <= bounds.high().x - && point.y <= bounds.high().y; - } - - GroupModel::InsideResult GroupModel::IsInsideObject(G3D::Ray const& ray, float& z_dist) const - { - if (triangles.empty() || !IsInsideOrAboveBound(iBound, ray.origin())) - return OUT_OF_BOUNDS; - - if (meshTree.bound().high().z >= ray.origin().z) + if (triangles.empty() || !iBound.contains(pos)) { - float dist = G3D::finf(); - if (IntersectRay(ray, dist, false)) - { - z_dist = dist - 0.1f; - return INSIDE; - } - if (meshTree.bound().contains(ray.origin())) - return MAYBE_INSIDE; + return false; } - else + Vector3 rPos = pos - 0.1f * down; + float dist = G3D::inf(); + G3D::Ray ray(rPos, down); + bool hit = IntersectRay(ray, dist, false); + if (hit) { - // some group models don't have any floor to intersect with - // so we should attempt to intersect with a model part below this group - // then find back where we originated from (in WorldModel::GetLocationInfo) - float dist = G3D::finf(); - float delta = ray.origin().z - meshTree.bound().high().z; - if (IntersectRay(ray.bumpedRay(delta), dist, false)) - { - z_dist = dist - 0.1f + delta; - return ABOVE; - } + z_dist = dist - 0.1f; } - - return OUT_OF_BOUNDS; + return hit; } bool GroupModel::GetLiquidLevel(const Vector3& pos, float& liqHeight) const @@ -566,58 +541,76 @@ namespace VMAP class WModelAreaCallback { public: - WModelAreaCallback(std::vector const& vals) : - prims(vals), hit() { } - std::vector const& prims; - std::array hit; - bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool /*stopAtFirstHit*/) + WModelAreaCallback(const std::vector& vals, const Vector3& down): + prims(vals.begin()), hit(vals.end()), minVol(G3D::inf()), zDist(G3D::inf()), zVec(down) { } + std::vector::const_iterator prims; + std::vector::const_iterator hit; + float minVol; + float zDist; + Vector3 zVec; + void operator()(const Vector3& point, uint32 entry) { float group_Z; - if (GroupModel::InsideResult result = prims[entry].IsInsideObject(ray, group_Z); result != GroupModel::OUT_OF_BOUNDS) + //float pVol = prims[entry].GetBound().volume(); + //if (pVol < minVol) + //{ + /* if (prims[entry].iBound.contains(point)) */ + if (prims[entry].IsInsideObject(point, zVec, group_Z)) { - if (result != GroupModel::MAYBE_INSIDE) + //minVol = pVol; + //hit = prims + entry; + if (group_Z < zDist) { - if (group_Z < distance) - { - distance = group_Z; - hit[result] = &prims[entry]; - return true; - } + zDist = group_Z; + hit = prims + entry; } - else - hit[result] = &prims[entry]; +#ifdef VMAP_DEBUG + const GroupModel& gm = prims[entry]; + printf("%10u %8X %7.3f, %7.3f, %7.3f | %7.3f, %7.3f, %7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(), + gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z, + gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z); +#endif } - return false; + //} + //std::cout << "trying to intersect '" << prims[entry].name << "'\n"; } }; - bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const + bool WorldModel::IntersectPoint(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, AreaInfo& info) const { if (groupModels.empty()) { return false; } - WModelAreaCallback callback(groupModels); - G3D::Ray r(p - down * 0.1f, down); - float zDist = groupTree.bound().extent().length(); - groupTree.intersectRay(r, callback, zDist, false); - if (callback.hit[GroupModel::INSIDE]) + WModelAreaCallback callback(groupModels, down); + groupTree.intersectPoint(p, callback); + if (callback.hit != groupModels.end()) { info.rootId = RootWMOID; - info.hitModel = callback.hit[GroupModel::INSIDE]; - dist = zDist; + info.groupId = callback.hit->GetWmoID(); + info.flags = callback.hit->GetMogpFlags(); + info.result = true; + dist = callback.zDist; return true; } + return false; + } - // some group models don't have any floor to intersect with - // so we should attempt to intersect with a model part below the group `p` is in (stored in GroupModel::ABOVE) - // then find back where we originated from (GroupModel::MAYBE_INSIDE) - if (callback.hit[GroupModel::MAYBE_INSIDE] && callback.hit[GroupModel::ABOVE]) + bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const + { + if (groupModels.empty()) + { + return false; + } + + WModelAreaCallback callback(groupModels, down); + groupTree.intersectPoint(p, callback); + if (callback.hit != groupModels.end()) { info.rootId = RootWMOID; - info.hitModel = callback.hit[GroupModel::MAYBE_INSIDE]; - dist = zDist; + info.hitModel = &(*callback.hit); + dist = callback.zDist; return true; } return false; diff --git a/src/common/Collision/Models/WorldModel.h b/src/common/Collision/Models/WorldModel.h index 2d5d8126b..9febf86e7 100644 --- a/src/common/Collision/Models/WorldModel.h +++ b/src/common/Collision/Models/WorldModel.h @@ -29,7 +29,6 @@ namespace VMAP class TreeNode; struct AreaInfo; struct LocationInfo; - struct GroupLocationInfo; enum class ModelIgnoreFlags : uint32; class MeshTriangle @@ -82,14 +81,12 @@ namespace VMAP void setMeshData(std::vector& vert, std::vector& tri); void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = nullptr; } bool IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit) const; - enum InsideResult { INSIDE = 0, MAYBE_INSIDE = 1, ABOVE = 2, OUT_OF_BOUNDS = -1 }; - InsideResult IsInsideObject(G3D::Ray const& ray, float& z_dist) const; + bool IsInsideObject(const G3D::Vector3& pos, const G3D::Vector3& down, float& z_dist) const; bool GetLiquidLevel(const G3D::Vector3& pos, float& liqHeight) const; [[nodiscard]] uint32 GetLiquidType() const; bool writeToFile(FILE* wf); bool readFromFile(FILE* rf); - [[nodiscard]] G3D::AABox const& GetBound() const { return iBound; } - [[nodiscard]] G3D::AABox const& GetMeshTreeBound() const { return meshTree.bound(); } + [[nodiscard]] const G3D::AABox& GetBound() const { return iBound; } [[nodiscard]] uint32 GetMogpFlags() const { return iMogpFlags; } [[nodiscard]] uint32 GetWmoID() const { return iGroupWMOID; } void GetMeshData(std::vector& outVertices, std::vector& outTriangles, WmoLiquid*& liquid); @@ -112,7 +109,8 @@ namespace VMAP void setGroupModels(std::vector& models); void setRootWmoID(uint32 id) { RootWMOID = id; } bool IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const; - bool GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const; + bool IntersectPoint(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, AreaInfo& info) const; + bool GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const; bool writeFile(const std::string& filename); bool readFile(const std::string& filename); void GetGroupModels(std::vector& outGroupModels); diff --git a/src/common/Utilities/CircularBuffer.h b/src/common/Utilities/CircularBuffer.h index 55681c87b..4c23099c9 100644 --- a/src/common/Utilities/CircularBuffer.h +++ b/src/common/Utilities/CircularBuffer.h @@ -1,5 +1,5 @@ /* -# Copyright (C) 2016+ AzerothCore + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE * * This file was based on * https://embeddedartistry.com/blog/2017/05/17/creating-a-circular-buffer-in-c-and-c/ diff --git a/src/common/Utilities/DataMap.h b/src/common/Utilities/DataMap.h index 31910f945..170539a67 100644 --- a/src/common/Utilities/DataMap.h +++ b/src/common/Utilities/DataMap.h @@ -1,5 +1,5 @@ /* - * Originally written by Rochet2 - Copyright (C) 2018+ AzerothCore + * Originally written by Rochet2 - Copyright (C) 2018+ AzerothCore , released under GNU AGPL v3 license: http://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #ifndef _DATA_MAP_H_ diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h index a382910b8..b89d4e3f7 100644 --- a/src/common/Utilities/EventMap.h +++ b/src/common/Utilities/EventMap.h @@ -97,6 +97,32 @@ public: return _eventMap.empty(); } + /** + * @return Current internal time as uint32 milliseconds + * + * was removed in core https://github.com/azerothcore/azerothcore-wotlk/pull/23121, + * but still required atm for mod-playerbot. + */ + uint32 GetTimer() const + { + return static_cast(duration_cast(_time.time_since_epoch()).count()); + } + + /** + * @return Time of found even + * + * was removed in core https://github.com/azerothcore/azerothcore-wotlk/pull/23121, + * but still required atm for mod-playerbot. + */ + uint32 GetNextEventTime(uint16 eventId) const + { + auto timeUntil = GetTimeUntilEvent(eventId); + if (timeUntil == Milliseconds::max()) + return 0; + + return GetTimer() + static_cast(timeUntil.count()); + } + /** * @name SetPhase * @brief Sets the phase of the map (absolute). diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h index 644c2b643..dc8779957 100644 --- a/src/common/Utilities/EventProcessor.h +++ b/src/common/Utilities/EventProcessor.h @@ -120,7 +120,7 @@ class EventProcessor [[nodiscard]] uint64 CalculateQueueTime(uint64 delay) const; void CancelEventGroup(uint8 group); - bool HasEvents() const { return !m_events.empty(); } + bool HaveEventList() const { return !m_events.empty(); } protected: uint64 m_time{0}; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 3976d4e76..a7669fa16 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -347,6 +347,7 @@ inline wchar_t wcharToLower(wchar_t wchar) void wstrToUpper(std::wstring& str); void wstrToLower(std::wstring& str); +void strToLower(std::string& str); std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension); diff --git a/src/server/apps/worldserver/Main.cpp b/src/server/apps/worldserver/Main.cpp index 511c17e36..6a08e9689 100644 --- a/src/server/apps/worldserver/Main.cpp +++ b/src/server/apps/worldserver/Main.cpp @@ -434,6 +434,11 @@ bool StartDB() if (!loader.Load()) return false; + if (!sScriptMgr->OnDatabasesLoading()) + { + return false; + } + ///- Get the realm Id from the configuration file realm.Id.Realm = sConfigMgr->GetOption("RealmID", 1); if (!realm.Id.Realm) @@ -479,6 +484,8 @@ void StopDB() WorldDatabase.Close(); LoginDatabase.Close(); + sScriptMgr->OnDatabasesClosing(); + MySQL::Library_End(); } @@ -569,6 +576,8 @@ void WorldUpdateLoop() CharacterDatabase.WarnAboutSyncQueries(true); WorldDatabase.WarnAboutSyncQueries(true); + sScriptMgr->OnDatabaseWarnAboutSyncQueries(true); + ///- While we have not World::m_stopEvent, update the world while (!World::IsStopped()) { @@ -598,6 +607,8 @@ void WorldUpdateLoop() #endif } + sScriptMgr->OnDatabaseWarnAboutSyncQueries(false); + LoginDatabase.WarnAboutSyncQueries(false); CharacterDatabase.WarnAboutSyncQueries(false); WorldDatabase.WarnAboutSyncQueries(false); diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index c6305069d..59bf10b06 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -678,6 +678,7 @@ Allow.IP.Based.Action.Logging = 0 Appender.Console=1,4,0,"1 9 3 6 5 8" Appender.Server=2,5,0,Server.log,w +Appender.Playerbots=2,5,0,Playerbots.log,w # Appender.GM=2,5,15,gm_%s.log Appender.Errors=2,2,0,Errors.log,w # Appender.DB=3,5,0 @@ -714,6 +715,7 @@ Logger.sql=4,Console Server Logger.time.update=4,Console Server Logger.module=4,Console Server Logger.spells.scripts=2,Console Errors +Logger.playerbots=5,Console Playerbots #Logger.achievement=4,Console Server #Logger.addon=4,Console Server #Logger.ahbot=4,Console Server diff --git a/src/server/database/Database/DatabaseEnv.cpp b/src/server/database/Database/DatabaseEnv.cpp index 561e80f4b..56f904d2e 100644 --- a/src/server/database/Database/DatabaseEnv.cpp +++ b/src/server/database/Database/DatabaseEnv.cpp @@ -20,3 +20,7 @@ DatabaseWorkerPool WorldDatabase; DatabaseWorkerPool CharacterDatabase; DatabaseWorkerPool LoginDatabase; + +#ifdef MOD_PLAYERBOTS +DatabaseWorkerPool PlayerbotsDatabase; +#endif diff --git a/src/server/database/Database/DatabaseEnv.h b/src/server/database/Database/DatabaseEnv.h index 3e0cd2e86..7d2b5da77 100644 --- a/src/server/database/Database/DatabaseEnv.h +++ b/src/server/database/Database/DatabaseEnv.h @@ -25,6 +25,10 @@ #include "Implementation/LoginDatabase.h" #include "Implementation/WorldDatabase.h" +#ifdef MOD_PLAYERBOTS +#include "Implementation/PlayerbotsDatabase.h" +#endif + #include "PreparedStatement.h" #include "QueryCallback.h" #include "Transaction.h" @@ -36,4 +40,9 @@ AC_DATABASE_API extern DatabaseWorkerPool Character /// Accessor to the realm/login database AC_DATABASE_API extern DatabaseWorkerPool LoginDatabase; +#ifdef MOD_PLAYERBOTS +/// Accessor to the playerbots database +AC_DATABASE_API extern DatabaseWorkerPool PlayerbotsDatabase; +#endif + #endif diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h index b8e5a8882..d6bbaa65e 100644 --- a/src/server/database/Database/DatabaseEnvFwd.h +++ b/src/server/database/Database/DatabaseEnvFwd.h @@ -32,6 +32,10 @@ class CharacterDatabaseConnection; class LoginDatabaseConnection; class WorldDatabaseConnection; +#ifdef MOD_PLAYERBOTS +class PlayerbotsDatabaseConnection; +#endif + class PreparedStatementBase; template @@ -41,6 +45,10 @@ using CharacterDatabasePreparedStatement = PreparedStatement; using WorldDatabasePreparedStatement = PreparedStatement; +#ifdef MOD_PLAYERBOTS +using PlayerbotsDatabasePreparedStatement = PreparedStatement; +#endif + class PreparedResultSet; using PreparedQueryResult = std::shared_ptr; using PreparedQueryResultFuture = std::future; @@ -70,6 +78,10 @@ using CharacterDatabaseTransaction = SQLTransaction using LoginDatabaseTransaction = SQLTransaction; using WorldDatabaseTransaction = SQLTransaction; +#ifdef MOD_PLAYERBOTS +using PlayerbotsDatabaseTransaction = SQLTransaction; +#endif + class SQLQueryHolderBase; using QueryResultHolderFuture = std::future; using QueryResultHolderPromise = std::promise; @@ -81,6 +93,10 @@ using CharacterDatabaseQueryHolder = SQLQueryHolder using LoginDatabaseQueryHolder = SQLQueryHolder; using WorldDatabaseQueryHolder = SQLQueryHolder; +#ifdef MOD_PLAYERBOTS +using PlayerbotsDatabaseQueryHolder = SQLQueryHolder; +#endif + class SQLQueryHolderCallback; // mysql diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp index c39aa41b9..0328dd49d 100644 --- a/src/server/database/Database/DatabaseLoader.cpp +++ b/src/server/database/Database/DatabaseLoader.cpp @@ -238,3 +238,8 @@ template AC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); template AC_DATABASE_API DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); + +#ifdef MOD_PLAYERBOTS +template AC_DATABASE_API +DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool&, std::string const&); +#endif diff --git a/src/server/database/Database/DatabaseLoader.h b/src/server/database/Database/DatabaseLoader.h index 0f18315e6..0ef3e82cb 100644 --- a/src/server/database/Database/DatabaseLoader.h +++ b/src/server/database/Database/DatabaseLoader.h @@ -48,8 +48,12 @@ public: DATABASE_LOGIN = 1, DATABASE_CHARACTER = 2, DATABASE_WORLD = 4, - +#ifdef MOD_PLAYERBOTS + DATABASE_PLAYERBOTS = 8, + DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD | DATABASE_PLAYERBOTS +#else DATABASE_MASK_ALL = DATABASE_LOGIN | DATABASE_CHARACTER | DATABASE_WORLD +#endif }; [[nodiscard]] uint32 GetUpdateFlags() const @@ -57,6 +61,11 @@ public: return _updateFlags; } + void SetUpdateFlags(uint32 newUpdateFlags) + { + _updateFlags |= newUpdateFlags; + } + private: bool OpenDatabases(); bool PopulateDatabases(); @@ -73,7 +82,7 @@ private: std::string const _logger; std::string_view _modulesList; bool const _autoSetup; - uint32 const _updateFlags; + uint32 _updateFlags; std::queue _open, _populate, _update, _prepare; std::stack _close; diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index ee19a5a48..f539e2a6a 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -41,6 +41,10 @@ #include #endif +#ifdef MOD_PLAYERBOTS +#include "Implementation/PlayerbotsDatabase.h" +#endif + class PingOperation : public SQLOperation { //! Operation for idle delaythreads @@ -571,3 +575,7 @@ void DatabaseWorkerPool::ExecuteOrAppend(SQLTransaction& trans, PreparedSt template class AC_DATABASE_API DatabaseWorkerPool; template class AC_DATABASE_API DatabaseWorkerPool; template class AC_DATABASE_API DatabaseWorkerPool; + +#ifdef MOD_PLAYERBOTS +template class AC_DATABASE_API DatabaseWorkerPool; +#endif diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 1b8650b49..25e9b635a 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -356,6 +356,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petition_id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petition_id, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_OFFLINE, "UPDATE characters SET online = 0 WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_GROUP, "INSERT INTO `groups` (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raidDifficulty, masterLooterGuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_GROUP_MEMBER, "REPLACE INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_MEMBER, "DELETE FROM group_member WHERE memberGuid = ? AND guid = ?", CONNECTION_ASYNC); @@ -404,7 +405,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_DEL_INFO, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid FROM characters WHERE account = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID, "SELECT guid, class, race FROM characters WHERE account = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_PINFO, "SELECT totaltime, level, money, account, race, class, map, zone, gender, health, playerFlags FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM character_banned WHERE guid = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PINFO_MAILS, "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 3ead3cf40..0329464f6 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -280,6 +280,7 @@ enum CharacterDatabaseStatements : uint32 CHAR_UPD_PETITION_NAME, CHAR_INS_PETITION_SIGNATURE, CHAR_UPD_ACCOUNT_ONLINE, + CHAR_UPD_CHAR_OFFLINE, CHAR_INS_GROUP, CHAR_REP_GROUP_MEMBER, CHAR_DEL_GROUP_MEMBER, diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 1e091b56e..069abd665 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -75,6 +75,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_IP_NOT_BANNED, "DELETE FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM, "DELETE FROM realmcharacters WHERE acctid = ? AND realmid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_REP_REALM_CHARACTERS, "REPLACE INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); @@ -89,7 +90,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LAST_ATTEMPT_IP, "UPDATE account SET last_attempt_ip = ? WHERE username = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT_ACCESS, "DELETE FROM account_access WHERE id = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index 563cdf3eb..4f0129782 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -59,6 +59,7 @@ enum LoginDatabaseStatements : uint32 LOGIN_SEL_ACCOUNT_BY_ID, LOGIN_INS_ACCOUNT_BANNED, LOGIN_UPD_ACCOUNT_NOT_BANNED, + LOGIN_DEL_REALM_CHARACTERS_BY_REALM, LOGIN_DEL_REALM_CHARACTERS, LOGIN_REP_REALM_CHARACTERS, LOGIN_SEL_SUM_REALM_CHARACTERS, diff --git a/src/server/database/Database/Implementation/PlayerbotsDatabase.cpp b/src/server/database/Database/Implementation/PlayerbotsDatabase.cpp new file mode 100644 index 000000000..930862e04 --- /dev/null +++ b/src/server/database/Database/Implementation/PlayerbotsDatabase.cpp @@ -0,0 +1,129 @@ +/* + * 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 General Public License as published by + * the Free Software Foundation; either version 2 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 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 . + */ + +#ifdef MOD_PLAYERBOTS + +#include "PlayerbotsDatabase.h" +#include "MySQLPreparedStatement.h" + +void PlayerbotsDatabaseConnection::DoPrepareStatements() +{ + if (!m_reconnecting) + m_stmts.resize(MAX_PLAYERBOTS_STATEMENTS); + + PrepareStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER, "SELECT DISTINCT name FROM playerbots_custom_strategy WHERE owner = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME, "SELECT idx, action_line FROM playerbots_custom_strategy WHERE owner = ? AND name = ? ORDER BY idx", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME_AND_IDX, "SELECT action_line FROM playerbots_custom_strategy WHERE owner = ? AND name = ? AND idx = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_DEL_CUSTOM_STRATEGY, "DELETE FROM playerbots_custom_strategy WHERE name = ? AND owner = ? AND idx = ?", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_UPD_CUSTOM_STRATEGY, "UPDATE playerbots_custom_strategy SET action_line = ? WHERE name = ? AND owner = ? AND idx = ?", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_INS_CUSTOM_STRATEGY, "INSERT INTO playerbots_custom_strategy (name, owner, idx, action_line) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_DB_STORE, "SELECT `key`,`value` FROM `playerbots_db_store` WHERE `guid` = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_DEL_DB_STORE, "DELETE FROM `playerbots_db_store` WHERE `guid` = ?", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_INS_DB_STORE, "INSERT INTO `playerbots_db_store` (`guid`, `key`, `value`) VALUES (?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_ENCHANTS, "SELECT class, spec, spellid, slotid FROM playerbots_enchants", CONNECTION_SYNCH); + + PrepareStatement(PLAYERBOTS_SEL_EQUIP_CACHE, "SELECT clazz, lvl, slot, quality, item FROM playerbots_equip_cache", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_EQUIP_CACHE, "INSERT INTO playerbots_equip_cache (clazz, lvl, slot, quality, item) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_VALUE, "SELECT `value`, `time`, validIn FROM playerbots_guild_tasks WHERE `value` = ? AND guildid = ? AND `type` = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER, "SELECT `value`, `time`, validIn, guildid FROM playerbots_guild_tasks WHERE owner = ? AND `type` = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_AND_TYPE, "SELECT `value`, `time`, validIn FROM playerbots_guild_tasks WHERE owner = ? AND guildid = ? AND `type` = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_DISTINCT, "SELECT DISTINCT guildid FROM playerbots_guild_tasks WHERE owner = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_ORDERED, "SELECT `value`, `time`, validIn, guildid FROM playerbots_guild_tasks WHERE owner = ? AND type = ? ORDER BY guildid", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_DEL_GUILD_TASKS, "DELETE FROM playerbots_guild_tasks WHERE owner = ? AND guildid = ? AND `type` = ?", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_INS_GUILD_TASKS, "INSERT INTO playerbots_guild_tasks (owner, guildid, `time`, validIn, `type`, `value`) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_RANDOM_BOTS_VALUE, "SELECT value FROM playerbots_random_bots WHERE event = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BOT, "SELECT `bot` FROM playerbots_random_bots WHERE event = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_EVENT, "SELECT bot FROM playerbots_random_bots WHERE owner = ? AND event = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_BOT, "SELECT `event`, `value`, `time`, validIn, `data` FROM playerbots_random_bots WHERE owner = ? AND bot = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_RANDOM_BOTS_BY_EVENT_AND_VALUE, "SELECT bot FROM playerbots_random_bots WHERE event = ? AND value = ?", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_RANDOM_BOTS, "INSERT INTO playerbots_random_bots (owner, bot, `time`, validIn, event, `value`, `data`) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_RANDOM_BOTS, "DELETE FROM playerbots_random_bots", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_RANDOM_BOTS_BY_OWNER, "DELETE FROM playerbots_random_bots WHERE owner = ? AND bot = ?", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_RANDOM_BOTS_BY_OWNER_AND_EVENT, "DELETE FROM playerbots_random_bots WHERE owner = ? AND bot = ? AND event = ?", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_UPD_RANDOM_BOTS, "UPDATE playerbots_random_bots SET validIn = ? WHERE event = ? AND bot = ?", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_RARITY_CACHE, "SELECT item, rarity FROM playerbots_rarity_cache", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_RARITY_CACHE, "INSERT INTO playerbots_rarity_cache (item, rarity) VALUES (?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_RNDITEM_CACHE, "SELECT lvl, type, item FROM playerbots_rnditem_cache", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_RNDITEM_CACHE, "INSERT INTO playerbots_rnditem_cache (lvl, type, item) VALUES (?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_SPEECH, "SELECT name, text, type FROM playerbots_speech", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_SPEECH_PROBABILITY, "SELECT name, probability FROM playerbots_speech_probability", CONNECTION_SYNCH); + + PrepareStatement(PLAYERBOTS_SEL_TELE_CACHE, "SELECT map_id, x, y, z, level FROM playerbots_tele_cache", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_TELE_CACHE, "INSERT INTO playerbots_tele_cache (level, map_id, x, y, z) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_TRAVELNODE, "SELECT id, name, map_id, x, y, z, linked FROM playerbots_travelnode", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_TRAVELNODE, "INSERT INTO `playerbots_travelnode` (`id`, `name`, `map_id`, `x`, `y`, `z`, `linked`) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_TRAVELNODE, "DELETE FROM playerbots_travelnode", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_TRAVELNODE_LINK, "SELECT node_id, to_node_id,type,object,distance,swim_distance, extra_cost,calculated, max_creature_0,max_creature_1,max_creature_2 FROM playerbots_travelnode_link", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_TRAVELNODE_LINK, "INSERT INTO `playerbots_travelnode_link` (`node_id`, `to_node_id`,`type`,`object`,`distance`,`swim_distance`, `extra_cost`,`calculated`, `max_creature_0`,`max_creature_1`,`max_creature_2`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_TRAVELNODE_LINK, "DELETE FROM playerbots_travelnode_link", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_TRAVELNODE_PATH, "SELECT node_id, to_node_id, nr, map_id, x, y, z FROM playerbots_travelnode_path order by node_id, to_node_id, nr", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_INS_TRAVELNODE_PATH, "INSERT INTO `playerbots_travelnode_path` (`node_id`, `to_node_id`, `nr`, `map_id`, `x`, `y`, `z`) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_TRAVELNODE_PATH, "DELETE FROM playerbots_travelnode_path", CONNECTION_ASYNC); + + PrepareStatement(PLAYERBOTS_SEL_TEXT, "SELECT `name`, `text`, `say_type`, `reply_type`, `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8` FROM `ai_playerbot_texts`", CONNECTION_SYNCH); + PrepareStatement( + PLAYERBOTS_SEL_DUNGEON_SUGGESTION, + "SELECT" + " d.`name`, " + " d.`difficulty`, " + " d.`min_level`, " + " d.`max_level`, " + " a.`abbrevation`, " + " s.`strategy` " + "FROM playerbots_dungeon_suggestion_definition d " + "LEFT OUTER JOIN playerbots_dungeon_suggestion_abbrevation a " + " ON d.slug = a.definition_slug " + "LEFT OUTER JOIN playerbots_dungeon_suggestion_strategy s " + " ON d.slug = s.definition_slug " + " AND d.difficulty = s.difficulty " + "WHERE d.expansion <= ?;", + CONNECTION_SYNCH + ); + + PrepareStatement(PLAYERBOTS_SEL_WEIGHTSCALES, "SELECT id, name, class FROM playerbots_weightscales", CONNECTION_SYNCH); + PrepareStatement(PLAYERBOTS_SEL_WEIGHTSCALE_DATA, "SELECT id, field, val FROM playerbots_weightscale_data", CONNECTION_SYNCH); + + PrepareStatement(PLAYERBOTS_INS_EQUIP_CACHE_NEW, "INSERT INTO playerbots_item_info_cache (id, quality, slot, source, sourceId, team, faction, factionRepRank, minLevel, " + "scale_1, scale_2, scale_3, scale_4, scale_5, scale_6, scale_7, scale_8, scale_9, scale_10, scale_11, scale_12, scale_13, scale_14, scale_15, " + "scale_16, scale_17, scale_18, scale_19, scale_20, scale_21, scale_22, scale_23, scale_24, scale_25, scale_26, scale_27, scale_28, scale_29, scale_30, scale_31, scale_32) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(PLAYERBOTS_DEL_EQUIP_CACHE_NEW, "DELETE FROM playerbots_item_info_cache WHERE id = ?", CONNECTION_ASYNC); +} + +PlayerbotsDatabaseConnection::PlayerbotsDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) +{ +} + +PlayerbotsDatabaseConnection::PlayerbotsDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +{ +} + +PlayerbotsDatabaseConnection::~PlayerbotsDatabaseConnection() +{ +} + +#endif diff --git a/src/server/database/Database/Implementation/PlayerbotsDatabase.h b/src/server/database/Database/Implementation/PlayerbotsDatabase.h new file mode 100644 index 000000000..4b826f237 --- /dev/null +++ b/src/server/database/Database/Implementation/PlayerbotsDatabase.h @@ -0,0 +1,120 @@ +/* + * 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 General Public License as published by + * the Free Software Foundation; either version 2 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 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 . + */ + +#ifdef MOD_PLAYERBOTS + +#ifndef _PlayerbotsDatabase_H +#define _PlayerbotsDatabase_H + +#include "MySQLConnection.h" + +enum PlayerbotsDatabaseStatements : uint32 +{ + /* Naming standard for defines: + {DB}_{SEL/INS/UPD/DEL/REP}_{Summary of data changed} + When updating more than one field, consider looking at the calling function + name for a suiting suffix. + */ + + PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER, + PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME, + PLAYERBOTS_SEL_CUSTOM_STRATEGY_BY_OWNER_AND_NAME_AND_IDX, + PLAYERBOTS_DEL_CUSTOM_STRATEGY, + PLAYERBOTS_UPD_CUSTOM_STRATEGY, + PLAYERBOTS_INS_CUSTOM_STRATEGY, + + PLAYERBOTS_SEL_DB_STORE, + PLAYERBOTS_DEL_DB_STORE, + PLAYERBOTS_INS_DB_STORE, + + PLAYERBOTS_SEL_ENCHANTS, + + PLAYERBOTS_SEL_EQUIP_CACHE, + PLAYERBOTS_INS_EQUIP_CACHE, + + PLAYERBOTS_SEL_GUILD_TASKS_BY_VALUE, + PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER, + PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_AND_TYPE, + PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_DISTINCT, + PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER_ORDERED, + PLAYERBOTS_DEL_GUILD_TASKS, + PLAYERBOTS_INS_GUILD_TASKS, + + PLAYERBOTS_SEL_RANDOM_BOTS_VALUE, + PLAYERBOTS_SEL_RANDOM_BOTS_BOT, + PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_EVENT, + PLAYERBOTS_SEL_RANDOM_BOTS_BY_OWNER_AND_BOT, + PLAYERBOTS_SEL_RANDOM_BOTS_BY_EVENT_AND_VALUE, + PLAYERBOTS_INS_RANDOM_BOTS, + PLAYERBOTS_DEL_RANDOM_BOTS, + PLAYERBOTS_DEL_RANDOM_BOTS_BY_OWNER, + PLAYERBOTS_DEL_RANDOM_BOTS_BY_OWNER_AND_EVENT, + PLAYERBOTS_UPD_RANDOM_BOTS, + + PLAYERBOTS_SEL_RARITY_CACHE, + PLAYERBOTS_INS_RARITY_CACHE, + + PLAYERBOTS_SEL_RNDITEM_CACHE, + PLAYERBOTS_INS_RNDITEM_CACHE, + + PLAYERBOTS_SEL_SPEECH, + PLAYERBOTS_SEL_SPEECH_PROBABILITY, + + PLAYERBOTS_SEL_TELE_CACHE, + PLAYERBOTS_INS_TELE_CACHE, + + PLAYERBOTS_SEL_TEXT, + PLAYERBOTS_SEL_DUNGEON_SUGGESTION, + + PLAYERBOTS_SEL_TRAVELNODE, + PLAYERBOTS_INS_TRAVELNODE, + PLAYERBOTS_DEL_TRAVELNODE, + + PLAYERBOTS_SEL_TRAVELNODE_LINK, + PLAYERBOTS_INS_TRAVELNODE_LINK, + PLAYERBOTS_DEL_TRAVELNODE_LINK, + + PLAYERBOTS_SEL_TRAVELNODE_PATH, + PLAYERBOTS_INS_TRAVELNODE_PATH, + PLAYERBOTS_DEL_TRAVELNODE_PATH, + + PLAYERBOTS_SEL_WEIGHTSCALES, + PLAYERBOTS_SEL_WEIGHTSCALE_DATA, + + PLAYERBOTS_INS_EQUIP_CACHE_NEW, + PLAYERBOTS_DEL_EQUIP_CACHE_NEW, + + MAX_PLAYERBOTS_STATEMENTS +}; + +class AC_DATABASE_API PlayerbotsDatabaseConnection : public MySQLConnection +{ +public: + typedef PlayerbotsDatabaseStatements Statements; + + //- Constructors for sync and async connections + PlayerbotsDatabaseConnection(MySQLConnectionInfo& connInfo); + PlayerbotsDatabaseConnection(ProducerConsumerQueue* q, MySQLConnectionInfo& connInfo); + ~PlayerbotsDatabaseConnection(); + + //- Loads database type specific prepared statements + void DoPrepareStatements() override; +}; + +#endif + +#endif diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp index 4e06beb48..a583a33a3 100644 --- a/src/server/database/Updater/DBUpdater.cpp +++ b/src/server/database/Updater/DBUpdater.cpp @@ -77,10 +77,16 @@ std::string DBUpdater::GetTableName() return "Auth"; } +template<> +std::string DBUpdater::GetSourceDirectory() +{ + return BuiltInConfig::GetSourceDirectory(); +} + template<> std::string DBUpdater::GetBaseFilesDirectory() { - return BuiltInConfig::GetSourceDirectory() + "/data/sql/base/db_auth/"; + return DBUpdater::GetSourceDirectory() + "/data/sql/base/db_auth/"; } template<> @@ -93,7 +99,7 @@ bool DBUpdater::IsEnabled(uint32 const updateMask) template<> std::string DBUpdater::GetDBModuleName() { - return "db-auth"; + return "auth"; } // World Database @@ -109,10 +115,16 @@ std::string DBUpdater::GetTableName() return "World"; } +template<> +std::string DBUpdater::GetSourceDirectory() +{ + return BuiltInConfig::GetSourceDirectory(); +} + template<> std::string DBUpdater::GetBaseFilesDirectory() { - return BuiltInConfig::GetSourceDirectory() + "/data/sql/base/db_world/"; + return DBUpdater::GetSourceDirectory() + "/data/sql/base/db_world/"; } template<> @@ -125,7 +137,7 @@ bool DBUpdater::IsEnabled(uint32 const updateMask) template<> std::string DBUpdater::GetDBModuleName() { - return "db-world"; + return "world"; } // Character Database @@ -141,10 +153,16 @@ std::string DBUpdater::GetTableName() return "Character"; } +template<> +std::string DBUpdater::GetSourceDirectory() +{ + return BuiltInConfig::GetSourceDirectory(); +} + template<> std::string DBUpdater::GetBaseFilesDirectory() { - return BuiltInConfig::GetSourceDirectory() + "/data/sql/base/db_characters/"; + return DBUpdater::GetSourceDirectory() + "/data/sql/base/db_characters/"; } template<> @@ -157,9 +175,49 @@ bool DBUpdater::IsEnabled(uint32 const updateMask) template<> std::string DBUpdater::GetDBModuleName() { - return "db-characters"; + return "characters"; } +#ifdef MOD_PLAYERBOTS +// Playerbots Database +template<> +std::string DBUpdater::GetConfigEntry() +{ + return "Updates.Playerbots"; +} + +template<> +std::string DBUpdater::GetTableName() +{ + return "Playerbots"; +} + +template<> +std::string DBUpdater::GetSourceDirectory() +{ + return BuiltInConfig::GetSourceDirectory() + "/modules/mod-playerbots"; +} + +template<> +std::string DBUpdater::GetBaseFilesDirectory() +{ + return DBUpdater::GetSourceDirectory() + "/data/sql/playerbots/base/"; +} + +template<> +bool DBUpdater::IsEnabled(uint32 const updateMask) +{ + // This way silences warnings under msvc + return (updateMask & DatabaseLoader::DATABASE_PLAYERBOTS) ? true : false; +} + +template<> +std::string DBUpdater::GetDBModuleName() +{ + return "db_playerbot"; +} +#endif + // All template BaseLocation DBUpdater::GetBaseLocationType() @@ -225,7 +283,7 @@ bool DBUpdater::Update(DatabaseWorkerPool& pool, std::string_view modulesL LOG_INFO("sql.updates", "Updating {} database...", DBUpdater::GetTableName()); - Path const sourceDirectory(BuiltInConfig::GetSourceDirectory()); + Path const sourceDirectory(DBUpdater::GetSourceDirectory()); if (!is_directory(sourceDirectory)) { @@ -300,7 +358,7 @@ bool DBUpdater::Update(DatabaseWorkerPool& pool, std::vector return false; } - Path const sourceDirectory(BuiltInConfig::GetSourceDirectory()); + Path const sourceDirectory(DBUpdater::GetSourceDirectory()); if (!is_directory(sourceDirectory)) { return false; @@ -534,3 +592,7 @@ void DBUpdater::ApplyFile(DatabaseWorkerPool& pool, std::string const& hos template class AC_DATABASE_API DBUpdater; template class AC_DATABASE_API DBUpdater; template class AC_DATABASE_API DBUpdater; + +#ifdef MOD_PLAYERBOTS +template class AC_DATABASE_API DBUpdater; +#endif diff --git a/src/server/database/Updater/DBUpdater.h b/src/server/database/Updater/DBUpdater.h index 58ebf3320..3a0e58709 100644 --- a/src/server/database/Updater/DBUpdater.h +++ b/src/server/database/Updater/DBUpdater.h @@ -72,6 +72,7 @@ public: static inline std::string GetConfigEntry(); static inline std::string GetTableName(); + static std::string GetSourceDirectory(); static std::string GetBaseFilesDirectory(); static bool IsEnabled(uint32 const updateMask); static BaseLocation GetBaseLocationType(); diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index b3a7eaa86..46e5dafe8 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -162,7 +162,7 @@ UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() cons // data/sql for (auto const& itr : moduleList) { - std::string path = _sourceDirectory->generic_string() + "/modules/" + itr + "/data/sql/" + _dbModuleName; // modules/mod-name/data/sql/db-world + std::string path = _sourceDirectory->generic_string() + "/modules/" + itr + "/data/sql/" + _dbModuleName; // modules/mod-name/sql/world Path const p(path); if (!is_directory(p)) diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index f21e93230..8d0804f3b 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -83,19 +83,29 @@ WorldObject* CreatureAI::GetSummoner() const inline bool IsValidCombatTarget(Creature* source, Player* target) { if (target->IsGameMaster()) + { return false; + } if (!source->IsInWorld() || !target->IsInWorld()) + { return false; + } if (!source->IsAlive() || !target->IsAlive()) + { return false; + } if (!source->InSamePhase(target)) + { return false; + } - if (source->IsInFlight() || target->IsInFlight()) + if (source->HasUnitState(UNIT_STATE_IN_FLIGHT) || target->HasUnitState(UNIT_STATE_IN_FLIGHT)) + { return false; + } return true; } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index aef961781..b1b6c65bd 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -950,9 +950,6 @@ bool SmartAIMgr::CheckUnusedTargetParams(SmartScriptHolder const& e) case SMART_TARGET_VEHICLE_PASSENGER: return sizeof(SmartTarget::vehicle); // case SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT: return sizeof(SmartTarget::goClosest); case SMART_TARGET_PLAYER_WITH_AURA: return sizeof(SmartTarget::playerWithAura); - case SMART_TARGET_RANDOM_POINT: return sizeof(SmartTarget::randomPoint); - case SMART_TARGET_SUMMONED_CREATURES: return sizeof(SmartTarget::summonedCreatures); - case SMART_TARGET_INSTANCE_STORAGE: return sizeof(SmartTarget::instanceStorage); default: LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using a target {} with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 2451aac3d..1e615b6d5 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -1826,15 +1826,6 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve // someone on this realm has already completed that achievement if (sAchievementMgr->IsRealmCompleted(achievement)) return false; - - // A character may only have 1 race-specific 'Realm First!' achievement - // prevent clever use of the race/faction change service to obtain multiple 'Realm First!' achievements - constexpr std::array raceSpecificRealmFirstAchievements { 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413 }; - bool isRaceSpecific = std::ranges::find(raceSpecificRealmFirstAchievements, achievement->ID) != std::ranges::end(raceSpecificRealmFirstAchievements); - if (isRaceSpecific) - for (uint32 raceAchievementId : raceSpecificRealmFirstAchievements) - if (raceAchievementId != achievement->ID && HasAchieved(raceAchievementId)) - return false; } // pussywizard: progress will be deleted after getting the achievement (optimization) diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 985193f9d..0e4dd3fde 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -1103,3 +1103,22 @@ std::unordered_map ArenaTeam::ArenaReqPlayersForType = { ARENA_TYPE_3v3, 6}, { ARENA_TYPE_5v5, 10} }; + +void ArenaTeam::SetEmblem(uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor) +{ + BackgroundColor = backgroundColor; + EmblemStyle = emblemStyle; + EmblemColor = emblemColor; + BorderStyle = borderStyle; + BorderColor = borderColor; +} + +void ArenaTeam::SetRatingForAll(uint32 rating) +{ + Stats.Rating = rating; + + for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr) + { + itr->PersonalRating = rating; + } +} diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index 33c47920e..a0ec07397 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -217,6 +217,10 @@ public: static std::unordered_map ArenaSlotByType; // Slot -> Type static std::unordered_map ArenaReqPlayersForType; // Type -> Players count + void SetEmblem(uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor); + void SetRatingForAll(uint32 rating); + + protected: uint32 TeamId; uint8 Type; diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index b22cdc143..6178869f5 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -205,6 +205,7 @@ struct BattlegroundObjectInfo enum ArenaType : uint8 { + ARENA_TYPE_NONE = 0, ARENA_TYPE_2v2 = 2, ARENA_TYPE_3v3 = 3, ARENA_TYPE_5v5 = 5 diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index 72932386a..92e58975e 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -246,6 +246,18 @@ protected: uint32 BasesDefended = 0; }; +struct CaptureABPointInfo +{ + CaptureABPointInfo() : _ownerTeamId(TEAM_NEUTRAL), _iconNone(0), _iconCapture(0), _state(BG_AB_NODE_STATE_NEUTRAL), _captured(false) {} + + TeamId _ownerTeamId; + uint32 _iconNone; + uint32 _iconCapture; + uint8 _state; + + bool _captured; +}; + class AC_GAME_API BattlegroundAB : public Battleground { public: @@ -270,6 +282,9 @@ public: bool IsTeamScores500Disadvantage(TeamId teamId) const { return _teamScores500Disadvantage[teamId]; } TeamId GetPrematureWinner() override; + + [[nodiscard]] CaptureABPointInfo const& GetCapturePointInfo(uint32 node) const { return _capturePointInfo[node]; } + private: void PostUpdateImpl(uint32 diff) override; @@ -280,21 +295,7 @@ private: void NodeDeoccupied(uint8 node); void ApplyPhaseMask(); - struct CapturePointInfo - { - CapturePointInfo() : _ownerTeamId(TEAM_NEUTRAL), _iconNone(0), _iconCapture(0), _state(BG_AB_NODE_STATE_NEUTRAL), _captured(false) - { - } - - TeamId _ownerTeamId; - uint32 _iconNone; - uint32 _iconCapture; - uint8 _state; - - bool _captured; - }; - - CapturePointInfo _capturePointInfo[BG_AB_DYNAMIC_NODES_COUNT]; + CaptureABPointInfo _capturePointInfo[BG_AB_DYNAMIC_NODES_COUNT]; EventMap _bgEvents; uint32 _honorTics; uint32 _reputationTics; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 57417dd1d..eec6ff058 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1791,6 +1791,10 @@ public: TeamId GetPrematureWinner() override; + [[nodiscard]] BG_AV_NodeInfo const& GetAVNodeInfo(uint32 node) const { return m_Nodes[node]; } + [[nodiscard]] bool IsCaptainAlive(uint8 index) const { return m_CaptainAlive[index]; } + [[nodiscard]] TeamId GetMineOwner(uint8 index) const { return m_Mine_Owner[index]; } + private: void PostUpdateImpl(uint32 diff) override; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index 2730a0604..b4da9d7f5 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -346,6 +346,25 @@ protected: uint32 FlagCaptures = 0; }; +struct CaptureEYPointInfo +{ + CaptureEYPointInfo() : _ownerTeamId(TEAM_NEUTRAL), _barStatus(BG_EY_PROGRESS_BAR_STATE_MIDDLE), _areaTrigger(0) + { + _playersCount[TEAM_ALLIANCE] = 0; + _playersCount[TEAM_HORDE] = 0; + } + + Player* player = nullptr; + TeamId _ownerTeamId; + int8 _barStatus; + uint32 _areaTrigger; + int8 _playersCount[PVP_TEAMS_COUNT]; + + bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; } + bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; } + bool IsUncontrolled() const { return _ownerTeamId == TEAM_NEUTRAL; } +}; + class AC_GAME_API BattlegroundEY : public Battleground { public: @@ -385,6 +404,8 @@ public: bool AllNodesConrolledByTeam(TeamId teamId) const override; TeamId GetPrematureWinner() override; + [[nodiscard]] CaptureEYPointInfo const& GetCapturePointInfo(uint32 node) const { return _capturePointInfo[node]; } + private: void PostUpdateImpl(uint32 diff) override; @@ -400,26 +421,7 @@ private: /* Scorekeeping */ void AddPoints(TeamId teamId, uint32 points); - struct CapturePointInfo - { - CapturePointInfo() : _ownerTeamId(TEAM_NEUTRAL), _barStatus(BG_EY_PROGRESS_BAR_STATE_MIDDLE), _areaTrigger(0) - { - _playersCount[TEAM_ALLIANCE] = 0; - _playersCount[TEAM_HORDE] = 0; - } - - TeamId _ownerTeamId; - int8 _barStatus; - uint32 _areaTrigger; - int8 _playersCount[PVP_TEAMS_COUNT]; - Player* player = nullptr; - - bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; } - bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; } - bool IsUncontrolled() const { return _ownerTeamId == TEAM_NEUTRAL; } - }; - - CapturePointInfo _capturePointInfo[EY_POINTS_MAX]; + CaptureEYPointInfo _capturePointInfo[EY_POINTS_MAX]; EventMap _bgEvents; uint32 _honorTics; uint8 _ownedPointsCount[PVP_TEAMS_COUNT]; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index 9f859ddfe..bc5daf8fc 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -922,6 +922,9 @@ public: bool AllNodesConrolledByTeam(TeamId teamId) const override; // overwrited bool IsResourceGlutAllowed(TeamId teamId) const; void DoAction(uint32 action, ObjectGuid guid) override; + + [[nodiscard]] ICNodePoint const& GetICNodePoint(uint8 index) { return nodePoint[index]; } + private: uint32 closeFortressDoorsTimer; bool doorsClosed; diff --git a/src/server/game/Chat/Channels/ChannelMgr.h b/src/server/game/Chat/Channels/ChannelMgr.h index daf595d2f..868f2a171 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.h +++ b/src/server/game/Chat/Channels/ChannelMgr.h @@ -40,6 +40,7 @@ public: Channel* GetJoinChannel(std::string const& name, uint32 channel_id); Channel* GetChannel(std::string const& name, Player* p, bool pkt = true); + const ChannelMap& GetChannels() const { return channels; } static void LoadChannels(); static void LoadChannelRights(); diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index a0dc7f090..33892e072 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -371,6 +371,78 @@ std::size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, La return BuildChatPacket(data, chatType, language, senderGUID, receiverGUID, message, chatTag, senderName, receiverName, achievementId, gmMessage, channelName); } +void ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg msgtype, std::string_view message, Language language /*= LANG_UNIVERSAL*/, PlayerChatTag chatTag /*= CHAT_TAG_NONE*/, + ObjectGuid const& senderGuid /*= ObjectGuid()*/, std::string_view senderName /*= nullptr*/, + ObjectGuid const& targetGuid /*= ObjectGuid()*/, std::string_view targetName /*= nullptr*/, + std::string_view channelName /*= nullptr*/, uint32 achievementId /*= 0*/) +{ + const bool isGM = (chatTag & CHAT_TAG_GM) != 0; + bool isAchievement = false; + + data.Initialize((isGM && language != LANG_ADDON) ? SMSG_GM_MESSAGECHAT : SMSG_MESSAGECHAT); + data << uint8(msgtype); + data << uint32(language); + data << ObjectGuid(senderGuid); + data << uint32(0); // 2.1.0 + + switch (msgtype) + { + case CHAT_MSG_MONSTER_SAY: + case CHAT_MSG_MONSTER_PARTY: + case CHAT_MSG_MONSTER_YELL: + case CHAT_MSG_MONSTER_WHISPER: + case CHAT_MSG_MONSTER_EMOTE: + case CHAT_MSG_RAID_BOSS_WHISPER: + case CHAT_MSG_RAID_BOSS_EMOTE: + case CHAT_MSG_BATTLENET: + case CHAT_MSG_WHISPER_FOREIGN: + data << uint32(senderName.size() + 1); + data << senderName; + data << ObjectGuid(targetGuid); // Unit Target + if (targetGuid && !targetGuid.IsPlayer() && !targetGuid.IsPet() && (msgtype != CHAT_MSG_WHISPER_FOREIGN)) + { + data << uint32(targetName.size() + 1); // target name length + data << targetName; // target name + } + break; + case CHAT_MSG_BG_SYSTEM_NEUTRAL: + case CHAT_MSG_BG_SYSTEM_ALLIANCE: + case CHAT_MSG_BG_SYSTEM_HORDE: + data << ObjectGuid(targetGuid); // Unit Target + if (targetGuid && !targetGuid.IsPlayer()) + { + data << uint32(targetName.size() + 1); // target name length + data << targetName; // target name + } + break; + case CHAT_MSG_ACHIEVEMENT: + case CHAT_MSG_GUILD_ACHIEVEMENT: + data << ObjectGuid(targetGuid); // Unit Target + isAchievement = true; + break; + default: + if (isGM) + { + data << uint32(senderName.size() + 1); + data << senderName; + } + + if (msgtype == CHAT_MSG_CHANNEL) + { + data << channelName; + } + data << ObjectGuid(targetGuid); + break; + } + data << uint32(message.size() + 1); + data << message; + data << uint8(chatTag); + + if (isAchievement) + data << uint32(achievementId); +} + + Player* ChatHandler::getSelectedPlayer() const { if (!m_session) diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index e2891a3b8..adddbd6d1 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -33,6 +33,17 @@ class WorldObject; struct GameTele; +enum PlayerChatTag +{ + CHAT_TAG_NONE = 0x00, + CHAT_TAG_AFK = 0x01, + CHAT_TAG_DND = 0x02, + CHAT_TAG_GM = 0x04, + CHAT_TAG_COM = 0x08, // Commentator + CHAT_TAG_DEV = 0x10, // Developer +}; +typedef uint32 ChatTagFlags; + class AC_GAME_API ChatHandler { public: @@ -47,6 +58,13 @@ public: // Builds chat packet and returns receiver guid position in the packet to substitute in whisper builders static std::size_t BuildChatPacket(WorldPacket& data, ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string_view message, uint32 achievementId = 0, std::string const& channelName = "", LocaleConstant locale = DEFAULT_LOCALE); + // All in one chat message builder + static void BuildChatPacket( + WorldPacket& data, ChatMsg msgtype, std::string_view message, Language language = LANG_UNIVERSAL, PlayerChatTag chatTag = CHAT_TAG_NONE, + ObjectGuid const& senderGuid = ObjectGuid(), std::string_view senderName = {}, + ObjectGuid const& targetGuid = ObjectGuid(), std::string_view targetName = {}, + std::string_view channelName = {}, uint32 achievementId = 0); + static char* LineFromMessage(char*& pos) { char* start = strtok(pos, "\n"); pos = nullptr; return start; } void SendNotification(std::string_view str); diff --git a/src/server/game/Combat/UnitEvents.h b/src/server/game/Combat/UnitEvents.h index da2c1a965..db1408089 100644 --- a/src/server/game/Combat/UnitEvents.h +++ b/src/server/game/Combat/UnitEvents.h @@ -92,13 +92,27 @@ private: }; ThreatMgr* iThreatMgr; public: - ThreatRefStatusChangeEvent(uint32 pType) : UnitBaseEvent(pType), iThreatMgr(nullptr) { iHostileReference = nullptr; } + ThreatRefStatusChangeEvent(uint32 pType) : UnitBaseEvent(pType), iFValue(0.f), iThreatMgr(nullptr) + { + iHostileReference = nullptr; + } - ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference) : UnitBaseEvent(pType), iThreatMgr(nullptr) { iHostileReference = pHostileReference; } + ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference) : UnitBaseEvent(pType), iFValue(0.f), iThreatMgr(nullptr) + { + iHostileReference = pHostileReference; + } - ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, float pValue) : UnitBaseEvent(pType), iThreatMgr(nullptr) { iHostileReference = pHostileReference; iFValue = pValue; } + ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, float pValue) : UnitBaseEvent(pType), iThreatMgr(nullptr) + { + iHostileReference = pHostileReference; + iFValue = pValue; + } - ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, bool pValue) : UnitBaseEvent(pType), iThreatMgr(nullptr) { iHostileReference = pHostileReference; iBValue = pValue; } + ThreatRefStatusChangeEvent(uint32 pType, HostileReference* pHostileReference, bool pValue) : UnitBaseEvent(pType), iThreatMgr(nullptr) + { + iHostileReference = pHostileReference; + iBValue = pValue; + } [[nodiscard]] int32 getIValue() const { return iIValue; } diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 7aa741332..7cb68e1e4 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -34,11 +34,16 @@ typedef std::map AreaFlagByMapID; typedef std::tuple WMOAreaTableKey; typedef std::map WMOAreaInfoByTripple; +typedef std::multimap CharSectionsMap; + DBCStorage sAreaTableStore(AreaTableEntryfmt); DBCStorage sAreaGroupStore(AreaGroupEntryfmt); DBCStorage sAreaPOIStore(AreaPOIEntryfmt); static WMOAreaInfoByTripple sWMOAreaInfoByTripple; +static AreaFlagByAreaID sAreaFlagByAreaID; +// for instances without generated *.map files +static AreaFlagByMapID sAreaFlagByMapID; DBCStorage sAchievementStore(Achievementfmt); DBCStorage sAchievementCategoryStore(AchievementCategoryfmt); @@ -49,6 +54,10 @@ DBCStorage sBattlemasterListStore(BattlemasterListEntryf DBCStorage sBarberShopStyleStore(BarberShopStyleEntryfmt); DBCStorage sCharStartOutfitStore(CharStartOutfitEntryfmt); std::map sCharStartOutfitMap; + +DBCStorage sCharSectionsStore(CharSectionsEntryfmt); +CharSectionsMap sCharSectionMap; + DBCStorage sCharTitlesStore(CharTitlesEntryfmt); DBCStorage sChatChannelsStore(ChatChannelsEntryfmt); DBCStorage sChrClassesStore(ChrClassesEntryfmt); @@ -71,6 +80,10 @@ DBCStorage sDurabilityCostsStore(DurabilityCostsfmt); DBCStorage sEmotesStore(EmotesEntryfmt); DBCStorage sEmotesTextStore(EmotesTextEntryfmt); +typedef std::tuple EmotesTextSoundKey; +static std::map sEmotesTextSoundMap; +DBCStorage sEmotesTextSoundStore(EmotesTextSoundEntryfmt); + typedef std::map FactionTeamMap; static FactionTeamMap sFactionTeamMap; DBCStorage sFactionStore(FactionEntryfmt); @@ -280,6 +293,7 @@ void LoadDBCStores(const std::string& dataPath) LOAD_DBC(sBattlemasterListStore, "BattlemasterList.dbc", "battlemasterlist_dbc"); LOAD_DBC(sBarberShopStyleStore, "BarberShopStyle.dbc", "barbershopstyle_dbc"); LOAD_DBC(sCharStartOutfitStore, "CharStartOutfit.dbc", "charstartoutfit_dbc"); + LOAD_DBC(sCharSectionsStore, "CharSections.dbc", "charsections_dbc"); LOAD_DBC(sCharTitlesStore, "CharTitles.dbc", "chartitles_dbc"); LOAD_DBC(sChatChannelsStore, "ChatChannels.dbc", "chatchannels_dbc"); LOAD_DBC(sChrClassesStore, "ChrClasses.dbc", "chrclasses_dbc"); @@ -299,6 +313,7 @@ void LoadDBCStores(const std::string& dataPath) LOAD_DBC(sDurabilityQualityStore, "DurabilityQuality.dbc", "durabilityquality_dbc"); LOAD_DBC(sEmotesStore, "Emotes.dbc", "emotes_dbc"); LOAD_DBC(sEmotesTextStore, "EmotesText.dbc", "emotestext_dbc"); + LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc", "emotetextsound_dbc"); LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc"); LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc"); LOAD_DBC(sGameObjectArtKitStore, "GameObjectArtKit.dbc", "gameobjectartkit_dbc"); @@ -384,9 +399,26 @@ void LoadDBCStores(const std::string& dataPath) #undef LOAD_DBC + for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i) // areaflag numbered from 0 + { + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(i)) + { + // fill AreaId->DBC records + sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID), area->exploreFlag)); + + // fill MapId->DBC records ( skip sub zones and continents ) + if (area->zone == 0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530) + sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid, area->exploreFlag)); + } + } + for (CharStartOutfitEntry const* outfit : sCharStartOutfitStore) sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit; + for (CharSectionsEntry const* charSection : sCharSectionsStore) + if (charSection->Race && ((1 << (charSection->Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0) //ignore Nonplayable races + sCharSectionMap.insert({ charSection->GenType | (charSection->Gender << 8) | (charSection->Race << 16), charSection }); + for (FactionEntry const* faction : sFactionStore) { if (faction->team) @@ -408,6 +440,9 @@ void LoadDBCStores(const std::string& dataPath) std::swap(*(float*)(&info->maxZ), *(float*)(&info->minZ)); } + for (EmotesTextSoundEntry const* emoteTextSound : sEmotesTextSoundStore) + sEmotesTextSoundMap[EmotesTextSoundKey(emoteTextSound->EmotesTextId, emoteTextSound->RaceId, emoteTextSound->SexId)] = emoteTextSound; + // fill data for (MapDifficultyEntry const* entry : sMapDifficultyStore) sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = MapDifficulty(entry->resetTime, entry->maxPlayers, entry->areaTriggerText[0] != '\0'); @@ -848,6 +883,18 @@ CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, ui return itr->second; } +CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color) +{ + std::pair eqr = sCharSectionMap.equal_range(uint32(genType) | uint32(gender << 8) | uint32(race << 16)); + for (CharSectionsMap::const_iterator itr = eqr.first; itr != eqr.second; ++itr) + { + if (itr->second->Type == type && itr->second->Color == color) + return itr->second; + } + + return nullptr; +} + /// Returns LFGDungeonEntry for a specific map and difficulty. Will return first found entry if multiple dungeons use the same map (such as Scarlet Monastery) LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty) { @@ -913,6 +960,12 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u return nullptr; } +EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender) +{ + auto itr = sEmotesTextSoundMap.find(EmotesTextSoundKey(emote, race, gender)); + return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr; +} + const std::vector& GetSkillLineAbilitiesBySkillLine(uint32 skillLine) { auto it = sSkillLineAbilityIndexBySkillLine.find(skillLine); @@ -923,3 +976,40 @@ const std::vector& GetSkillLineAbilitiesBySkillLin } return it->second; } + +uint32 GetAreaFlagByMapId(uint32 mapid) +{ + AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid); + if (i == sAreaFlagByMapID.end()) + return 0; + return i->second; +} + +int32 GetAreaFlagByAreaID(uint32 area_id) +{ + AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id); + if (i == sAreaFlagByAreaID.end()) + return -1; + + return i->second; +} + +AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id) +{ + int32 areaflag = GetAreaFlagByAreaID(area_id); + if (areaflag < 0) + return nullptr; + + return sAreaTableStore.LookupEntry(areaflag); +} + +AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id) +{ + if (area_flag) + return sAreaTableStore.LookupEntry(area_flag); + + if (MapEntry const* mapEntry = sMapStore.LookupEntry(map_id)) + return GetAreaEntryByAreaID(mapEntry->linked_zone); + + return nullptr; +} \ No newline at end of file diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index ec8cb68bb..011a9cbab 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -35,6 +35,13 @@ TalentSpellPos const* GetTalentSpellPos(uint32 spellId); WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid); + +// -1 if not found +int32 GetAreaFlagByAreaID(uint32 area_id); +uint32 GetAreaFlagByMapId(uint32 mapid); +AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id); +AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id); + uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId); enum ContentLevels : uint8 @@ -63,6 +70,8 @@ PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundB CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender); +CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color); + LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty difficulty); LFGDungeonEntry const* GetZoneLFGDungeonEntry(std::string const& zoneName, LocaleConstant locale); @@ -72,6 +81,7 @@ typedef std::unordered_multimap SkillRac typedef std::pair SkillRaceClassInfoBounds; SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); +EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender); typedef std::unordered_map > SkillLineAbilityIndexBySkillLine; const std::vector& GetSkillLineAbilitiesBySkillLine(uint32 skillLine); @@ -87,6 +97,7 @@ extern DBCStorage sBarberShopStyleStore; extern DBCStorage sBattlemasterListStore; extern DBCStorage sChatChannelsStore; extern DBCStorage sCharStartOutfitStore; +extern DBCStorage sCharSectionsStore; extern DBCStorage sCharTitlesStore; extern DBCStorage sChrClassesStore; extern DBCStorage sChrRacesStore; @@ -105,6 +116,7 @@ extern DBCStorage sDurabilityCostsStore; extern DBCStorage sDurabilityQualityStore; extern DBCStorage sEmotesStore; extern DBCStorage sEmotesTextStore; +extern DBCStorage sEmotesTextSoundStore; extern DBCStorage sFactionStore; extern DBCStorage sFactionTemplateStore; extern DBCStorage sGameObjectArtKitStore; diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index c96ae4f2a..fd4bd6ce9 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -581,6 +581,7 @@ namespace lfg [[nodiscard]] bool IsTesting() const { return m_Testing; } void SetDungeon(ObjectGuid guid, uint32 dungeon); + LFGDungeonData const* GetLFGDungeon(uint32 id); private: TeamId GetTeam(ObjectGuid guid); @@ -593,7 +594,6 @@ namespace lfg void SetCanOverrideRBState(ObjectGuid guid, bool val); void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap, uint32 randomDungeonId = 0); void _SaveToDB(ObjectGuid guid); - LFGDungeonData const* GetLFGDungeon(uint32 id); // Proposals void RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type); diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index aae5df67a..6e7f99a32 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -25,6 +25,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "Player.h" +#include "ScriptMgr.h" #include "World.h" namespace lfg @@ -411,6 +412,11 @@ namespace lfg if (!sLFGMgr->AllQueued(check)) // can't create proposal return LFG_COMPATIBILITY_PENDING; + if (!sScriptMgr->OnPlayerbotCheckLFGQueue(proposal.queues)) + { + return LFG_INCOMPATIBLES_HAS_IGNORES; + } + // Create a new proposal proposal.cancelTime = GameTime::GetGameTime().count() + LFG_TIME_PROPOSAL; proposal.state = LFG_PROPOSAL_INITIATING; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 4a8a98354..bd98a2570 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1373,6 +1373,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) m_spawnId = sObjectMgr->GenerateCreatureSpawnId(); CreatureData& data = sObjectMgr->NewOrExistCreatureData(m_spawnId); + data.spawnId = m_spawnId; uint32 displayId = GetNativeDisplayId(); uint32 npcflag = GetNpcFlags(); @@ -3497,7 +3498,7 @@ bool Creature::IsMovementPreventedByCasting() const void Creature::SetCannotReachTarget(ObjectGuid const& cannotReach) { if (cannotReach == m_cannotReachTarget) - { +{ return; } diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index f1f3d6f02..92e1c4bb2 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -365,6 +365,7 @@ typedef std::unordered_map EquipmentInfo struct CreatureData { CreatureData() = default; + ObjectGuid::LowType spawnId{0}; uint32 id1{0}; // entry in creature_template uint32 id2{0}; // entry in creature_template uint32 id3{0}; // entry in creature_template diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 9aea0ea74..9c0c27fb7 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1084,7 +1084,7 @@ void Item::SendTimeUpdate(Player* owner) owner->SendDirectMessage(&data); } -Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clone, uint32 randomPropertyId) +Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clone, uint32 randomPropertyId, bool temp) { if (count < 1) return nullptr; //don't create item at zero count @@ -1098,7 +1098,8 @@ Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clo ASSERT_NODEBUGINFO(count != 0 && "pProto->Stackable == 0 but checked at loading already"); Item* pItem = NewItemOrBag(pProto); - if (pItem->Create(sObjectMgr->GetGenerator().Generate(), item, player)) + uint32 guid = temp ? 0xFFFFFFFF : sObjectMgr->GetGenerator().Generate(); + if (pItem->Create(guid, item, player)) { pItem->SetCount(count); if (!clone) @@ -1276,10 +1277,15 @@ void Item::ClearSoulboundTradeable(Player* currentOwner) bool Item::CheckSoulboundTradeExpire() { - // called from owner's update - GetOwner() MUST be valid - if (GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME) + 2 * HOUR < GetOwner()->GetTotalPlayedTime()) + // we have to check the owner for mod_playerbots since bots programically call methods like DestroyItem, + // MoveItemToMail, DestroyItemCount which do not handle soulboundTradeable clearing. + Player* owner = GetOwner(); + if (!owner) + return true; // remove from tradeable list + + if (GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME) + 2 * HOUR < owner->GetTotalPlayedTime()) { - ClearSoulboundTradeable(GetOwner()); + ClearSoulboundTradeable(owner); return true; // remove from tradeable list } diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 9f467fad7..c53867e29 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -219,7 +219,7 @@ bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto); class Item : public Object { public: - static Item* CreateItem(uint32 item, uint32 count, Player const* player = nullptr, bool clone = false, uint32 randomPropertyId = 0); + static Item* CreateItem(uint32 item, uint32 count, Player const* player = nullptr, bool clone = false, uint32 randomPropertyId = 0, bool temp = false); Item* CloneItem(uint32 count, Player const* player = nullptr) const; Item(); diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index b073cb107..28378270f 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -251,7 +251,7 @@ enum SocketColor #define SOCKET_COLOR_ALL (SOCKET_COLOR_META | SOCKET_COLOR_RED | SOCKET_COLOR_YELLOW | SOCKET_COLOR_BLUE) -enum InventoryType +enum InventoryType : uint32 { INVTYPE_NON_EQUIP = 0, INVTYPE_HEAD = 1, @@ -826,6 +826,8 @@ struct ItemTemplate [[nodiscard]] bool IsWeaponVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_WEAPON_ENCHANTMENT; } [[nodiscard]] bool IsArmorVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT; } [[nodiscard]] bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && HasFlag(ITEM_FLAG_CONJURED); } + [[nodiscard]] bool IsWeapon() const { return Class == ITEM_CLASS_WEAPON; } + [[nodiscard]] bool IsRangedWeapon() const { return IsWeapon() && (InventoryType == INVTYPE_RANGED || InventoryType == INVTYPE_THROWN || InventoryType == INVTYPE_RANGEDRIGHT); } [[nodiscard]] bool HasStat(ItemModType stat) const; [[nodiscard]] bool HasSpellPowerStat() const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ea1dbf9f5..26ecd4dc4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -3294,7 +3294,9 @@ void Player::learnSpell(uint32 spellId, bool temporary /*= false*/, bool learnFr // Xinef: don't allow to learn active spell once more if (HasActiveSpell(spellId)) { +#ifndef MOD_PLAYERBOTS LOG_DEBUG("entities.player", "Player ({}) tries to learn already active spell: {}", GetGUID().ToString(), spellId); +#endif return; } @@ -4330,6 +4332,28 @@ void Player::DeleteOldRecoveryItems(uint32 keepDays) } } +void Player::SetMovement(PlayerMovementType pType) +{ + WorldPacket data; + const PackedGuid& guid = GetPackGUID(); + switch (pType) + { + case MOVE_WATER_WALK: + data.Initialize(SMSG_MOVE_WATER_WALK, guid.size() + 4); + break; + case MOVE_LAND_WALK: + data.Initialize(SMSG_MOVE_LAND_WALK, guid.size() + 4); + break; + default: + LOG_ERROR("entities.player", "Player::SetMovement: Unsupported move type ({}), data not sent to client.", pType); + return; + } + data << guid; + data << GetSession()->GetOrderCounter(); // movement counter + SendDirectMessage(&data); + GetSession()->IncrementOrderCounter(); +} + /* Preconditions: - a resurrectable corpse must not be loaded for the player (only bones) - the player must be in world @@ -4365,6 +4389,7 @@ void Player::BuildPlayerRepop() } GetMap()->AddToMap(corpse); SetHealth(1); // convert player body to ghost + SetMovement(MOVE_WATER_WALK); SetWaterWalking(true); if (!IsImmobilizedState()) @@ -4405,6 +4430,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) SetDynamicFlag(UNIT_DYNFLAG_REFER_A_FRIEND); setDeathState(DeathState::Alive); + SetMovement(MOVE_LAND_WALK); SendMoveRoot(false); SetWaterWalking(false); m_deathTimer = 0; @@ -4925,6 +4951,15 @@ void Player::CleanupChannels() } } +// Playerbot helper if bot talks in a different locale +bool Player::IsInChannel(const Channel* c) +{ + return std::any_of(m_channels.begin(), m_channels.end(), [c](const Channel* chan) + { + return c->GetChannelId() == chan->GetChannelId(); + }); +} + void Player::ClearChannelWatch() { for (JoinedChannelsList::iterator itr = m_channels.begin(); itr != m_channels.end(); ++itr) @@ -9355,7 +9390,11 @@ void Player::Say(std::string_view text, Language language, WorldObject const* /* { std::string _text(text); if (!sScriptMgr->OnPlayerCanUseChat(this, CHAT_MSG_SAY, language, _text)) + { return; + } + + sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, language, this, this, _text); @@ -9377,7 +9416,11 @@ void Player::Yell(std::string_view text, Language language, WorldObject const* / std::string _text(text); if (!sScriptMgr->OnPlayerCanUseChat(this, CHAT_MSG_YELL, language, _text)) + { return; + } + + sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, language, this, this, _text); @@ -9399,7 +9442,11 @@ void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/, std::string _text(text); if (!sScriptMgr->OnPlayerCanUseChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text)) + { return; + } + + sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); @@ -9428,7 +9475,11 @@ void Player::Whisper(std::string_view text, Language language, Player* target, b std::string _text(text); if (!sScriptMgr->OnPlayerCanUseChat(this, CHAT_MSG_WHISPER, language, _text, target)) + { return; + } + + sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, target); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, language, this, this, _text); @@ -11635,7 +11686,7 @@ void Player::SendInitialPacketsAfterAddToMap() GetSession()->IncrementOrderCounter(); } - if (HasAuraType(SPELL_AURA_WATER_WALK) || HasAura(8326)) + if (HasAuraType(SPELL_AURA_WATER_WALK)) { uint32 const counter = GetSession()->GetOrderCounter(); setCompoundState << uint8(2 + GetPackGUID().size() + 4); @@ -12045,6 +12096,18 @@ void Player::GetAurasForTarget(Unit* target, bool force /*= false*/) if (!target || (!force && target->GetVisibleAuras()->empty())) // speedup things return; + /*! Blizz sends certain movement packets sometimes even before CreateObject + These movement packets are usually found in SMSG_COMPRESSED_MOVES + */ + if (target->HasFeatherFallAura()) + target->SendMovementFeatherFall(this); + + if (target->HasWaterWalkAura()) + target->SendMovementWaterWalking(this); + + if (target->HasHoverAura()) + target->SendMovementHover(this); + WorldPacket data(SMSG_AURA_UPDATE_ALL); data<< target->GetPackGUID(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 9496eb950..399ad652a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -656,7 +656,7 @@ enum PlayerSlots #define INVENTORY_SLOT_BAG_0 255 -enum EquipmentSlots // 19 slots +enum EquipmentSlots : uint32 // 19 slots { EQUIPMENT_SLOT_START = 0, EQUIPMENT_SLOT_HEAD = 0, @@ -827,16 +827,6 @@ enum EnviromentalDamage DAMAGE_FALL_TO_VOID = 6 // custom case for fall without durability loss }; -enum PlayerChatTag -{ - CHAT_TAG_NONE = 0x00, - CHAT_TAG_AFK = 0x01, - CHAT_TAG_DND = 0x02, - CHAT_TAG_GM = 0x04, - CHAT_TAG_COM = 0x08, // Commentator tag. Do not exist in clean client - CHAT_TAG_DEV = 0x10, -}; - enum PlayedTimeIndex { PLAYED_TIME_TOTAL = 0, @@ -1292,6 +1282,7 @@ public: InventoryResult CanUseItem(Item* pItem, bool not_loading = true) const; [[nodiscard]] bool HasItemTotemCategory(uint32 TotemCategory) const; bool IsTotemCategoryCompatiableWith(ItemTemplate const* pProto, uint32 requiredTotemCategoryId) const; + InventoryResult BotCanUseItem(ItemTemplate const* pItem) const; InventoryResult CanUseItem(ItemTemplate const* pItem) const; [[nodiscard]] InventoryResult CanUseAmmo(uint32 item) const; InventoryResult CanRollForItemInLFG(ItemTemplate const* item, WorldObject const* lootedObject) const; @@ -2050,10 +2041,13 @@ public: } bool IsMirrorTimerActive(MirrorTimerType type) { return m_MirrorTimer[type] == getMaxTimer(type); } + void SetMovement(PlayerMovementType pType); + bool CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone); void JoinedChannel(Channel* c); void LeftChannel(Channel* c); + bool IsInChannel(const Channel* c); void CleanupChannels(); void ClearChannelWatch(); void UpdateLFGChannel(); @@ -2634,6 +2628,8 @@ public: void SendSystemMessage(std::string_view msg, bool escapeCharacters = false); + void ResetSpeakTimers(); + std::string GetDebugInfo() const override; bool IsExpectingChangeTransport() const { return _expectingChangeTransport; } diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index e8117aa58..b7932bbc3 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -908,6 +908,31 @@ bool Player::IsTotemCategoryCompatiableWith(ItemTemplate const* pProto, uint32 r return true; } +InventoryResult Player::BotCanUseItem(ItemTemplate const* proto) const +{ + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass == ITEM_SUBCLASS_ARMOR_IDOL && !IsClass(CLASS_DRUID, CLASS_CONTEXT_EQUIP_RELIC)) + { + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + } + + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass == ITEM_SUBCLASS_ARMOR_TOTEM && !IsClass(CLASS_SHAMAN, CLASS_CONTEXT_EQUIP_RELIC)) + { + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + } + + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass == ITEM_SUBCLASS_ARMOR_LIBRAM && !IsClass(CLASS_PALADIN, CLASS_CONTEXT_EQUIP_RELIC)) + { + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + } + + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass == ITEM_SUBCLASS_ARMOR_SIGIL && !IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_EQUIP_RELIC)) + { + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + } + + return CanUseItem(proto); +} + InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemTemplate const* pProto, uint32& count, bool swap, Item* pSrcItem) const { Item* pItem2 = GetItemByPos(bag, slot); diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index 469131a65..669bd3bc3 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -447,6 +447,7 @@ void Player::Update(uint32 p_time) m_delayed_unit_relocation_timer = 0; RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED); } + sScriptMgr->OnPlayerAfterUpdate(this, p_time); } void Player::UpdateMirrorTimers() @@ -1462,9 +1463,6 @@ void Player::UpdatePvPState() if (pvpInfo.IsHostile) // in hostile area { - if (IsInFlight()) // on taxi - return; - if (!IsPvP() || pvpInfo.EndTimer != 0) UpdatePvP(true, true); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 615732f59..b67a2ecd3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -1864,7 +1864,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) auto canTakeMeleeDamage = [&]() { - return victim->IsAlive() && !victim->IsInFlight() && (!victim->IsCreature() || !victim->ToCreature()->IsEvadingAttacks()); + return victim->IsAlive() && !victim->HasUnitState(UNIT_STATE_IN_FLIGHT) && (!victim->IsCreature() || !victim->ToCreature()->IsEvadingAttacks()); }; if (!canTakeMeleeDamage()) @@ -1956,11 +1956,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) Probability = 0.65f * victim->GetLevel() + 0.5f; uint32 VictimDefense = victim->GetDefenseSkillValue(); - uint32 VictimAuraDefense = -victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE) * 25; uint32 AttackerMeleeSkill = GetUnitMeleeSkill(); // xinef: fix daze mechanics - Probability -= ((float)VictimDefense + (float)VictimAuraDefense - AttackerMeleeSkill) * 0.1428f; + Probability -= ((float)VictimDefense - AttackerMeleeSkill) * 0.1428f; if (Probability > 40.0f) Probability = 40.0f; @@ -10403,6 +10402,11 @@ ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTem } } + return GetFactionReactionTo(factionTemplateEntry, targetFactionTemplateEntry); +} + +ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, FactionTemplateEntry const* targetFactionTemplateEntry) +{ // common faction based check if (factionTemplateEntry->IsHostileTo(*targetFactionTemplateEntry)) return REP_HOSTILE; @@ -10412,6 +10416,7 @@ ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTem return REP_FRIENDLY; if (factionTemplateEntry->factionFlags & FACTION_TEMPLATE_FLAG_HATES_ALL_EXCEPT_FRIENDS) return REP_HOSTILE; + // neutral by default return REP_NEUTRAL; } @@ -15975,6 +15980,11 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup) if (IsInWorld()) // not in world and not being removed atm RemoveFromWorld(); + // Added for mod_playerbots crash fixes; cancel and remove pending events before aura/spellmod cleanup. + // Without this SpellEvent may be cancelled later during EventProcessor destruction after auras/spellmods + // are already removed and leading to invalid access in Player::RestoreSpellMods on logout. + m_Events.KillAllEvents(false); + ASSERT(GetGUID()); // A unit may be in removelist and not in world, but it is still in grid @@ -18225,6 +18235,8 @@ void Unit::Kill(Unit* killer, Unit* victim, bool durabilityLoss, WeaponAttackTyp } } + sScriptMgr->OnPlayerbotCheckKillTask(player, victim); + // Dungeon specific stuff, only applies to players killing creatures if (creature->GetInstanceId()) { @@ -18417,8 +18429,10 @@ void Unit::SetControlled(bool apply, UnitState state, Unit* source /*= nullptr*/ void Unit::SetStunned(bool apply) { - if (IsInFlight()) + if (HasUnitState(UNIT_STATE_IN_FLIGHT)) + { return; + } if (apply) { @@ -19167,11 +19181,23 @@ void Unit::SendPlaySpellVisual(uint32 id) SendMessageToSet(&data, true); } +void Unit::SendPlaySpellVisual(ObjectGuid guid, uint32 id) +{ + WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 8 + 4); + data << guid; + data << uint32(id); // SpellVisualKit.dbc index + SendMessageToSet(&data, true); +} + void Unit::SendPlaySpellImpact(ObjectGuid guid, uint32 id) { WorldPacket data(SMSG_PLAY_SPELL_IMPACT, 8 + 4); data << guid; // target data << uint32(id); // SpellVisualKit.dbc index + + if (IsPlayer()) + ToPlayer()->SendDirectMessage(&data); + else SendMessageToSet(&data, true); } @@ -21494,3 +21520,18 @@ Player const* Unit::GetClientControlling() const } return nullptr; } + +void Unit::SetCannotReachTargetUnit(bool cannotReach, bool isChase) +{ + if (cannotReach == m_cannotReachTarget) + { + return; + } + + m_cannotReachTarget = cannotReach; +} + +bool Unit::CanNotReachTarget() const +{ + return m_cannotReachTarget; +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 1590c2721..a7e8aba76 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1851,6 +1851,7 @@ public: // Reputations system ReputationRank GetReactionTo(Unit const* target, bool checkOriginalFaction = false) const; ReputationRank GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, Unit const* target) const; + static ReputationRank GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, FactionTemplateEntry const* targetFactionTemplateEntry); // Shared vision SharedVisionList const& GetSharedVisionList() { return m_sharedVision; } @@ -2008,6 +2009,7 @@ public: void SendComboPoints(); void SendPlaySpellVisual(uint32 id); + void SendPlaySpellVisual(ObjectGuid guid, uint32 id); void SendPlaySpellImpact(ObjectGuid guid, uint32 id); void SendPetActionFeedback(uint8 msg) const; @@ -2049,6 +2051,10 @@ public: // Debug void OutDebugInfo() const; std::string GetDebugInfo() const override; + void SetCannotReachTargetUnit(bool target, bool isChase); + [[nodiscard]] bool CanNotReachTarget() const; + + bool m_cannotReachTarget; //----------- Public variables ----------// uint32 m_extraAttacks; diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h index 1aa254581..8b30a81d1 100644 --- a/src/server/game/Entities/Vehicle/VehicleDefines.h +++ b/src/server/game/Entities/Vehicle/VehicleDefines.h @@ -45,6 +45,7 @@ enum VehicleFlags VEHICLE_FLAG_CUSTOM_PITCH = 0x00000040, // If set use pitchMin and pitchMax from DBC, otherwise pitchMin = -pi/2, pitchMax = pi/2 VEHICLE_FLAG_ADJUST_AIM_ANGLE = 0x00000400, // Lua_IsVehicleAimAngleAdjustable VEHICLE_FLAG_ADJUST_AIM_POWER = 0x00000800, // Lua_IsVehicleAimPowerAdjustable + VEHICLE_FLAG_FIXED_POSITION = 0x00200000 // Used for cannons, when they should be rooted }; enum VehicleSpells diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 36028c0e3..0acf11080 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -867,6 +867,7 @@ public: return nullptr; } + [[nodiscard]] AreaTriggerTeleportContainer const& GetAllAreaTriggerTeleports() const { return _areaTriggerTeleportStore; } [[nodiscard]] AreaTriggerTeleport const* GetAreaTriggerTeleport(uint32 trigger) const { AreaTriggerTeleportContainer::const_iterator itr = _areaTriggerTeleportStore.find(trigger); diff --git a/src/server/game/Grids/GridTerrainData.cpp b/src/server/game/Grids/GridTerrainData.cpp index ab4a1c286..e2439dc2e 100644 --- a/src/server/game/Grids/GridTerrainData.cpp +++ b/src/server/game/Grids/GridTerrainData.cpp @@ -527,11 +527,9 @@ float GridTerrainData::getLiquidLevel(float x, float y) const } // Get water state on map -LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float collisionHeight, Optional ReqLiquidType) const +LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const { LiquidData liquidData; - liquidData.Status = LIQUID_MAP_NO_WATER; - if (!_loadedLiquidData) return liquidData; @@ -577,7 +575,7 @@ LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float } // Check req liquid type mask - if (type != 0 && (!ReqLiquidType || (*ReqLiquidType & type) != 0)) + if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0)) { // Check water level: // Check water height map diff --git a/src/server/game/Grids/GridTerrainData.h b/src/server/game/Grids/GridTerrainData.h index 18324d574..082e42282 100644 --- a/src/server/game/Grids/GridTerrainData.h +++ b/src/server/game/Grids/GridTerrainData.h @@ -186,7 +186,7 @@ struct LoadedHoleData HolesType holes; }; -enum LiquidStatus : uint32 +enum LiquidStatus { LIQUID_MAP_NO_WATER = 0x00000000, LIQUID_MAP_ABOVE_WATER = 0x00000001, @@ -249,7 +249,7 @@ public: inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); } float getMinHeight(float x, float y) const; float getLiquidLevel(float x, float y) const; - LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, Optional ReqLiquidType) const; + LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const; }; #endif diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index c4a9b9262..c208fc0ab 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -262,6 +262,8 @@ public: void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag); void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); + ObjectGuid const GetTargetIcon(uint8 id) const { return m_targetIcons[id]; } + Difficulty GetDifficulty(bool isRaid) const; Difficulty GetDungeonDifficulty() const; Difficulty GetRaidDifficulty() const; @@ -300,6 +302,8 @@ public: bool CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise); void EndRoll(Loot* loot, Map* allowedMap); + Rolls GetRolls() const { return RollId; } + // related to disenchant rolls void ResetMaxEnchantingLevel(); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index d38838121..cc31bfca6 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -829,7 +829,7 @@ bool Guild::BankMoveItemData::HasStoreRights(MoveItemData* pOther) const // Do not check rights if item is being swapped within the same bank tab if (pOther->IsBank() && pOther->GetContainer() == m_container) return true; - return m_pGuild->_MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM); + return m_pGuild->MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM); } bool Guild::BankMoveItemData::HasWithdrawRights(MoveItemData* pOther) const @@ -1218,7 +1218,7 @@ void Guild::HandleRoster(WorldSession* session) } } - bool sendOfficerNote = _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE); + bool sendOfficerNote = HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE); roster.MemberData.reserve(m_members.size()); for (auto const& [guid, member] : m_members) { @@ -1275,7 +1275,7 @@ void Guild::HandleSetMOTD(WorldSession* session, std::string_view motd) return; // Player must have rights to set MOTD - if (!_HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD)) + if (!HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD)) SendCommandResult(session, GUILD_COMMAND_EDIT_MOTD, ERR_GUILD_PERMISSIONS); else { @@ -1298,7 +1298,7 @@ void Guild::HandleSetInfo(WorldSession* session, std::string_view info) return; // Player must have rights to set guild's info - if (_HasRankRight(session->GetPlayer(), GR_RIGHT_MODIFY_GUILD_INFO)) + if (HasRankRight(session->GetPlayer(), GR_RIGHT_MODIFY_GUILD_INFO)) { m_info = info; @@ -1331,6 +1331,12 @@ void Guild::HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo) } } +void Guild::HandleSetEmblem(EmblemInfo const& emblemInfo) +{ + m_emblemInfo = emblemInfo; + m_emblemInfo.SaveToDB(m_id); +} + void Guild::HandleSetLeader(WorldSession* session, std::string_view name) { Player* player = session->GetPlayer(); @@ -1367,7 +1373,7 @@ void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string void Guild::HandleSetMemberNote(WorldSession* session, std::string_view name, std::string_view note, bool isPublic) { // Player must have rights to set public/officer note - if (!_HasRankRight(session->GetPlayer(), isPublic ? GR_RIGHT_EPNOTE : GR_RIGHT_EOFFNOTE)) + if (!HasRankRight(session->GetPlayer(), isPublic ? GR_RIGHT_EPNOTE : GR_RIGHT_EOFFNOTE)) SendCommandResult(session, GUILD_COMMAND_PUBLIC_NOTE, ERR_GUILD_PERMISSIONS); else if (Member* member = GetMember(name)) { @@ -1400,6 +1406,29 @@ void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string_v } } +void Guild::HandleSetRankInfo(uint8 rankId, uint32 rights, std::string_view name, uint32 moneyPerDay) +{ + if (RankInfo* rankInfo = GetRankInfo(rankId)) + { + if (!name.empty()) + { + rankInfo->SetName(name); + } + + if (rights > 0) + { + rankInfo->SetRights(rights); + } + + if (moneyPerDay > 0) + { + _SetRankBankMoneyPerDay(rankId, moneyPerDay); + } + + _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(rankId), rankInfo->GetName(), std::to_string(m_ranks.size())); + } +} + void Guild::HandleBuyBankTab(WorldSession* session, uint8 tabId) { Player* player = session->GetPlayer(); @@ -1470,7 +1499,7 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) return; } // Inviting player must have rights to invite - if (!_HasRankRight(player, GR_RIGHT_INVITE)) + if (!HasRankRight(player, GR_RIGHT_INVITE)) { SendCommandResult(session, GUILD_COMMAND_INVITE, ERR_GUILD_PERMISSIONS); return; @@ -1541,7 +1570,7 @@ void Guild::HandleRemoveMember(WorldSession* session, std::string_view name) { Player* player = session->GetPlayer(); // Player must have rights to remove members - if (!_HasRankRight(player, GR_RIGHT_REMOVE)) + if (!HasRankRight(player, GR_RIGHT_REMOVE)) SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_PERMISSIONS); else if (Member* member = GetMember(name)) { @@ -1574,7 +1603,7 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, std::string_view name, Player* player = session->GetPlayer(); GuildCommandType type = demote ? GUILD_COMMAND_DEMOTE : GUILD_COMMAND_PROMOTE; // Player must have rights to promote - if (!_HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE)) + if (!HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE)) SendCommandResult(session, type, ERR_GUILD_PERMISSIONS); // Promoted player must be a member of guild else if (Member* member = GetMember(name)) @@ -1708,7 +1737,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool if (uint32(_GetMemberRemainingMoney(*member)) < amount) // Check if we have enough slot/money today return false; - if (!(_GetRankRights(member->GetRankId()) & GR_RIGHT_WITHDRAW_REPAIR) && repair) + if (!(GetRankRights(member->GetRankId()) & GR_RIGHT_WITHDRAW_REPAIR) && repair) return false; // Call script after validation and before money transfer. @@ -1850,7 +1879,7 @@ void Guild::SendPermissions(WorldSession* session) WorldPackets::Guild::GuildPermissionsQueryResults queryResult; queryResult.RankID = rankId; queryResult.WithdrawGoldLimit = _GetRankBankMoneyPerDay(rankId); - queryResult.Flags = _GetRankRights(rankId); + queryResult.Flags = GetRankRights(rankId); queryResult.NumTabs = _GetPurchasedTabsSize(); for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) @@ -2116,13 +2145,13 @@ bool Guild::Validate() // Broadcasts void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::string_view msg, uint32 language) const { - if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) + if (session && session->GetPlayer() && HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPacket data; ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); for (auto const& [guid, member] : m_members) if (Player* player = member.FindPlayer()) - if (_HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID())) + if (HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID())) player->SendDirectMessage(&data); } } @@ -2177,11 +2206,19 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max // Members handling bool Guild::AddMember(ObjectGuid guid, uint8 rankId) { + Player* leader = nullptr; + if (this->GetLeaderGUID()) + { + leader = ObjectAccessor::FindConnectedPlayer(this->GetLeaderGUID()); + } + Player* player = ObjectAccessor::FindConnectedPlayer(guid); + // Player cannot be in guild if (player) { - if (player->GetGuildId() != 0) + if (player->GetGuildId() != 0 || + (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && (leader && leader->GetTeamId() != player->GetTeamId()))) return false; } else if (sCharacterCache->GetCharacterGuildIdByGuid(guid) != 0) @@ -2525,7 +2562,7 @@ inline std::string Guild::_GetRankName(uint8 rankId) const return ""; } -inline uint32 Guild::_GetRankRights(uint8 rankId) const +uint32 Guild::GetRankRights(uint8 rankId) const { if (const RankInfo* rankInfo = GetRankInfo(rankId)) return rankInfo->GetRights(); @@ -2574,7 +2611,7 @@ inline int32 Guild::_GetMemberRemainingMoney(Member const& member) const if (rankId == GR_GUILDMASTER) return static_cast(GUILD_WITHDRAW_MONEY_UNLIMITED); - if ((_GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != 0) + if ((GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != 0) { int32 remaining = _GetRankBankMoneyPerDay(rankId) - member.GetBankWithdrawValue(GUILD_BANK_MAX_TABS); if (remaining > 0) @@ -2594,7 +2631,7 @@ inline void Guild::_UpdateMemberWithdrawSlots(CharacterDatabaseTransaction trans } } -inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const +bool Guild::MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const { if (const Member* member = GetMember(guid)) { @@ -2606,6 +2643,19 @@ inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 righ return false; } +bool Guild::HasRankRight(Player* player, uint32 right) const +{ + if (player) + { + if (Member const* member = GetMember(player->GetGUID())) + { + return (GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY; + } + } + + return false; +} + // Add new event log record inline void Guild::_LogEvent(GuildEventLogTypes eventType, ObjectGuid playerGuid1, ObjectGuid playerGuid2, uint8 newRank) { @@ -2751,7 +2801,7 @@ bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError void Guild::_SendBankContent(WorldSession* session, uint8 tabId, bool sendAllSlots) const { ObjectGuid guid = session->GetPlayer()->GetGUID(); - if (!_MemberHasTabRights(guid, tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (!MemberHasTabRights(guid, tabId, GUILD_BANK_RIGHT_VIEW_TAB)) return; _SendBankList(session, tabId, sendAllSlots); @@ -2914,7 +2964,7 @@ void Guild::_SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*= if (!member.ShouldReceiveBankPartialUpdatePackets()) continue; - if (!_MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (!MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) continue; Player* player = member.FindPlayer(); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index ab5d47295..3e0d88522 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -238,7 +238,8 @@ enum GuildMemberFlags class EmblemInfo { public: - EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } + EmblemInfo(uint32 /*style*/ = 0, uint32 /*color*/ = 0, uint32 /*borderStyle*/ = 0, uint32 /*borderColor*/ = 0, uint32 /*backgroundColor*/ = 0) : + m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } void LoadFromDB(Field* fields); void SaveToDB(uint32 guildId) const; @@ -696,11 +697,13 @@ public: void HandleQuery(WorldSession* session); void HandleSetMOTD(WorldSession* session, std::string_view motd); void HandleSetInfo(WorldSession* session, std::string_view info); - void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo); + void HandleSetEmblem(WorldSession* session, EmblemInfo const& emblemInfo); + void HandleSetEmblem(EmblemInfo const& emblemInfo); void HandleSetLeader(WorldSession* session, std::string_view name); void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string_view name, std::string_view icon); void HandleSetMemberNote(WorldSession* session, std::string_view name, std::string_view note, bool isPublic); void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string_view name, uint32 rights, uint32 moneyPerDay, std::array const& rightsAndSlots); + void HandleSetRankInfo(uint8 rankId, uint32 rights = 0, std::string_view name = "", uint32 moneyPerDay = 0); void HandleBuyBankTab(WorldSession* session, uint8 tabId); void HandleInviteMember(WorldSession* session, std::string const& name); void HandleAcceptMember(WorldSession* session); @@ -779,6 +782,10 @@ public: [[nodiscard]] bool ModifyBankMoney(CharacterDatabaseTransaction trans, const uint64& amount, bool add) { return _ModifyBankMoney(trans, amount, add); } [[nodiscard]] uint32 GetMemberSize() const { return m_members.size(); } + bool MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const; + bool HasRankRight(Player* player, uint32 right) const; + uint32 GetRankRights(uint8 rankId) const; + protected: uint32 m_id; std::string m_name; @@ -803,13 +810,6 @@ private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } - inline bool _HasRankRight(Player* player, uint32 right) const - { - if (player) - if (Member const* member = GetMember(player->GetGUID())) - return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY; - return false; - } inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); } @@ -840,7 +840,6 @@ private: void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay); void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true); int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const; - uint32 _GetRankRights(uint8 rankId) const; int32 _GetRankBankMoneyPerDay(uint8 rankId) const; int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const; std::string _GetRankName(uint8 rankId) const; @@ -848,7 +847,6 @@ private: int32 _GetMemberRemainingSlots(Member const& member, uint8 tabId) const; int32 _GetMemberRemainingMoney(Member const& member) const; void _UpdateMemberWithdrawSlots(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 tabId); - bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const; void _LogEvent(GuildEventLogTypes eventType, ObjectGuid playerGuid1, ObjectGuid playerGuid2 = ObjectGuid::Empty, uint8 newRank = 0); void _LogBankEvent(CharacterDatabaseTransaction trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index eeff0d3d6..31a5b5181 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -60,19 +60,9 @@ #include "WorldSession.h" #include "WorldSessionMgr.h" -class LoginQueryHolder : public CharacterDatabaseQueryHolder +LoginQueryHolder::LoginQueryHolder(uint32 accountId, ObjectGuid guid) : m_accountId(accountId), m_guid(guid) { -private: - uint32 m_accountId; - ObjectGuid m_guid; -public: - LoginQueryHolder(uint32 accountId, ObjectGuid guid) - : m_accountId(accountId), m_guid(guid) { } - - ObjectGuid GetGuid() const { return m_guid; } - uint32 GetAccountId() const { return m_accountId; } - bool Initialize(); -}; +} bool LoginQueryHolder::Initialize() { @@ -570,7 +560,12 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) newChar->SaveToDB(characterTransaction, true, false); createInfo->CharCount++; - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_REALM_CHARACTERS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); + stmt->SetData(0, GetAccountId()); + stmt->SetData(1, realm.Id.Realm); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_REALM_CHARACTERS); stmt->SetData(0, createInfo->CharCount); stmt->SetData(1, GetAccountId()); stmt->SetData(2, realm.Id.Realm); @@ -787,6 +782,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData) void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) { + m_playerLoading = true; ObjectGuid playerGuid = holder.GetGuid(); Player* pCurrChar = new Player(this); @@ -904,8 +900,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) CharacterDatabase.Execute(stmt); LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); - loginStmt->SetData(0, realm.Id.Realm); - loginStmt->SetData(1, GetAccountId()); + loginStmt->SetData(0, GetAccountId()); LoginDatabase.Execute(loginStmt); pCurrChar->SetInGameTime(GameTime::GetGameTimeMS().count()); @@ -950,6 +945,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) pCurrChar->CastSpell(pCurrChar, 20584, true, 0); // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) + pCurrChar->SetMovement(MOVE_WATER_WALK); } // Set FFA PvP for non GM in non-rest mode diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index f191dc05a..d7adcdc99 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -335,10 +335,15 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) msg.erase(end, msg.end()); } - // Validate hyperlinks - if (!ValidateHyperlinksAndMaybeKick(msg)) + // Skip validation for playerbots module + auto playerbotsHyperlink = msg.find("Hfound:") != std::string::npos; + if (!playerbotsHyperlink) { - return; + // Validate hyperlinks + if (!ValidateHyperlinksAndMaybeKick(msg)) + { + return; + } } } @@ -434,7 +439,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, group)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; ChatHandler::BuildChatPacket(data, ChatMsg(type), Language(lang), sender, nullptr, msg); @@ -448,10 +457,18 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) { if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, guild)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } + else + { + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg); + } } } break; @@ -462,7 +479,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) { if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, guild)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); guild->BroadcastToGuild(this, true, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } @@ -481,7 +502,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, group)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, Language(lang), sender, nullptr, msg); @@ -500,7 +525,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, group)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_LEADER, Language(lang), sender, nullptr, msg); @@ -514,7 +543,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, group)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); // In battleground, raid warning is sent only to players in battleground - code is ok WorldPacket data; @@ -530,7 +563,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, group)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND, Language(lang), sender, nullptr, msg); @@ -545,7 +582,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; if (!sScriptMgr->OnPlayerCanUseChat(GetPlayer(), type, lang, msg, group)) + { return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_BATTLEGROUND_LEADER, Language(lang), sender, nullptr, msg); @@ -568,7 +609,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) if (Channel* chn = cMgr->GetChannel(channel, sender)) { if (!sScriptMgr->OnPlayerCanUseChat(sender, type, lang, msg, chn)) + { return; + } + + sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn); chn->Say(sender->GetGUID(), msg.c_str(), lang); } @@ -597,7 +642,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } if (!sScriptMgr->OnPlayerCanUseChat(sender, type, lang, msg)) + { return; + } + + sScriptMgr->OnPlayerChat(sender, type, lang, msg); } break; } @@ -621,7 +670,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } if (!sScriptMgr->OnPlayerCanUseChat(sender, type, lang, msg)) + { return; + } + + sScriptMgr->OnPlayerChat(sender, type, lang, msg); break; } diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index 7ce587015..464a9e06c 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -482,6 +482,8 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData) break; } + sScriptMgr->OnPlayerbotCheckPetitionAccount(_player, found); + if (found) { WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8 + 8 + 4)); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 0ea47ff8a..452e540a7 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -54,10 +54,6 @@ Map::~Map() { // UnloadAll must be called before deleting the map - // Kill all scheduled events without executing them, since the map and its objects are being destroyed. - // This prevents events from running on invalid or deleted objects during map destruction. - Events.KillAllEvents(false); - sScriptMgr->OnDestroyMap(this); if (!m_scriptSchedule.empty()) @@ -451,7 +447,7 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) } } - Events.Update(t_diff); + _creatureRespawnScheduler.Update(t_diff); if (!t_diff) { @@ -1101,7 +1097,7 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl if (ground) *ground = ground_z; - LiquidData const& liquidData = const_cast(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, {}); + LiquidData const& liquidData = const_cast(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS); switch (liquidData.Status) { case LIQUID_MAP_ABOVE_WATER: @@ -1202,18 +1198,27 @@ static inline bool IsInWMOInterior(uint32 mogpFlags) bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const { + float vmap_z = z; + float dynamic_z = z; float check_z = z; VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); - VMAP::AreaAndLiquidData vdata; - VMAP::AreaAndLiquidData ddata; + uint32 vflags; + int32 vadtId; + int32 vrootId; + int32 vgroupId; + uint32 dflags; + int32 dadtId; + int32 drootId; + int32 dgroupId; + + bool hasVmapAreaInfo = vmgr->GetAreaInfo(GetId(), x, y, vmap_z, vflags, vadtId, vrootId, vgroupId); + bool hasDynamicAreaInfo = _dynamicTree.GetAreaInfo(x, y, dynamic_z, phaseMask, dflags, dadtId, drootId, dgroupId); + auto useVmap = [&]() { check_z = vmap_z; flags = vflags; adtId = vadtId; rootId = vrootId; groupId = vgroupId; }; + auto useDyn = [&]() { check_z = dynamic_z; flags = dflags; adtId = dadtId; rootId = drootId; groupId = dgroupId; }; - bool hasVmapAreaInfo = vmgr->GetAreaAndLiquidData(GetId(), x, y, z, {}, vdata) && vdata.areaInfo.has_value(); - bool hasDynamicAreaInfo = _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value(); - auto useVmap = [&] { check_z = vdata.floorZ; groupId = vdata.areaInfo->groupId; adtId = vdata.areaInfo->adtId; rootId = vdata.areaInfo->rootId; flags = vdata.areaInfo->mogpFlags; }; - auto useDyn = [&] { check_z = ddata.floorZ; groupId = ddata.areaInfo->groupId; adtId = ddata.areaInfo->adtId; rootId = ddata.areaInfo->rootId; flags = ddata.areaInfo->mogpFlags; }; if (hasVmapAreaInfo) { - if (hasDynamicAreaInfo && ddata.floorZ > vdata.floorZ) + if (hasDynamicAreaInfo && dynamic_z > vmap_z) useDyn(); else useVmap(); @@ -1294,30 +1299,32 @@ void Map::GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, flo zoneid = area->zone; } -LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, Optional ReqLiquidType) +LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) { LiquidData liquidData; - liquidData.Status = LIQUID_MAP_NO_WATER; VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); - VMAP::AreaAndLiquidData vmapData; + float liquid_level = INVALID_HEIGHT; + float ground_level = INVALID_HEIGHT; + uint32 liquid_type = 0; + uint32 mogpFlags = 0; bool useGridLiquid = true; - if (vmgr->GetAreaAndLiquidData(GetId(), x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo) + if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type, mogpFlags)) { - useGridLiquid = !vmapData.areaInfo || !IsInWMOInterior(vmapData.areaInfo->mogpFlags); - LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", vmapData.liquidInfo->level, vmapData.floorZ, vmapData.liquidInfo->type); + useGridLiquid = !IsInWMOInterior(mogpFlags); + LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", liquid_level, ground_level, liquid_type); // Check water level and ground level - if (vmapData.liquidInfo->level > vmapData.floorZ && G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE)) + if (liquid_level > ground_level && G3D::fuzzyGe(z, ground_level - GROUND_HEIGHT_TOLERANCE)) { // hardcoded in client like this - if (GetId() == MAP_OUTLAND && vmapData.liquidInfo->type == 2) - vmapData.liquidInfo->type = 15; + if (GetId() == MAP_OUTLAND && liquid_type == 2) + liquid_type = 15; uint32 liquidFlagType = 0; - if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(vmapData.liquidInfo->type)) + if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type)) liquidFlagType = liq->Type; - if (vmapData.liquidInfo->type && vmapData.liquidInfo->type < 21) + if (liquid_type && liquid_type < 21) { if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z))) { @@ -1331,19 +1338,19 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) { - vmapData.liquidInfo->type = overrideLiquid; + liquid_type = overrideLiquid; liquidFlagType = liq->Type; } } } - liquidData.Level = vmapData.liquidInfo->level; - liquidData.DepthLevel = vmapData.floorZ; - liquidData.Entry = vmapData.liquidInfo->type; + liquidData.Level = liquid_level; + liquidData.DepthLevel = ground_level; + liquidData.Entry = liquid_type; liquidData.Flags = 1 << liquidFlagType; } - float delta = vmapData.liquidInfo->level - z; + float delta = liquid_level - z; // Get position delta if (delta > collisionHeight) @@ -1362,7 +1369,7 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, { LiquidData const& map_data = gmap->GetLiquidData(x, y, z, collisionHeight, ReqLiquidType); // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: - if (map_data.Status != LIQUID_MAP_NO_WATER && (map_data.Level > vmapData.floorZ)) + if (map_data.Status != LIQUID_MAP_NO_WATER && (map_data.Level > ground_level)) { // hardcoded in client like this uint32 liquidEntry = map_data.Entry; @@ -1378,7 +1385,7 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, return liquidData; } -void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, Optional reqLiquidType) +void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType) { GridTerrainData* gmap = GetGridTerrainData(x, y); @@ -1593,7 +1600,7 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, float collisionHeight) const { - LiquidData const& liquidData = const_cast(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, {}); + LiquidData const& liquidData = const_cast(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, MAP_ALL_LIQUIDS); return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0; } @@ -1722,6 +1729,12 @@ void Map::SendObjectUpdates() WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) { + if (!sScriptMgr->OnPlayerbotCheckUpdatesToSend(iter->first)) + { + iter->second.Clear(); + continue; + } + iter->second.BuildPacket(packet); iter->first->SendDirectMessage(&packet); packet.clear(); // clean the string @@ -2751,13 +2764,13 @@ void Map::RemoveOldCorpses() void Map::ScheduleCreatureRespawn(ObjectGuid creatureGuid, Milliseconds respawnTimer, Position pos) { - Events.AddEventAtOffset([this, creatureGuid, pos]() + _creatureRespawnScheduler.Schedule(respawnTimer, [this, creatureGuid, pos](TaskContext) { if (Creature* creature = GetCreature(creatureGuid)) creature->Respawn(); else SummonCreature(creatureGuid.GetEntry(), pos); - }, respawnTimer); + }); } /// Send a packet to all players (or players selected team) in the zone (except self if mentioned) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 21226c54a..96f9cc32b 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -23,7 +23,6 @@ #include "DataMap.h" #include "Define.h" #include "DynamicTree.h" -#include "EventProcessor.h" #include "GameObjectModel.h" #include "GridDefines.h" #include "GridRefMgr.h" @@ -34,6 +33,7 @@ #include "PathGenerator.h" #include "Position.h" #include "SharedDefines.h" +#include "TaskScheduler.h" #include "Timer.h" #include "GridTerrainData.h" #include @@ -172,7 +172,7 @@ public: // currently unused for normal maps bool CanUnload(uint32 diff) { - if (!m_unloadTimer || Events.HasEvents()) + if (!m_unloadTimer) return false; if (m_unloadTimer <= diff) @@ -243,8 +243,8 @@ public: [[nodiscard]] float GetMinHeight(float x, float y) const; Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr); - void GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, Optional reqLiquidType = {}); - LiquidData const GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, Optional ReqLiquidType); + void GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS); + LiquidData const GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType); [[nodiscard]] bool GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const; [[nodiscard]] uint32 GetAreaId(uint32 phaseMask, float x, float y, float z) const; @@ -430,7 +430,7 @@ public: void UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone); [[nodiscard]] uint32 ApplyDynamicModeRespawnScaling(WorldObject const* obj, uint32 respawnDelay) const; - EventProcessor Events; + TaskScheduler _creatureRespawnScheduler; void ScheduleCreatureRespawn(ObjectGuid /*creatureGuid*/, Milliseconds /*respawnTimer*/, Position pos = Position()); diff --git a/src/server/game/Misc/GameGraveyard.cpp b/src/server/game/Misc/GameGraveyard.cpp index e497a9245..318632e21 100644 --- a/src/server/game/Misc/GameGraveyard.cpp +++ b/src/server/game/Misc/GameGraveyard.cpp @@ -119,6 +119,11 @@ GraveyardStruct const* Graveyard::GetClosestGraveyard(Player* player, TeamId tea uint32 areaId = 0; player->GetZoneAndAreaId(zoneId, areaId); + return GetClosestGraveyard(mapId, x, y, z, teamId, areaId, zoneId, player->getClass() == CLASS_DEATH_KNIGHT); +} + +GraveyardStruct const* Graveyard::GetClosestGraveyard(uint32 mapId, float x, float y, float z, TeamId teamId, uint32 areaId, uint32 zoneId, bool isDeathKnight) +{ if (!zoneId && !areaId) { if (z > -500) @@ -202,7 +207,7 @@ GraveyardStruct const* Graveyard::GetClosestGraveyard(Player* player, TeamId tea GRAVEYARD_ARCHERUS = 1405 }; - if (!player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_GRAVEYARD) && (graveyardLink.safeLocId == GRAVEYARD_EBON_HOLD || graveyardLink.safeLocId == GRAVEYARD_ARCHERUS)) + if (!isDeathKnight && (graveyardLink.safeLocId == GRAVEYARD_EBON_HOLD || graveyardLink.safeLocId == GRAVEYARD_ARCHERUS)) { continue; } diff --git a/src/server/game/Misc/GameGraveyard.h b/src/server/game/Misc/GameGraveyard.h index 1ba22d1f7..741dd0ea8 100644 --- a/src/server/game/Misc/GameGraveyard.h +++ b/src/server/game/Misc/GameGraveyard.h @@ -57,6 +57,7 @@ public: GraveyardStruct const* GetGraveyard(const std::string& name) const; GraveyardStruct const* GetDefaultGraveyard(TeamId teamId); GraveyardStruct const* GetClosestGraveyard(Player* player, TeamId teamId, bool nearCorpse = false); + GraveyardStruct const* GetClosestGraveyard(uint32 mapId, float x, float y, float z, TeamId teamId, uint32 areaId, uint32 zoneId, bool isDeathKnight); GraveyardData const* FindGraveyardData(uint32 id, uint32 zone); GraveyardContainer const& GetGraveyardData() const { return _graveyardStore; } bool AddGraveyardLink(uint32 id, uint32 zoneId, TeamId teamId, bool persist = true); diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 8e4f91c16..71d21d48a 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -923,6 +923,48 @@ void MotionMaster::MoveRotate(uint32 time, RotateDirection direction) Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE); } +#ifdef MOD_PLAYERBOTS +void MotionMaster::MoveKnockbackFromForPlayer(float srcX, float srcY, float speedXY, float speedZ) +{ + if (speedXY <= 0.1f) + return; + + Position dest = _owner->GetPosition(); + float moveTimeHalf = speedZ / Movement::gravity; + float dist = 2 * moveTimeHalf * speedXY; + float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ); + + // Use a mmap raycast to get a valid destination. + _owner->MovePositionToFirstCollision(dest, dist, _owner->GetRelativeAngle(srcX, srcY) + float(M_PI)); + + Movement::MoveSplineInit init(_owner); + init.MoveTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ()); + init.SetParabolic(max_height, 0); + init.SetOrientationFixed(true); + init.SetVelocity(speedXY); + Mutate(new EffectMovementGenerator(init, 0), MOTION_SLOT_CONTROLLED); +} + +// Similar to MovePoint except setting orientationInversed +void MotionMaster::MovePointBackwards(uint32 id, float x, float y, float z, bool generatePath, bool forceDestination, MovementSlot slot, float orientation /* = 0.0f*/) +{ + if (_owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) + return; + + if (_owner->IsPlayer()) + { + LOG_DEBUG("movement.motionmaster", "Player ({}) targeted point (Id: {} X: {} Y: {} Z: {})", _owner->GetGUID().ToString(), id, x, y, z); + Mutate(new PointMovementGenerator(id, x, y, z, FORCED_MOVEMENT_NONE, 0.0f, orientation, nullptr, generatePath, forceDestination, std::nullopt, ObjectGuid::Empty, true), slot); + } + else + { + LOG_DEBUG("movement.motionmaster", "Creature ({}) targeted point (ID: {} X: {} Y: {} Z: {})", _owner->GetGUID().ToString(), id, x, y, z); + Mutate(new PointMovementGenerator(id, x, y, z, FORCED_MOVEMENT_NONE, 0.0f, orientation, nullptr, generatePath, forceDestination, std::nullopt, ObjectGuid::Empty, true), slot); + } +} + +#endif + void MotionMaster::propagateSpeedChange() { /*Impl::container_type::iterator it = Impl::c.begin(); diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 4ac140260..e4b2d2c20 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -262,7 +262,10 @@ public: void MoveDistract(uint32 time); void MoveWaypoint(uint32 path_id, bool repeatable, PathSource pathSource = PathSource::WAYPOINT_MGR); void MoveRotate(uint32 time, RotateDirection direction); - +#ifdef MOD_PLAYERBOTS + void MoveKnockbackFromForPlayer(float srcX, float srcY, float speedXY, float speedZ); + void MovePointBackwards(uint32 id, float x, float y, float z, bool generatePath = true, bool forceDestination = true, MovementSlot slot = MOTION_SLOT_ACTIVE, float orientation = 0.0f); +#endif [[nodiscard]] MovementGeneratorType GetCurrentMovementGeneratorType() const; [[nodiscard]] MovementGeneratorType GetMotionSlotType(int slot) const; bool HasMovementGeneratorType(MovementGeneratorType type) const; diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp index 5ddbc2c45..4d606f461 100644 --- a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp @@ -211,8 +211,8 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con { bool buildShortcut = false; - auto liquidDataStart = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight(), {}); - auto liquidDataEnd = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight(), {}); + auto liquidDataStart = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS); + auto liquidDataEnd = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS); bool startUnderWaterEndInWater = liquidDataStart.Status == LIQUID_MAP_UNDER_WATER && (liquidDataEnd.Status & MAP_LIQUID_STATUS_IN_CONTACT) != 0; @@ -698,7 +698,7 @@ void PathGenerator::UpdateFilter() NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const { - LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), {}); + LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS); if (liquidData.Status == LIQUID_MAP_NO_WATER) return NAV_GROUND; diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 66ba79be5..526c92730 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -47,6 +47,10 @@ void PointMovementGenerator::DoInitialize(T* unit) i_recalculateSpeed = false; Movement::MoveSplineInit init(unit); + /// Added by mod-playerbots + if (_reverseOrientation) + init.SetOrientationInversed(); + /// End added if (m_precomputedPath.size() > 2) // pussywizard: for charge init.MovebyPath(m_precomputedPath); else if (_generatePath) @@ -216,14 +220,9 @@ template <> void PointMovementGenerator::MovementInform(Creature* unit if (Unit* summoner = unit->GetCharmerOrOwner()) { if (UnitAI* AI = summoner->GetAI()) + { AI->SummonMovementInform(unit, POINT_MOTION_TYPE, id); - } - else - { - if (TempSummon* tempSummon = unit->ToTempSummon()) - if (Unit* summoner = tempSummon->GetSummonerUnit()) - if (UnitAI* AI = summoner->GetAI()) - AI->SummonMovementInform(unit, POINT_MOTION_TYPE, id); + } } } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 7c13fb982..0239f1a72 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -276,14 +276,22 @@ void WaypointMovementGenerator::MovementInform(Creature* creature) if (Unit* owner = creature->GetCharmerOrOwner()) { if (UnitAI* AI = owner->GetAI()) + { AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode); + } } else { if (TempSummon* tempSummon = creature->ToTempSummon()) + { if (Unit* owner = tempSummon->GetSummonerUnit()) + { if (UnitAI* AI = owner->GetAI()) + { AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode); + } + } + } } } @@ -410,7 +418,6 @@ void FlightPathMovementGenerator::DoFinalize(Player* player) player->m_taxi.ClearTaxiDestinations(); player->Dismount(); player->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - player->UpdatePvPState(); // to account for cases such as flying into a PvP territory, as it does not flag on the way in if (player->m_taxi.empty()) { @@ -440,9 +447,6 @@ void FlightPathMovementGenerator::DoReset(Player* player) return; } - if (player->pvpInfo.EndTimer) - player->UpdatePvP(false, true); // PvP flag timer immediately ends when starting taxi - player->getHostileRefMgr().setOnlineOfflineState(false); player->AddUnitState(UNIT_STATE_IN_FLIGHT); player->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); diff --git a/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp b/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp index df84d2156..e2831a9d1 100644 --- a/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp @@ -19,6 +19,21 @@ #include "ScriptMgr.h" #include "ScriptMgrMacros.h" +bool ScriptMgr::OnDatabasesLoading() +{ + auto ret = IsValidBoolScript([&](DatabaseScript* script) + { + return !script->OnDatabasesLoading(); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + void ScriptMgr::OnAfterDatabasesLoaded(uint32 updateFlags) { CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_AFTER_DATABASES_LOADED, script->OnAfterDatabasesLoaded(updateFlags)); @@ -29,6 +44,46 @@ void ScriptMgr::OnAfterDatabaseLoadCreatureTemplates(std::vectorOnAfterDatabaseLoadCreatureTemplates(creatureTemplates)); } +void ScriptMgr::OnDatabasesKeepAlive() +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabasesKeepAlive(); + }); +} + +void ScriptMgr::OnDatabasesClosing() +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabasesClosing(); + }); +} + +void ScriptMgr::OnDatabaseWarnAboutSyncQueries(bool apply) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabaseWarnAboutSyncQueries(apply); + }); +} + +void ScriptMgr::OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabaseSelectIndexLogout(player, statementIndex, statementParam); + }); +} + +void ScriptMgr::OnDatabaseGetDBRevision(std::string& revision) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabaseGetDBRevision(revision); + }); +} + DatabaseScript::DatabaseScript(const char* name, std::vector enabledHooks) : ScriptObject(name, DATABASEHOOK_END) { diff --git a/src/server/game/Scripting/ScriptDefines/DatabaseScript.h b/src/server/game/Scripting/ScriptDefines/DatabaseScript.h index 708f0a986..21b55ee8b 100644 --- a/src/server/game/Scripting/ScriptDefines/DatabaseScript.h +++ b/src/server/game/Scripting/ScriptDefines/DatabaseScript.h @@ -52,6 +52,13 @@ public: */ virtual void OnAfterDatabaseLoadCreatureTemplates(std::vector /*creatureTemplates*/) { } + [[nodiscard]] virtual bool OnDatabasesLoading() { return true; } + virtual void OnDatabasesKeepAlive() { } + virtual void OnDatabasesClosing() { } + virtual void OnDatabaseWarnAboutSyncQueries(bool /*apply*/) { } + virtual void OnDatabaseSelectIndexLogout(Player* /*player*/, uint32& /*statementIndex*/, uint32& /*statementParam*/) { } + virtual void OnDatabaseGetDBRevision(std::string& /*revision*/) { } + }; #endif diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index 62439d284..3c7f4dd4f 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -169,11 +169,36 @@ void ScriptMgr::OnPlayerDuelEnd(Player* winner, Player* loser, DuelCompleteType CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_DUEL_END, script->OnPlayerDuelEnd(winner, loser, type)); } +void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg) +{ + CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_CHAT, script->OnPlayerChat(player, type, lang, msg)); +} + void ScriptMgr::OnPlayerBeforeSendChatMessage(Player* player, uint32& type, uint32& lang, std::string& msg) { CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_BEFORE_SEND_CHAT_MESSAGE, script->OnPlayerBeforeSendChatMessage(player, type, lang, msg)); } +void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* receiver) +{ + CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_CHAT_WITH_RECEIVER, script->OnPlayerChat(player, type, lang, msg, receiver)); +} + +void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) +{ + CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_CHAT_WITH_GROUP, script->OnPlayerChat(player, type, lang, msg, group)); +} + +void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) +{ + CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_CHAT_WITH_GUILD, script->OnPlayerChat(player, type, lang, msg, guild)); +} + +void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Channel* channel) +{ + CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_CHAT_WITH_CHANNEL, script->OnPlayerChat(player, type, lang, msg, channel)); +} + void ScriptMgr::OnPlayerEmote(Player* player, uint32 emote) { CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_EMOTE, script->OnPlayerEmote(player, emote)); @@ -194,11 +219,17 @@ void ScriptMgr::OnPlayerBeforeUpdate(Player* player, uint32 p_time) CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_BEFORE_UPDATE, script->OnPlayerBeforeUpdate(player, p_time)); } +void ScriptMgr::OnPlayerAfterUpdate(Player* player, uint32 p_time) +{ + CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_AFTER_UPDATE, script->OnPlayerAfterUpdate(player, p_time)); +} + void ScriptMgr::OnPlayerUpdate(Player* player, uint32 p_time) { CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_UPDATE, script->OnPlayerUpdate(player, p_time)); } + void ScriptMgr::OnPlayerLogin(Player* player) { CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_LOGIN, script->OnPlayerLogin(player)); diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.h b/src/server/game/Scripting/ScriptDefines/PlayerScript.h index 5ee56e7ac..71d6ffcca 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.h +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.h @@ -45,6 +45,7 @@ enum PlayerHook PLAYERHOOK_ON_AFTER_SPEC_SLOT_CHANGED, PLAYERHOOK_ON_BEFORE_UPDATE, PLAYERHOOK_ON_UPDATE, + PLAYERHOOK_ON_AFTER_UPDATE, PLAYERHOOK_ON_MONEY_CHANGED, PLAYERHOOK_ON_BEFORE_LOOT_MONEY, PLAYERHOOK_ON_GIVE_EXP, @@ -55,7 +56,12 @@ enum PlayerHook PLAYERHOOK_ON_DUEL_REQUEST, PLAYERHOOK_ON_DUEL_START, PLAYERHOOK_ON_DUEL_END, + PLAYERHOOK_ON_CHAT, PLAYERHOOK_ON_BEFORE_SEND_CHAT_MESSAGE, + PLAYERHOOK_ON_CHAT_WITH_RECEIVER, + PLAYERHOOK_ON_CHAT_WITH_GROUP, + PLAYERHOOK_ON_CHAT_WITH_GUILD, + PLAYERHOOK_ON_CHAT_WITH_CHANNEL, PLAYERHOOK_ON_EMOTE, PLAYERHOOK_ON_TEXT_EMOTE, PLAYERHOOK_ON_SPELL_CAST, @@ -263,6 +269,7 @@ public: // Called for player::update virtual void OnPlayerBeforeUpdate(Player* /*player*/, uint32 /*p_time*/) { } + virtual void OnPlayerAfterUpdate(Player* /*player*/, uint32 /*p_time*/) { } virtual void OnPlayerUpdate(Player* /*player*/, uint32 /*p_time*/) { } // Called when a player's money is modified (before the modification is done) @@ -299,8 +306,18 @@ public: virtual void OnPlayerDuelEnd(Player* /*winner*/, Player* /*loser*/, DuelCompleteType /*type*/) { } // The following methods are called when a player sends a chat message. + virtual void OnPlayerChat(Player* /*player*/, uint32 /*type*/, uint32 /*lang*/, std::string& /*msg*/) { } + virtual void OnPlayerBeforeSendChatMessage(Player* /*player*/, uint32& /*type*/, uint32& /*lang*/, std::string& /*msg*/) { } + virtual void OnPlayerChat(Player* /*player*/, uint32 /*type*/, uint32 /*lang*/, std::string& /*msg*/, Player* /*receiver*/) { } + + virtual void OnPlayerChat(Player* /*player*/, uint32 /*type*/, uint32 /*lang*/, std::string& /*msg*/, Group* /*group*/) { } + + virtual void OnPlayerChat(Player* /*player*/, uint32 /*type*/, uint32 /*lang*/, std::string& /*msg*/, Guild* /*guild*/) { } + + virtual void OnPlayerChat(Player* /*player*/, uint32 /*type*/, uint32 /*lang*/, std::string& /*msg*/, Channel* /*channel*/) { } + // Both of the below are called on emote opcodes. virtual void OnPlayerEmote(Player* /*player*/, uint32 /*emote*/) { } diff --git a/src/server/game/Scripting/ScriptDefines/PlayerbotsScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerbotsScript.cpp new file mode 100644 index 000000000..22379a1fb --- /dev/null +++ b/src/server/game/Scripting/ScriptDefines/PlayerbotsScript.cpp @@ -0,0 +1,105 @@ +/* + * 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 General Public License as published by + * the Free Software Foundation; either version 2 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 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 "ScriptMgr.h" +#include "ScriptMgrMacros.h" + +bool ScriptMgr::OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList) +{ + auto ret = IsValidBoolScript([&](PlayerbotScript* script) + { + return !script->OnPlayerbotCheckLFGQueue(guidsList); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + +void ScriptMgr::OnPlayerbotCheckKillTask(Player* player, Unit* victim) +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotCheckKillTask(player, victim); + }); +} + +void ScriptMgr::OnPlayerbotCheckPetitionAccount(Player* player, bool& found) +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotCheckPetitionAccount(player, found); + }); +} + +bool ScriptMgr::OnPlayerbotCheckUpdatesToSend(Player* player) +{ + auto ret = IsValidBoolScript([&](PlayerbotScript* script) + { + return !script->OnPlayerbotCheckUpdatesToSend(player); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + +void ScriptMgr::OnPlayerbotPacketSent(Player* player, WorldPacket const* packet) +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotPacketSent(player, packet); + }); +} + +void ScriptMgr::OnPlayerbotUpdate(uint32 diff) +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotUpdate(diff); + }); +} + +void ScriptMgr::OnPlayerbotUpdateSessions(Player* player) +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotUpdateSessions(player); + }); +} + +void ScriptMgr::OnPlayerbotLogout(Player* player) +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotLogout(player); + }); +} + +void ScriptMgr::OnPlayerbotLogoutBots() +{ + ExecuteScript([&](PlayerbotScript* script) + { + script->OnPlayerbotLogoutBots(); + }); +} diff --git a/src/server/game/Scripting/ScriptDefines/ServerScript.cpp b/src/server/game/Scripting/ScriptDefines/ServerScript.cpp index 9794127f0..2860141a8 100644 --- a/src/server/game/Scripting/ScriptDefines/ServerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/ServerScript.cpp @@ -43,6 +43,15 @@ void ScriptMgr::OnSocketClose(std::shared_ptr socket) CALL_ENABLED_HOOKS(ServerScript, SERVERHOOK_ON_SOCKET_CLOSE, script->OnSocketClose(socket)); } +void ScriptMgr::OnPacketReceived(WorldSession* session, WorldPacket const& packet) +{ + WorldPacket copy(packet); + ExecuteScript([&](ServerScript* script) + { + script->OnPacketReceived(session, copy); + }); +} + bool ScriptMgr::CanPacketSend(WorldSession* session, WorldPacket const& packet) { ASSERT(session); diff --git a/src/server/game/Scripting/ScriptDefines/ServerScript.h b/src/server/game/Scripting/ScriptDefines/ServerScript.h index 5f3a7787b..64b6762d2 100644 --- a/src/server/game/Scripting/ScriptDefines/ServerScript.h +++ b/src/server/game/Scripting/ScriptDefines/ServerScript.h @@ -70,6 +70,8 @@ public: * @return True if you want to continue receive the packet, false if you want to disallow receive the packet */ [[nodiscard]] virtual bool CanPacketReceive(WorldSession* /*session*/, WorldPacket& /*packet*/) { return true; } + + virtual void OnPacketReceived(WorldSession* /*session*/, WorldPacket const& /*packet*/) { } }; #endif diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 34ad17546..0d99f7fd0 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -58,6 +58,11 @@ ScriptMgr* ScriptMgr::instance() return &instance; } +PlayerbotScript::PlayerbotScript(const char* name) : ScriptObject(name) +{ + ScriptRegistry::AddScript(this); +} + void ScriptMgr::Initialize() { LOG_INFO("server.loading", "> Loading C++ scripts"); @@ -143,6 +148,7 @@ void ScriptMgr::Unload() SCR_CLEAR(); SCR_CLEAR(); SCR_CLEAR(); + SCR_CLEAR(); SCR_CLEAR(); SCR_CLEAR(); SCR_CLEAR(); @@ -227,6 +233,7 @@ void ScriptMgr::CheckIfScriptsInDatabaseExist() !ScriptRegistry::GetScriptById(sid) && !ScriptRegistry::GetScriptById(sid) && !ScriptRegistry::GetScriptById(sid) && + !ScriptRegistry::GetScriptById(sid) && !ScriptRegistry::GetScriptById(sid)) { LOG_ERROR("sql.sql", "Script named '{}' is assigned in the database, but has no code!", scriptName); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 0dadd18f6..392d7d5fc 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -105,7 +105,26 @@ namespace Acore::ChatCommands */ -// Manages registration, loading, and execution of scripts. +class PlayerbotScript : public ScriptObject +{ +protected: + + PlayerbotScript(const char* name); + +public: + bool IsDatabaseBound() const { return false; } + + [[nodiscard]] virtual bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& /*guidsList*/) { return true; } + virtual void OnPlayerbotCheckKillTask(Player* /*player*/, Unit* /*victim*/) { } + virtual void OnPlayerbotCheckPetitionAccount(Player* /*player*/, bool& /*found*/) { } + [[nodiscard]] virtual bool OnPlayerbotCheckUpdatesToSend(Player* /*player*/) { return true; } + virtual void OnPlayerbotPacketSent(Player* /*player*/, WorldPacket const* /*packet*/) { } + virtual void OnPlayerbotUpdate(uint32 /*diff*/) { } + virtual void OnPlayerbotUpdateSessions(Player* /*player*/) { } + virtual void OnPlayerbotLogout(Player* /*player*/) { } + virtual void OnPlayerbotLogoutBots() { } +}; + class ScriptMgr { friend class ScriptObject; @@ -158,6 +177,7 @@ public: /* ServerScript */ void OnSocketOpen(std::shared_ptr socket); void OnSocketClose(std::shared_ptr socket); bool CanPacketReceive(WorldSession* session, WorldPacket const& packet); + void OnPacketReceived(WorldSession* session, WorldPacket const& packet); bool CanPacketSend(WorldSession* session, WorldPacket const& packet); public: /* WorldScript */ @@ -298,6 +318,7 @@ public: /* PlayerScript */ void OnPlayerReleasedGhost(Player* player); void OnPlayerSendInitialPacketsBeforeAddToMap(Player* player, WorldPacket& data); void OnPlayerBeforeUpdate(Player* player, uint32 p_time); + void OnPlayerAfterUpdate(Player* player, uint32 diff); void OnPlayerUpdate(Player* player, uint32 p_time); void OnPlayerPVPKill(Player* killer, Player* killed); void OnPlayerPVPFlagChange(Player* player, bool state); @@ -319,7 +340,12 @@ public: /* PlayerScript */ void OnPlayerDuelRequest(Player* target, Player* challenger); void OnPlayerDuelStart(Player* player1, Player* player2); void OnPlayerDuelEnd(Player* winner, Player* loser, DuelCompleteType type); + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg); void OnPlayerBeforeSendChatMessage(Player* player, uint32& type, uint32& lang, std::string& msg); + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* receiver); + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group); + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild); + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Channel* channel); void OnPlayerEmote(Player* player, uint32 emote); void OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, ObjectGuid guid); void OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck); @@ -679,8 +705,14 @@ public: /* CommandSC */ public: /* DatabaseScript */ + bool OnDatabasesLoading(); void OnAfterDatabasesLoaded(uint32 updateFlags); void OnAfterDatabaseLoadCreatureTemplates(std::vector creatureTemplateStore); + void OnDatabasesKeepAlive(); + void OnDatabasesClosing(); + void OnDatabaseWarnAboutSyncQueries(bool apply); + void OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam); + void OnDatabaseGetDBRevision(std::string& revision); public: /* WorldObjectScript */ @@ -698,6 +730,18 @@ public: /* LootScript */ void OnLootMoney(Player* player, uint32 gold); +public: /* PlayerbotScript */ + + bool OnPlayerbotCheckLFGQueue(lfg::Lfg5Guids const& guidsList); + void OnPlayerbotCheckKillTask(Player* player, Unit* victim); + void OnPlayerbotCheckPetitionAccount(Player* player, bool& found); + bool OnPlayerbotCheckUpdatesToSend(Player* player); + void OnPlayerbotPacketSent(Player* player, WorldPacket const* packet); + void OnPlayerbotUpdate(uint32 diff); + void OnPlayerbotUpdateSessions(Player* player); + void OnPlayerbotLogout(Player* player); + void OnPlayerbotLogoutBots(); + public: /* TicketScript */ void OnTicketCreate(GmTicket* ticket); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 254328b80..8a212f546 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -105,7 +105,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) /// WorldSession constructor WorldSession::WorldSession(uint32 id, std::string&& name, uint32 accountFlags, std::shared_ptr sock, AccountTypes sec, uint8 expansion, - time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, bool skipQueue, uint32 TotalTime) : + time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, bool skipQueue, uint32 TotalTime, bool isBot) : m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -137,7 +137,8 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 accountFlags, s _timeSyncClockDeltaQueue(6), _timeSyncClockDelta(0), _pendingTimeSyncRequests(), - _orderCounter(0) + _orderCounter(0), + _isBot(isBot) { memset(m_Tutorials, 0, sizeof(m_Tutorials)); @@ -153,6 +154,10 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 accountFlags, s ResetTimeOutTime(false); LoginDatabase.Execute("UPDATE account SET online = 1 WHERE id = {};", GetAccountId()); // One-time query } + else if (isBot) + { + m_Address = "bot"; + } } /// WorldSession destructor @@ -251,6 +256,14 @@ ObjectGuid::LowType WorldSession::GetGuidLow() const /// Send a packet to the client void WorldSession::SendPacket(WorldPacket const* packet) { + if (packet->GetOpcode() == NULL_OPCODE) + { + LOG_ERROR("network.opcode", "{} send NULL_OPCODE", GetPlayerInfo()); + return; + } + + sScriptMgr->OnPlayerbotPacketSent(GetPlayer(), packet); + if (!m_Socket) return; @@ -401,6 +414,9 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) opHandle->Call(this, *packet); LogUnprocessedTail(packet); +#ifdef MOD_PLAYERBOTS + sScriptMgr->OnPacketReceived(this, *packet); +#endif } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer @@ -419,6 +435,9 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) opHandle->Call(this, *packet); LogUnprocessedTail(packet); +#ifdef MOD_PLAYERBOTS + sScriptMgr->OnPacketReceived(this, *packet); +#endif } break; case STATUS_TRANSFER: @@ -429,6 +448,9 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) opHandle->Call(this, *packet); LogUnprocessedTail(packet); +#ifdef MOD_PLAYERBOTS + sScriptMgr->OnPacketReceived(this, *packet); +#endif } break; case STATUS_AUTHED: @@ -445,6 +467,9 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) opHandle->Call(this, *packet); LogUnprocessedTail(packet); +#ifdef MOD_PLAYERBOTS + sScriptMgr->OnPacketReceived(this, *packet); +#endif break; case STATUS_NEVER: LOG_ERROR("network.opcode", "Received not allowed opcode {} from {}", @@ -533,6 +558,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) //logout procedure should happen only in World::UpdateSessions() method!!! if (updater.ProcessUnsafe()) { + sScriptMgr->OnPlayerbotUpdateSessions(GetPlayer()); + if (m_Socket && m_Socket->IsOpen() && _warden) { _warden->Update(diff); @@ -625,6 +652,8 @@ void WorldSession::LogoutPlayer(bool save) if (ObjectGuid lguid = _player->GetLootGUID()) DoLootRelease(lguid); + sScriptMgr->OnPlayerbotLogout(_player); + ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) @@ -757,6 +786,10 @@ void WorldSession::LogoutPlayer(bool save) LOG_INFO("entities.player", "Account: {} (IP: {}) Logout Character:[{}] ({}) Level: {}", GetAccountId(), GetRemoteAddress(), _player->GetName(), _player->GetGUID().ToString(), _player->GetLevel()); + uint32 statementIndex = CHAR_UPD_ACCOUNT_ONLINE; + uint32 statementParam = GetAccountId(); + sScriptMgr->OnDatabaseSelectIndexLogout(_player, statementIndex, statementParam); + //! Remove the player from the world // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map @@ -776,8 +809,8 @@ void WorldSession::LogoutPlayer(bool save) LOG_DEBUG("network", "SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); //! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE); - stmt->SetData(0, GetAccountId()); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CharacterDatabaseStatements(statementIndex)); + stmt->SetData(0, statementParam); CharacterDatabase.Execute(stmt); } @@ -1516,3 +1549,8 @@ void WorldSession::SetPacketLogging(bool state) if (m_Socket) m_Socket->SetPacketLogging(state); } + +LockedQueue& WorldSession::GetPacketQueue() +{ + return _recvQueue; +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 6a1c554ca..283a301b2 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -29,6 +29,7 @@ #include "Common.h" #include "DatabaseEnv.h" #include "GossipDef.h" +#include "QueryHolder.h" #include "Packet.h" #include "SharedDefines.h" #include "World.h" @@ -40,7 +41,6 @@ class Creature; class GameObject; class InstanceSave; class Item; -class LoginQueryHolder; class LoadPetFromDBQueryHolder; class Object; class Pet; @@ -270,6 +270,20 @@ enum CharterTypes ARENA_TEAM_CHARTER_5v5_TYPE = 5 }; +class LoginQueryHolder : public CharacterDatabaseQueryHolder +{ + private: + uint32 m_accountId; + ObjectGuid m_guid; + + public: + LoginQueryHolder(uint32 accountId, ObjectGuid guid); + + ObjectGuid GetGuid() const { return m_guid; } + uint32 GetAccountId() const { return m_accountId; } + bool Initialize(); +}; + //class to deal with packet processing //allows to determine if next packet is safe to be processed class PacketFilter @@ -314,6 +328,11 @@ class CharacterCreateInfo friend class WorldSession; friend class Player; +public: + CharacterCreateInfo(std::string const name = "", uint8 _race = 0, uint8 _class = 0, uint8 gender = 0, uint8 skin = 0, uint8 face = 0, + uint8 hairStyle = 0, uint8 hairColor = 0, uint8 facialHair = 0) + : Name(name), Race(_race), Class(_class), Gender(gender), Skin(skin), Face(face), HairStyle(hairStyle), HairColor(hairColor), FacialHair(facialHair) { } + protected: /// User specified variables std::string Name; @@ -374,7 +393,7 @@ struct PacketCounter class WorldSession { public: - WorldSession(uint32 id, std::string&& name, uint32 accountFlags, std::shared_ptr sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, bool skipQueue, uint32 TotalTime); + WorldSession(uint32 id, std::string&& name, uint32 accountFlags, std::shared_ptr sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter, bool skipQueue, uint32 TotalTime, bool is_bot = false); ~WorldSession(); uint32 GetAccountFlags() const { return _accountFlags; } @@ -1132,6 +1151,8 @@ public: // opcodes handlers void SetKicked(bool val) { _kicked = val; } bool IsSocketClosed() const; + void SetAddress(std::string const& address) { m_Address = address; } + /* * CALLBACKS */ @@ -1145,6 +1166,13 @@ public: // opcodes handlers void SetPacketLogging(bool state); + LockedQueue& GetPacketQueue(); + + [[nodiscard]] bool IsBot() const + { + return _isBot; + } + private: void ProcessQueryCallbacks(); @@ -1257,6 +1285,8 @@ private: uint32 _orderCounter; + bool _isBot; + WorldSession(WorldSession const& right) = delete; WorldSession& operator=(WorldSession const& right) = delete; }; diff --git a/src/server/game/Server/WorldSessionMgr.cpp b/src/server/game/Server/WorldSessionMgr.cpp index b43099669..91256db9b 100644 --- a/src/server/game/Server/WorldSessionMgr.cpp +++ b/src/server/game/Server/WorldSessionMgr.cpp @@ -20,6 +20,7 @@ #include "GameTime.h" #include "Metric.h" #include "Player.h" +#include "ScriptMgr.h" #include "World.h" #include "WorldSession.h" #include "WorldSessionMgr.h" @@ -190,6 +191,10 @@ void WorldSessionMgr::KickAll() // pussywizard: kick offline sessions for (SessionMap::const_iterator itr = _offlineSessions.begin(); itr != _offlineSessions.end(); ++itr) itr->second->KickPlayer("KickAll offline sessions"); + +#ifdef MOD_PLAYERBOTS + sScriptMgr->OnPlayerbotLogoutBots(); +#endif } /// Kick (and save) all players with security level less `sec` diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 608b9614b..2d7a658d1 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1377,7 +1377,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici float ground = m_caster->GetMapHeight(x, y, z, true); float liquidLevel = VMAP_INVALID_HEIGHT_VALUE; - LiquidData const& liquidData = m_caster->GetMap()->GetLiquidData(m_caster->GetPhaseMask(), x, y, z, m_caster->GetCollisionHeight(), {}); + LiquidData const& liquidData = m_caster->GetMap()->GetLiquidData(m_caster->GetPhaseMask(), x, y, z, m_caster->GetCollisionHeight(), MAP_ALL_LIQUIDS); if (liquidData.Status) liquidLevel = liquidData.Level; diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index 03e70e55c..dc6c60681 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -22,6 +22,7 @@ #include "Common.h" #include "Duration.h" #include "ObjectGuid.h" +#include "QueryHolder.h" #include "SharedDefines.h" #include "WorldConfig.h" #include @@ -104,12 +105,16 @@ public: [[nodiscard]] virtual LocaleConstant GetAvailableDbcLocale(LocaleConstant locale) const = 0; virtual void LoadDBVersion() = 0; [[nodiscard]] virtual char const* GetDBVersion() const = 0; +#ifdef MOD_PLAYERBOTS + [[nodiscard]] virtual char const* GetPlayerbotsDBRevision() const = 0; +#endif virtual void UpdateAreaDependentAuras() = 0; [[nodiscard]] virtual uint32 GetCleaningFlags() const = 0; virtual void SetCleaningFlags(uint32 flags) = 0; virtual void ResetEventSeasonalQuests(uint16 event_id) = 0; [[nodiscard]] virtual std::string const& GetRealmName() const = 0; virtual void SetRealmName(std::string name) = 0; + virtual SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback) = 0; }; #endif //AZEROTHCORE_IWORLD_H diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index e1de134a2..d072bd56f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -67,6 +67,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "OutdoorPvPMgr.h" +#include "QueryHolder.h" #include "PetitionMgr.h" #include "Player.h" #include "PlayerDump.h" @@ -1171,6 +1172,8 @@ void World::Update(uint32 diff) ResetGuildCap(); } + sScriptMgr->OnPlayerbotUpdate(diff); + { // pussywizard: handle expired auctions, auctions expired when realm was offline are also handled here (not during loading when many required things aren't loaded yet) METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update expired auctions")); @@ -1290,6 +1293,7 @@ void World::Update(uint32 diff) CharacterDatabase.KeepAlive(); LoginDatabase.KeepAlive(); WorldDatabase.KeepAlive(); + sScriptMgr->OnDatabasesKeepAlive(); } { @@ -1456,6 +1460,7 @@ void World::_UpdateGameTime() void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode, std::string const& reason) { // ignore if server shutdown at next tick + if (IsStopped()) return; @@ -1803,6 +1808,12 @@ void World::UpdateAreaDependentAuras() void World::ProcessQueryCallbacks() { _queryProcessor.ProcessReadyCallbacks(); + _queryHolderProcessor.ProcessReadyCallbacks(); +} + +SQLQueryHolderCallback& World::AddQueryHolderCallback(SQLQueryHolderCallback&& callback) +{ + return _queryHolderProcessor.AddCallback(std::move(callback)); } bool World::IsPvPRealm() const diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 942665b4d..f42004e30 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -229,6 +229,9 @@ public: // used World DB version void LoadDBVersion() override; [[nodiscard]] char const* GetDBVersion() const override { return _dbVersion.c_str(); } +#ifdef MOD_PLAYERBOTS + [[nodiscard]] char const* GetPlayerbotsDBRevision() const override { return m_PlayerbotsDBRevision.c_str(); } +#endif void UpdateAreaDependentAuras() override; @@ -256,6 +259,9 @@ protected: void ResetRandomBG(); void CalendarDeleteOldEvents(); void ResetGuildCap(); + + SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback) override; + private: WorldConfig _worldConfig; @@ -300,9 +306,13 @@ private: // used versions std::string _dbVersion; uint32 _dbClientCacheVersion; +#ifdef MOD_PLAYERBOTS + std::string m_PlayerbotsDBRevision; +#endif void ProcessQueryCallbacks(); QueryCallbackProcessor _queryProcessor; + AsyncCallbackProcessor _queryHolderProcessor; /** * @brief Executed when a World Session is being finalized. Be it from a normal login or via queue popping. diff --git a/src/server/scripts/Commands/cs_cheat.cpp b/src/server/scripts/Commands/cs_cheat.cpp index 84d22411e..bbfedeceb 100644 --- a/src/server/scripts/Commands/cs_cheat.cpp +++ b/src/server/scripts/Commands/cs_cheat.cpp @@ -156,13 +156,13 @@ public: if (enable) { handler->GetSession()->GetPlayer()->SetCommandStatusOn(CHEAT_WATERWALK); - handler->GetSession()->GetPlayer()->SetWaterWalking(true); // ON + handler->GetSession()->GetPlayer()->SetMovement(MOVE_WATER_WALK); // ON handler->SendSysMessage("Waterwalking is ON. You can walk on water."); } else { handler->GetSession()->GetPlayer()->SetCommandStatusOff(CHEAT_WATERWALK); - handler->GetSession()->GetPlayer()->SetWaterWalking(false); // OFF + handler->GetSession()->GetPlayer()->SetMovement(MOVE_LAND_WALK); // OFF handler->SendSysMessage("Waterwalking is OFF. You can't walk on water."); } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 80201c969..4a6deb50f 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1949,7 +1949,7 @@ public: // the max level of the new profession. uint16 max = maxPureSkill ? *maxPureSkill : targetHasSkill ? target->GetPureMaxSkillValue(skillID) : uint16(level); - if (level <= 0 || level > max || max <= 0) + if (level < 0 || level > max || max < 0) { return false; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 66c50537e..e0adab854 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -219,6 +219,7 @@ public: { ObjectGuid::LowType guid = sObjectMgr->GenerateCreatureSpawnId(); CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid); + data.spawnId = guid; data.id1 = id; data.phaseMask = chr->GetPhaseMaskForSpawn(); data.posX = chr->GetTransOffsetX(); diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 98bfbbac3..63815aeec 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -213,6 +213,10 @@ public: handler->PSendSysMessage("Default DBC locale: {}.\nAll available DBC locales: {}", localeNames[defaultLocale], availableLocales); handler->PSendSysMessage("Using World DB: {}", sWorld->GetDBVersion()); +#ifdef MOD_PLAYERBOTS + handler->PSendSysMessage("Using Playerbots DB Revision: {}", sWorld->GetPlayerbotsDBRevision()); +#endif + std::string lldb = "No updates found!"; if (QueryResult resL = LoginDatabase.Query("SELECT name FROM updates ORDER BY name DESC LIMIT 1")) @@ -240,6 +244,10 @@ public: handler->PSendSysMessage("LoginDatabase queue size: {}", LoginDatabase.QueueSize()); handler->PSendSysMessage("CharacterDatabase queue size: {}", CharacterDatabase.QueueSize()); handler->PSendSysMessage("WorldDatabase queue size: {}", WorldDatabase.QueueSize()); +#ifdef MOD_PLAYERBOTS + handler->PSendSysMessage("PlayerbotsDatabase queue size: {}", PlayerbotsDatabase.QueueSize()); +#endif + if (Acore::Module::GetEnableModulesList().empty()) handler->PSendSysMessage("No modules are enabled"); diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp index 44a6b1182..1017c1ac2 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp @@ -37,7 +37,15 @@ enum Misc NPC_DRAKKARI_SCYTHECLAW = 26628, NPC_DRAKKARI_GUTRIPPER = 26641, - SAY_CLAW_EMOTE = 0 + SAY_CLAW_EMOTE = 0, + + EVENT_SPELL_BELLOWING_ROAR = 1, + EVENT_SPELL_GRIEVOUS_BITE = 2, + EVENT_SPELL_MANGLING_SLASH = 3, + EVENT_SPELL_FEARSOME_ROAR = 4, + EVENT_SPELL_PIERCING_SLASH = 5, + EVENT_SPELL_RAPTOR_CALL = 6, + EVENT_MENACING_CLAW = 7 }; class boss_dred : public CreatureScript @@ -52,52 +60,14 @@ public: struct boss_dredAI : public BossAI { - boss_dredAI(Creature* creature) : BossAI(creature, DATA_DRED) { } + boss_dredAI(Creature* creature) : BossAI(creature, DATA_DRED) + { + } void Reset() override { BossAI::Reset(); _raptorCount = 0; - - ScheduleHealthCheckEvent({ 67, 34 }, [&] { - DoCastAOE(SPELL_BELLOWING_ROAR); - }, false); - } - - void ScheduleTasks() override - { - ScheduleTimedEvent(20s, [&] { - DoCastVictim(SPELL_GRIEVOUS_BITE); - }, 20s); - - ScheduleTimedEvent(18s + 500ms, [&] { - DoCastVictim(SPELL_MANGLING_SLASH); - }, 20s); - - ScheduleTimedEvent(10s, 20s, [&] { - DoCastAOE(SPELL_FEARSOME_ROAR); - }, 17s); - - ScheduleTimedEvent(17s, [&] { - DoCastVictim(SPELL_PIERCING_SLASH); - }, 20s); - - if (IsHeroic()) - { - ScheduleTimedEvent(16s, [&] { - DoCastSelf(SPELL_RAPTOR_CALL); - }, 30s); - - ScheduleTimedEvent(21s, [&] { - Talk(SAY_CLAW_EMOTE); - me->setAttackTimer(BASE_ATTACK, 2000); - me->AttackerStateUpdate(me->GetVictim()); - if (me->GetVictim()) - me->AttackerStateUpdate(me->GetVictim()); - if (me->GetVictim()) - me->AttackerStateUpdate(me->GetVictim()); - }, 20s); - } } uint32 GetData(uint32 data) const override @@ -117,6 +87,67 @@ public: { BossAI::JustEngagedWith(who); _raptorCount = 0; + + events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 33s); + events.ScheduleEvent(EVENT_SPELL_GRIEVOUS_BITE, 20s); + events.ScheduleEvent(EVENT_SPELL_MANGLING_SLASH, 18s + 500ms); + events.ScheduleEvent(EVENT_SPELL_FEARSOME_ROAR, 10s, 20s); + events.ScheduleEvent(EVENT_SPELL_PIERCING_SLASH, 17s); + if (IsHeroic()) + { + events.ScheduleEvent(EVENT_MENACING_CLAW, 21s); + events.ScheduleEvent(EVENT_SPELL_RAPTOR_CALL, 20s, 25s); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SPELL_BELLOWING_ROAR: + me->CastSpell(me, SPELL_BELLOWING_ROAR, false); + events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 40s); + break; + case EVENT_SPELL_GRIEVOUS_BITE: + me->CastSpell(me->GetVictim(), SPELL_GRIEVOUS_BITE, false); + events.ScheduleEvent(EVENT_SPELL_GRIEVOUS_BITE, 20s); + break; + case EVENT_SPELL_MANGLING_SLASH: + me->CastSpell(me->GetVictim(), SPELL_MANGLING_SLASH, false); + events.ScheduleEvent(EVENT_SPELL_MANGLING_SLASH, 20s); + break; + case EVENT_SPELL_FEARSOME_ROAR: + me->CastSpell(me, SPELL_FEARSOME_ROAR, false); + events.ScheduleEvent(EVENT_SPELL_FEARSOME_ROAR, 17s); + break; + case EVENT_SPELL_PIERCING_SLASH: + me->CastSpell(me->GetVictim(), SPELL_PIERCING_SLASH, false); + events.ScheduleEvent(EVENT_SPELL_PIERCING_SLASH, 20s); + break; + case EVENT_SPELL_RAPTOR_CALL: + me->CastSpell(me, SPELL_RAPTOR_CALL, false); + events.ScheduleEvent(EVENT_SPELL_RAPTOR_CALL, 20s); + break; + case EVENT_MENACING_CLAW: + Talk(SAY_CLAW_EMOTE); + me->setAttackTimer(BASE_ATTACK, 2000); + me->AttackerStateUpdate(me->GetVictim()); + if (me->GetVictim()) + me->AttackerStateUpdate(me->GetVictim()); + if (me->GetVictim()) + me->AttackerStateUpdate(me->GetVictim()); + events.ScheduleEvent(EVENT_MENACING_CLAW, 20s); + break; + } + + DoMeleeAttackIfReady(); } private: @@ -150,23 +181,7 @@ class spell_dred_raptor_call : public SpellScript void HandleDummy(SpellEffIndex /*effIndex*/) { - std::list raptors; - GetCaster()->GetCreatureListWithEntryInGrid(raptors, { NPC_DRAKKARI_SCYTHECLAW, NPC_DRAKKARI_GUTRIPPER }, 100.0f); - - raptors.remove_if([](Creature* raptor) - { - return !raptor->IsAlive() || raptor->IsInCombat(); - }); - - if (raptors.empty()) - return; - - Creature* raptor = Acore::Containers::SelectRandomContainerElement(raptors); - if (!raptor) - return; - - if (GetCaster()->GetVictim()) - raptor->AI()->AttackStart(GetCaster()->GetVictim()); + GetCaster()->SummonCreature(RAND(NPC_DRAKKARI_GUTRIPPER, NPC_DRAKKARI_SCYTHECLAW), -522.02f, -718.89f, 30.26f, 2.41f); } void Register() override @@ -178,14 +193,16 @@ class spell_dred_raptor_call : public SpellScript class achievement_better_off_dred : public AchievementCriteriaScript { public: - achievement_better_off_dred() : AchievementCriteriaScript("achievement_better_off_dred") { } + achievement_better_off_dred() : AchievementCriteriaScript("achievement_better_off_dred") + { + } bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override { if (!target) return false; - return target->GetAI()->GetData(target->GetEntry()) >= 6; + return target->GetAI()->GetData(target->GetEntry()); } }; diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp index 36f8b555c..692888edf 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp @@ -47,7 +47,7 @@ enum Spells SPELL_COPY_OF_SUMMON_MINIONS = 59933, SPELL_BLIZZARD = 49034, SPELL_FROSTBOLT = 49037, - SPELL_WRATH_OF_MISERY = 50089 + SPELL_TOUCH_OF_MISERY = 50090 }; enum Misc @@ -56,7 +56,14 @@ enum Misc NPC_CRYSTAL_HANDLER = 26627, NPC_SUMMON_CRYSTAL_HANDLER_TARGET = 27583, - EVENT_KILL_TALK = 1, + EVENT_SUMMON_FETID_TROLL = 1, + EVENT_SUMMON_SHADOWCASTER = 2, + EVENT_SUMMON_HULKING_CORPSE = 3, + EVENT_SUMMON_CRYSTAL_HANDLER = 4, + EVENT_CAST_OFFENSIVE_SPELL = 5, + EVENT_KILL_TALK = 6, + EVENT_CHECK_PHASE = 7, + EVENT_SPELL_SUMMON_MINIONS = 8, ROOM_RIGHT = 0, ROOM_LEFT = 1, @@ -70,215 +77,198 @@ std::unordered_map> const npcSummon = { ROOM_STAIRS, { NPC_CRYSTAL_CHANNEL_TARGET, { -378.40f, -813.13f, 59.74f, 0.0f } } }, }; -// 26631 -struct boss_novos : public BossAI +class boss_novos : public CreatureScript { - boss_novos(Creature* creature) : BossAI(creature, DATA_NOVOS) { } +public: + boss_novos() : CreatureScript("boss_novos") { } - void Reset() override + struct boss_novosAI : public BossAI { - BossAI::Reset(); - instance->SetBossState(DATA_NOVOS_CRYSTALS, IN_PROGRESS); - instance->SetBossState(DATA_NOVOS_CRYSTALS, NOT_STARTED); - _crystalCounter = 0; - _summonTargetRightGUID.Clear(); - _summonTargetLeftGUID.Clear(); - _stage = 0; + boss_novosAI(Creature* creature) : BossAI(creature, DATA_NOVOS) + { + } - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + void Reset() override + { + BossAI::Reset(); + instance->SetBossState(DATA_NOVOS_CRYSTALS, IN_PROGRESS); + instance->SetBossState(DATA_NOVOS_CRYSTALS, NOT_STARTED); + _crystalCounter = 0; + _summonTargetRightGUID.Clear(); + _summonTargetLeftGUID.Clear(); + _stage = 0; - _achievement = true; - } + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - uint32 GetData(uint32 data) const override - { - if (data == me->GetEntry()) - return uint32(_achievement); - return 0; - } + _achievement = true; + } - void SetData(uint32 type, uint32) override - { - if (type == me->GetEntry()) - _achievement = false; - } + uint32 GetData(uint32 data) const override + { + if (data == me->GetEntry()) + return uint32(_achievement); + return 0; + } - void MoveInLineOfSight(Unit* /*who*/) override { } + void SetData(uint32 type, uint32) override + { + if (type == me->GetEntry()) + _achievement = false; + } - void JustEngagedWith(Unit* who) override - { - Talk(SAY_AGGRO); - BossAI::JustEngagedWith(who); - scheduler.ClearValidator(); + void MoveInLineOfSight(Unit* /*who*/) override { } - ScheduleTimedEvent(3s, [&] { - if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) - trigger->CastSpell(trigger, SPELL_SUMMON_FETID_TROLL_CORPSE, true, nullptr, nullptr, me->GetGUID()); - }, 3s); + void JustEngagedWith(Unit* who) override + { + Talk(SAY_AGGRO); + BossAI::JustEngagedWith(who); - ScheduleTimedEvent(9s, [&] { - if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) - trigger->CastSpell(trigger, SPELL_SUMMON_RISEN_SHADOWCASTER, true, nullptr, nullptr, me->GetGUID()); - }, 10s); + events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s); + events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 9s); + events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s); + events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s); + events.ScheduleEvent(EVENT_CHECK_PHASE, 80s); - ScheduleTimedEvent(30s, [&] { - if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) - trigger->CastSpell(trigger, SPELL_SUMMON_HULKING_CORPSE, true, nullptr, nullptr, me->GetGUID()); - }, 30s); + me->CastSpell(me, SPELL_ARCANE_BLAST, true); + me->CastSpell(me, SPELL_ARCANE_FIELD, true); + me->CastSpell(me, SPELL_DESPAWN_CRYSTAL_HANDLER, true); - scheduler.Schedule(70s, [this](TaskContext context) { - if (me->HasAura(SPELL_BEAM_CHANNEL)) + for (auto& itr : npcSummon) { - context.Repeat(2s); - return; + uint32 summonEntry; + Position summonPos; + std::tie(summonEntry, summonPos) = itr.second; + if (Creature* creature = me->SummonCreature(summonEntry, summonPos)) + switch (itr.first) + { + case ROOM_LEFT: + _summonTargetLeftGUID = creature->GetGUID(); + break; + case ROOM_RIGHT: + _summonTargetRightGUID = creature->GetGUID(); + break; + } } - scheduler.CancelAll(); + me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); + me->RemoveAllAuras(); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - me->InterruptNonMeleeSpells(false); + void JustDied(Unit* killer) override + { + Talk(SAY_DEATH); + BossAI::JustDied(killer); + instance->SetBossState(DATA_NOVOS_CRYSTALS, DONE); + } - scheduler.SetValidator([this] { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); - - ScheduleTimedEvent(5s, 10s, [&] { - DoCastRandomTarget(SPELL_BLIZZARD); - }, 12s, 25s); - - ScheduleTimedEvent(5s, 10s, [&] { - DoCastRandomTarget(SPELL_WRATH_OF_MISERY); - }, 8s, 16s); - - if (IsHeroic()) + void KilledUnit(Unit* /*victim*/) override + { + if (events.GetNextEventTime(EVENT_KILL_TALK) == 0) { - ScheduleTimedEvent(10s, [&] { - DoCastAOE(SPELL_SUMMON_MINIONS); - }, 37s, 55s); + Talk(SAY_KILL); + events.ScheduleEvent(EVENT_KILL_TALK, 6s); } - }); - - for (Seconds timer : { 16s, 32s, 48s, 64s }) - { - me->m_Events.AddEventAtOffset([&] { - Talk(SAY_SUMMONING_ADDS); - Talk(EMOTE_SUMMONING_ADDS); - if (Creature* target = ObjectAccessor::GetCreature(*me, _stage ? _summonTargetLeftGUID : _summonTargetRightGUID)) - target->CastSpell(target, SPELL_SUMMON_CRYSTAL_HANDLER, true, nullptr, nullptr, me->GetGUID()); - _stage = _stage ? 0 : 1; - }, timer); } - me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); - me->RemoveAllAuras(); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - - DoCastSelf(SPELL_ARCANE_BLAST, true); - DoCastSelf(SPELL_ARCANE_FIELD, true); - DoCastSelf(SPELL_DESPAWN_CRYSTAL_HANDLER, true); - - for (auto& itr : npcSummon) + void JustSummoned(Creature* summon) override { - uint32 summonEntry; - Position summonPos; - std::tie(summonEntry, summonPos) = itr.second; - if (Creature* creature = me->SummonCreature(summonEntry, summonPos)) - switch (itr.first) - { - case ROOM_LEFT: - _summonTargetLeftGUID = creature->GetGUID(); - break; - case ROOM_RIGHT: - _summonTargetRightGUID = creature->GetGUID(); - break; - } - } - } - - void JustDied(Unit* killer) override - { - Talk(SAY_DEATH); - BossAI::JustDied(killer); - instance->SetBossState(DATA_NOVOS_CRYSTALS, DONE); - } - - void KilledUnit(Unit* /*victim*/) override - { - if (!events.HasTimeUntilEvent(EVENT_KILL_TALK)) - { - Talk(SAY_KILL); - events.ScheduleEvent(EVENT_KILL_TALK, 6s); - } - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - - // Phase 1 - if (me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET && summon->GetEntry() != NPC_CRYSTAL_HANDLER) + summons.Summon(summon); + if (me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) && summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET && summon->GetEntry() != NPC_CRYSTAL_HANDLER) summon->SetReactState(REACT_DEFENSIVE); - - if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE) - summon->GetMotionMaster()->MovePoint(1, -373.56f, -770.86f, 28.59f); - - if (summon->EntryEquals(NPC_CRYSTAL_HANDLER)) + else if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET) summon->SetInCombatWithZone(); } - // Phase 2 - else if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET) - summon->SetInCombatWithZone(); - } - void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override - { - if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE) - summon->DespawnOrUnsummon(10s); - } - - void SummonMovementInform(Creature* summon, uint32 movementType, uint32 pathId) override - { - if (movementType == POINT_MOTION_TYPE && pathId == 1) + void UpdateAI(uint32 diff) override { - if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE) + if (!UpdateVictim()) + return; + + events.Update(diff); + switch (events.ExecuteEvent()) { - DoZoneInCombat(summon); - _achievement = false; + case EVENT_SUMMON_FETID_TROLL: + if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) + trigger->CastSpell(trigger, SPELL_SUMMON_FETID_TROLL_CORPSE, true, nullptr, nullptr, me->GetGUID()); + events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s); + break; + case EVENT_SUMMON_HULKING_CORPSE: + if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) + trigger->CastSpell(trigger, SPELL_SUMMON_HULKING_CORPSE, true, nullptr, nullptr, me->GetGUID()); + events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s); + break; + case EVENT_SUMMON_SHADOWCASTER: + if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) + trigger->CastSpell(trigger, SPELL_SUMMON_RISEN_SHADOWCASTER, true, nullptr, nullptr, me->GetGUID()); + events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 10s); + break; + case EVENT_SUMMON_CRYSTAL_HANDLER: + if (_crystalCounter++ < 4) + { + Talk(SAY_SUMMONING_ADDS); + Talk(EMOTE_SUMMONING_ADDS); + if (Creature* target = ObjectAccessor::GetCreature(*me, _stage ? _summonTargetLeftGUID : _summonTargetRightGUID)) + target->CastSpell(target, SPELL_SUMMON_CRYSTAL_HANDLER, true, nullptr, nullptr, me->GetGUID()); + _stage = _stage ? 0 : 1; + events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s); + } + break; + case EVENT_CHECK_PHASE: + if (me->HasAura(SPELL_BEAM_CHANNEL)) + { + events.ScheduleEvent(EVENT_CHECK_PHASE, 2s); + break; + } + events.Reset(); + events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 3s); + events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 10s); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->InterruptNonMeleeSpells(false); + break; + case EVENT_CAST_OFFENSIVE_SPELL: + if (!me->HasUnitState(UNIT_STATE_CASTING)) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + me->CastSpell(target, RAND(SPELL_BLIZZARD, SPELL_FROSTBOLT, SPELL_TOUCH_OF_MISERY), false); + + events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 500ms); + break; + case EVENT_SPELL_SUMMON_MINIONS: + if (me->HasUnitState(UNIT_STATE_CASTING)) + { + me->CastSpell(me, SPELL_SUMMON_MINIONS, false); + events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 15s); + break; + } + events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 500ms); + break; } } - } - void UpdateAI(uint32 diff) override + bool CheckEvadeIfOutOfCombatArea() const override + { + return !SelectTargetFromPlayerList(80.0f); + } + + private: + uint8 _crystalCounter; + uint8 _stage; + ObjectGuid _summonTargetRightGUID; + ObjectGuid _summonTargetLeftGUID; + + bool _achievement; + }; + + CreatureAI* GetAI(Creature* creature) const override { - if (!UpdateVictim()) - return; - - scheduler.Update(diff); - events.Update(diff); - - if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - DoSpellAttackIfReady(SPELL_FROSTBOLT); + return GetDraktharonKeepAI(creature); } - - bool CheckEvadeIfOutOfCombatArea() const override - { - return !SelectTargetFromPlayerList(80.0f); - } - -private: - uint8 _crystalCounter; - uint8 _stage; - ObjectGuid _summonTargetRightGUID; - ObjectGuid _summonTargetLeftGUID; - - bool _achievement; }; -// 51403 class spell_novos_despawn_crystal_handler : public SpellScript { PrepareSpellScript(spell_novos_despawn_crystal_handler); @@ -300,7 +290,6 @@ class spell_novos_despawn_crystal_handler : public SpellScript } }; -// 47336 class spell_novos_crystal_handler_death_aura : public AuraScript { PrepareAuraScript(spell_novos_crystal_handler_death_aura); @@ -318,7 +307,6 @@ class spell_novos_crystal_handler_death_aura : public AuraScript } }; -// 59910 class spell_novos_summon_minions : public SpellScript { PrepareSpellScript(spell_novos_summon_minions); @@ -340,7 +328,6 @@ class spell_novos_summon_minions : public SpellScript } }; -// 2057 class achievement_oh_novos : public AchievementCriteriaScript { public: @@ -354,7 +341,7 @@ public: void AddSC_boss_novos() { - RegisterCreatureAIWithFactory(boss_novos, GetDraktharonKeepAI); + new boss_novos(); RegisterSpellScript(spell_novos_despawn_crystal_handler); RegisterSpellScript(spell_novos_crystal_handler_death_aura); RegisterSpellScript(spell_novos_summon_minions); diff --git a/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h b/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h index dceeeafd8..e8f2722d0 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h +++ b/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h @@ -39,7 +39,6 @@ enum Creatures NPC_KURZEL = 26664, NPC_DRAKKARI_GUARDIAN = 26620, NPC_RISEN_DRAKKARI_WARRIOR = 26635, - NPC_FETID_TROLL_CORPSE = 27598, }; enum GameObjects diff --git a/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp b/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp index 9547a1d69..50be90a84 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp @@ -31,39 +31,50 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM } }; -struct instance_drak_tharon_keep : public InstanceScript +class instance_drak_tharon_keep : public InstanceMapScript { - instance_drak_tharon_keep(Map* map) : InstanceScript(map) - { - SetHeaders(DataHeader); - SetBossNumber(MAX_ENCOUNTERS); - LoadDoorData(doorData); - } +public: + instance_drak_tharon_keep() : InstanceMapScript("instance_drak_tharon_keep", MAP_DRAK_THARON_KEEP) { } - void OnGameObjectCreate(GameObject* go) override + struct instance_drak_tharon_keep_InstanceScript : public InstanceScript { - switch (go->GetEntry()) + instance_drak_tharon_keep_InstanceScript(Map* map) : InstanceScript(map) { - case GO_NOVOS_CRYSTAL_1: - case GO_NOVOS_CRYSTAL_2: - case GO_NOVOS_CRYSTAL_3: - case GO_NOVOS_CRYSTAL_4: - AddDoor(go); - break; + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTERS); + LoadDoorData(doorData); } - } - void OnGameObjectRemove(GameObject* go) override - { - switch (go->GetEntry()) + void OnGameObjectCreate(GameObject* go) override { - case GO_NOVOS_CRYSTAL_1: - case GO_NOVOS_CRYSTAL_2: - case GO_NOVOS_CRYSTAL_3: - case GO_NOVOS_CRYSTAL_4: - RemoveDoor(go); - break; + switch (go->GetEntry()) + { + case GO_NOVOS_CRYSTAL_1: + case GO_NOVOS_CRYSTAL_2: + case GO_NOVOS_CRYSTAL_3: + case GO_NOVOS_CRYSTAL_4: + AddDoor(go); + break; + } } + + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_NOVOS_CRYSTAL_1: + case GO_NOVOS_CRYSTAL_2: + case GO_NOVOS_CRYSTAL_3: + case GO_NOVOS_CRYSTAL_4: + RemoveDoor(go); + break; + } + } + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override + { + return new instance_drak_tharon_keep_InstanceScript(map); } }; @@ -110,7 +121,7 @@ class spell_dtk_summon_random_drakkari : public SpellScript void AddSC_instance_drak_tharon_keep() { - RegisterInstanceScript(instance_drak_tharon_keep, MAP_DRAK_THARON_KEEP); + new instance_drak_tharon_keep(); RegisterSpellScript(spell_dtk_raise_dead_aura); RegisterSpellScript(spell_dtk_summon_random_drakkari); } diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp index fcf59ae2e..25a253a64 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp @@ -63,27 +63,23 @@ public: memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } - void OnCreatureCreate(Creature* creature) override + void OnCreatureCreate(Creature* pCreature) override { - switch (creature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_DRAKOS: - uiDrakosGUID = creature->GetGUID(); + uiDrakosGUID = pCreature->GetGUID(); break; case NPC_VAROS: - uiVarosGUID = creature->GetGUID(); + uiVarosGUID = pCreature->GetGUID(); break; case NPC_UROM: - uiUromGUID = creature->GetGUID(); + uiUromGUID = pCreature->GetGUID(); break; case NPC_EREGOS: - uiEregosGUID = creature->GetGUID(); + uiEregosGUID = pCreature->GetGUID(); break; } - - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) - if (creature->EntryEquals(NPC_AMBER_DRAKE, NPC_EMERALD_DRAKE, NPC_RUBY_DRAKE)) - creature->SetFaction(FACTION_FRIENDLY); // Friendly faction to allow interaction from both factions } void OnGameObjectCreate(GameObject* pGo) override diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp index d35b11025..38a73129d 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp @@ -30,7 +30,6 @@ enum LokenSpells SPELL_LIGHTNING_NOVA_THUNDERS = 52663, SPELL_PULSING_SHOCKWAVE = 52961, - SPELL_PULSING_SHOCKWAVE_AURA = 59414, // Achievement ACHIEVEMENT_TIMELY_DEATH = 20384 @@ -50,6 +49,15 @@ enum Yells EMOTE_NOVA = 9 }; +enum LokenEvents +{ + EVENT_LIGHTNING_NOVA = 1, + EVENT_SHOCKWAVE = 2, + EVENT_ARC_LIGHTNING = 3, + EVENT_CHECK_HEALTH = 4, + EVENT_AURA_REMOVE = 5 +}; + struct boss_loken : public BossAI { boss_loken(Creature* creature) : BossAI(creature, DATA_LOKEN), _introDone(false) { } @@ -86,49 +94,18 @@ struct boss_loken : public BossAI _introDone = true; } - void OnAuraRemove(AuraApplication* auraApp, AuraRemoveMode /*mode*/) override - { - if (auraApp->GetBase()->GetId() == SPELL_LIGHTNING_NOVA_VISUAL) - { - me->RemoveAura(SPELL_LIGHTNING_NOVA_THUNDERS); - me->ClearUnitState(UNIT_STATE_CASTING); - me->ResumeChasingVictim(); - } - } - - void ScheduleTasks() override - { - me->m_Events.AddEventAtOffset([&] { - DoCastAOE(SPELL_PULSING_SHOCKWAVE_AURA, true); - me->ClearUnitState(UNIT_STATE_CASTING); // the aura above is a channeled spell, so we need this - DoCastSelf(SPELL_PULSING_SHOCKWAVE); - }, 3s); - - ScheduleTimedEvent(15s, [&] { - Talk(SAY_NOVA); - Talk(EMOTE_NOVA); - DoCastSelf(SPELL_LIGHTNING_NOVA_VISUAL, true); - DoCastSelf(SPELL_LIGHTNING_NOVA_THUNDERS, true); - DoCastAOE(SPELL_LIGHTNING_NOVA); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveIdle(); - }, 15s); - - if (IsHeroic()) - { - ScheduleTimedEvent(10s, [&] { - DoCastRandomTarget(SPELL_ARC_LIGHTNING, 0, 100.0f, false); - }, 12s); - - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_TIMELY_DEATH); - } - } - void JustEngagedWith(Unit*) override { me->m_Events.KillAllEvents(false); _JustEngagedWith(); Talk(SAY_AGGRO); + + events.ScheduleEvent(EVENT_ARC_LIGHTNING, 10s); + events.ScheduleEvent(EVENT_SHOCKWAVE, 3s); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 15s); + + if (IsHeroic()) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_TIMELY_DEATH); } void JustDied(Unit*) override @@ -145,6 +122,46 @@ struct boss_loken : public BossAI Talk(SAY_SLAY); } + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_LIGHTNING_NOVA: + Talk(SAY_NOVA); + events.Repeat(15s); + me->CastSpell(me, SPELL_LIGHTNING_NOVA_VISUAL, true); + me->CastSpell(me, SPELL_LIGHTNING_NOVA_THUNDERS, true); + + events.DelayEvents(5s); + events.ScheduleEvent(EVENT_AURA_REMOVE, me->GetMap()->IsHeroic() ? 4s : 5s); + + me->CastSpell(me, SPELL_LIGHTNING_NOVA, false); + break; + case EVENT_SHOCKWAVE: + me->CastSpell(me, SPELL_PULSING_SHOCKWAVE, false); + break; + case EVENT_ARC_LIGHTNING: + if (Unit* target = SelectTargetFromPlayerList(100, SPELL_ARC_LIGHTNING)) + me->CastSpell(target, SPELL_ARC_LIGHTNING, false); + + events.Repeat(12s); + break; + case EVENT_AURA_REMOVE: + me->RemoveAura(SPELL_LIGHTNING_NOVA_THUNDERS); + break; + } + + DoMeleeAttackIfReady(); + } private: bool _introDone; }; diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp index e24adc5ac..6071bc703 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/brann_bronzebeard.cpp @@ -334,6 +334,7 @@ public: SetDespawnAtEnd(false); ResetEvent(); + me->SetFaction(FACTION_FRIENDLY); me->SetReactState(REACT_PASSIVE); me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); @@ -365,12 +366,21 @@ public: case ACTION_START_ESCORT_EVENT: Start(false, ObjectGuid::Empty, 0, true, false); Talk(SAY_BRANN_ESCORT_START); + me->SetFaction(FACTION_ESCORTEE_N_NEUTRAL_PASSIVE); me->SetReactState(REACT_AGGRESSIVE); me->SetRegeneratingHealth(true); break; case ACTION_START_TRIBUNAL: { me->SetReactState(REACT_PASSIVE); + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + if (!PlayerList.IsEmpty()) + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + me->SetFaction(i->GetSource()->GetFaction()); + break; + } + SetEscortPaused(false); InitializeEvent(); me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); @@ -384,6 +394,7 @@ public: break; case ACTION_GO_TO_SJONNIR: Talk(SAY_BRANN_ENTRANCE_MEET); + me->SetFaction(FACTION_FRIENDLY); me->SetReactState(REACT_PASSIVE); me->SetRegeneratingHealth(true); SetEscortPaused(false); @@ -395,6 +406,7 @@ public: me->SetImmuneToAll(true); break; case ACTION_START_SJONNIR_FIGHT: + me->SetFaction(FACTION_FRIENDLY); SetEscortPaused(false); break; case ACTION_SJONNIR_DEAD: diff --git a/src/server/scripts/Northrend/isle_of_conquest.cpp b/src/server/scripts/Northrend/isle_of_conquest.cpp index 41a5b36ae..240fa79f6 100644 --- a/src/server/scripts/Northrend/isle_of_conquest.cpp +++ b/src/server/scripts/Northrend/isle_of_conquest.cpp @@ -209,14 +209,14 @@ public: enum BossIoCEvents { EVENT_CHECK_RAGE = 1, - EVENT_MORTAL_STRIKE = 2, + EVENT_BRUTAL_STRIKE = 2, EVENT_CRUSHING_LEAP = 3, EVENT_DAGGER_THROW = 4, }; enum BossIoCSpells { - SPELL_IOCBOSS_MORTAL_STRIKE = 39171, + SPELL_IOCBOSS_BRUTAL_STRIKE = 58460, SPELL_IOCBOSS_CRUSHING_LEAP = 68506, SPELL_IOCBOSS_DAGGER_THROW = 67280, SPELL_IOCBOSS_RAGE = 66776, @@ -262,7 +262,7 @@ public: void JustEngagedWith(Unit* /*who*/) override { events.ScheduleEvent(EVENT_CHECK_RAGE, 2s); - events.ScheduleEvent(EVENT_MORTAL_STRIKE, 6s); + events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 6s); events.ScheduleEvent(EVENT_CRUSHING_LEAP, 22s); events.ScheduleEvent(EVENT_DAGGER_THROW, 10s); } @@ -282,8 +282,8 @@ public: CheckRageBuff(); events.Repeat(2s); break; - case EVENT_MORTAL_STRIKE: - DoCastVictim(SPELL_IOCBOSS_MORTAL_STRIKE); + case EVENT_BRUTAL_STRIKE: + me->CastSpell(me->GetVictim(), SPELL_IOCBOSS_BRUTAL_STRIKE, false); events.Repeat(6s); break; case EVENT_CRUSHING_LEAP: diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index ec6a55f17..24704b502 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -1989,40 +1989,6 @@ class spell_soul_deflection : public AuraScript } }; -enum SpellBloodHaze -{ - SPELL_BLOODSPORE_HAZE = 50380, - SPELL_PSYCHOSIS = 50396 -}; - -// 50380 - Bloodspore Haze -class spell_bloodspore_haze : public SpellScript -{ - PrepareSpellScript(spell_bloodspore_haze); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_PSYCHOSIS }); - } - - void HandleEffectHit(SpellEffIndex /*effIndex*/) - { - if (!GetHitUnit()) - return; - - if (GetHitUnit()->GetAuraCount(SPELL_BLOODSPORE_HAZE) >= 5) - { - GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PSYCHOSIS, true); - GetHitUnit()->RemoveAura(SPELL_BLOODSPORE_HAZE); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_bloodspore_haze::HandleEffectHit, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); - } -}; - void AddSC_borean_tundra() { RegisterSpellScript(spell_q11919_q11940_drake_hunt_aura); @@ -2047,5 +2013,4 @@ void AddSC_borean_tundra() RegisterCreatureAI(npc_jenny); RegisterSpellScript(spell_necropolis_beam); RegisterSpellScript(spell_soul_deflection); - RegisterSpellScript(spell_bloodspore_haze); } diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index bccd217ad..56abff11e 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -390,6 +390,116 @@ class spell_q12227_camera_shake : public SpellScript OnEffectHitTarget += SpellEffectFn(spell_q12227_camera_shake::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_DUMMY); } }; +// Tallhorn Stage + +enum TallhornStage +{ + //Gameobject + OBJECT_HAUNCH = 188665 +}; + +class npc_tallhorn_stag : public CreatureScript +{ +public: + npc_tallhorn_stag() : CreatureScript("npc_tallhorn_stag") { } + + struct npc_tallhorn_stagAI : public ScriptedAI + { + npc_tallhorn_stagAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + _phase = 1; + } + + void UpdateAI(uint32 /*diff*/) override + { + if (_phase == 1) + { + if (me->FindNearestGameObject(OBJECT_HAUNCH, 2.0f)) + { + me->SetStandState(UNIT_STAND_STATE_DEAD); + me->SetImmuneToPC(true); + me->ReplaceAllDynamicFlags(UNIT_DYNFLAG_DEAD); + } + _phase = 0; + } + DoMeleeAttackIfReady(); + } + private: + uint8 _phase; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_tallhorn_stagAI(creature); + } +}; + +// Amberpine Woodsman + +enum AmberpineWoodsman +{ + // Creature + NPC_TALLHORN_STAG = 26363 +}; + +enum AmberpineWoodsmanEvents +{ + EVENT_WOODSMAN_1 = 1, + EVENT_WOODSMAN_2 = 2 +}; + +class npc_amberpine_woodsman : public CreatureScript +{ +public: + npc_amberpine_woodsman() : CreatureScript("npc_amberpine_woodsman") { } + + struct npc_amberpine_woodsmanAI : public ScriptedAI + { + npc_amberpine_woodsmanAI(Creature* creature) : ScriptedAI(creature) { } + + void Reset() override + { + if (me->FindNearestCreature(NPC_TALLHORN_STAG, 0.2f)) + { + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING); + } + else + _events.ScheduleEvent(EVENT_WOODSMAN_1, 0ms); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_WOODSMAN_1: + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_LOOT); + _events.ScheduleEvent(EVENT_WOODSMAN_2, 3s); + break; + case EVENT_WOODSMAN_2: + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK1H); + _events.ScheduleEvent(EVENT_WOODSMAN_1, 4s); + break; + default: + break; + } + } + UpdateVictim(); + } + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_amberpine_woodsmanAI(creature); + } +}; /*###### ## Quest 12288: Overwhelmed! @@ -1068,6 +1178,8 @@ void AddSC_grizzly_hills() new npc_emily(); new npc_mrfloppy(); new npc_ravenous_worg(); + new npc_tallhorn_stag(); + new npc_amberpine_woodsman(); RegisterCreatureAI(npc_wounded_skirmisher); RegisterSpellScript(spell_renew_skirmisher); new npc_venture_co_straggler(); diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp index 4af05b4b9..1a97cd121 100644 --- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp +++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp @@ -49,6 +49,7 @@ class spell_q12726_song_of_wind_and_water : public SpellScript cr->SetDisplayId(cr->GetDisplayId() == NPC_SOWAW_WATER_MODEL ? NPC_SOWAW_WIND_MODEL : NPC_SOWAW_WATER_MODEL); if (Player* player = cr->GetCharmerOrOwnerPlayerOrPlayerItself()) { + player->KilledMonsterCredit(cr->GetDisplayId() == NPC_SOWAW_WATER_MODEL ? 29008 : 29009); CreatureTemplate const* ct = sObjectMgr->GetCreatureTemplate(cr->GetDisplayId() == NPC_SOWAW_WIND_MODEL ? NPC_SOWAW_WIND_ELEMENTAL : NPC_SOWAW_WATER_ELEMENTAL); for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i) cr->m_spells[i] = ct->spells[i]; @@ -1106,6 +1107,108 @@ class spell_q12589_shoot_rjr : public SpellScript } }; +/*###### +## Quest: Reconnaissance Flight (12671) +######*/ +enum ReconnaissanceFlight +{ + NPC_PLANE = 28710, // Vic's Flying Machine + NPC_PILOT = 28646, + + VIC_SAY_0 = 0, + VIC_SAY_1 = 1, + VIC_SAY_2 = 2, + VIC_SAY_3 = 3, + VIC_SAY_4 = 4, + VIC_SAY_5 = 5, + VIC_SAY_6 = 6, + PLANE_EMOTE = 0, + + AURA_ENGINE = 52255, // Engine on Fire + + SPELL_LAND = 52226, // Land Flying Machine + SPELL_CREDIT = 53328 // Land Flying Machine Credit +}; + +class npc_vics_flying_machine : public CreatureScript +{ +public: + npc_vics_flying_machine() : CreatureScript("npc_vics_flying_machine") { } + + struct npc_vics_flying_machineAI : public VehicleAI + { + npc_vics_flying_machineAI(Creature* creature) : VehicleAI(creature) + { + pointId = 0; + } + + uint8 pointId; + + void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override + { + if (apply && passenger->IsPlayer()) + { + me->GetMotionMaster()->MovePath(NPC_PLANE, FORCED_MOVEMENT_NONE, PathSource::WAYPOINT_MGR); + } + } + + void MovementInform(uint32 type, uint32 /*id*/) override + { + if (type != ESCORT_MOTION_TYPE) + return; + + if (Vehicle* veh = me->GetVehicleKit()) + if (Unit* pilot = veh->GetPassenger(0)) + switch (pointId) + { + case 5: + pilot->ToCreature()->AI()->Talk(VIC_SAY_0); + break; + case 11: + pilot->ToCreature()->AI()->Talk(VIC_SAY_1); + break; + case 12: + pilot->ToCreature()->AI()->Talk(VIC_SAY_2); + break; + case 14: + pilot->ToCreature()->AI()->Talk(VIC_SAY_3); + break; + case 15: + pilot->ToCreature()->ToCreature()->AI()->Talk(VIC_SAY_4); + break; + case 17: + pilot->ToCreature()->AI()->Talk(VIC_SAY_5); + break; + case 21: + pilot->ToCreature()->AI()->Talk(VIC_SAY_6); + break; + case 25: + Talk(PLANE_EMOTE); + DoCastSelf(AURA_ENGINE); + break; + } + pointId++; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_LAND) + { + Unit* passenger = me->GetVehicleKit()->GetPassenger(1); // player should be on seat 1 + if (passenger && passenger->IsPlayer()) + passenger->CastSpell(passenger, SPELL_CREDIT, true); + + me->DespawnOrUnsummon(); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_vics_flying_machineAI(creature); + } +}; + /*###### ## Quest Dreadsaber Mastery: Stalking the Prey (12550) ######*/ @@ -1193,6 +1296,7 @@ void AddSC_sholazar_basin() new npc_jungle_punch_target(); RegisterSpellScript(spell_q12620_the_lifewarden_wrath); RegisterSpellScript(spell_q12589_shoot_rjr); + new npc_vics_flying_machine(); RegisterSpellScript(spell_shango_tracks); RegisterSpellScript(spell_q12611_deathbolt); diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 2bdf9dba9..87ca825ed 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -31,7 +31,6 @@ enum qSniffingOutThePerpetrator { NPC_FROSTHOUND = 29677, - NPC_FROSTBITE = 29903, SPELL_SUMMON_PURSUERS_PERIODIC = 54993, SPELL_SNIFFING_CREDIT = 55477, TALK_EMOTE_FROSTHOUND_SNIFF = 0, @@ -42,7 +41,7 @@ enum qSniffingOutThePerpetrator struct npc_frosthound : public npc_escortAI { - explicit npc_frosthound(Creature* creature) : npc_escortAI(creature), _summons(creature), _completionWaypoint((creature->GetEntry() == NPC_FROSTBITE) ? 19 : 34) { } + explicit npc_frosthound(Creature* creature) : npc_escortAI(creature), _summons(creature) {} void AttackStart(Unit* /*who*/) override {} void JustEngagedWith(Unit* /*who*/) override {} @@ -78,15 +77,20 @@ struct npc_frosthound : public npc_escortAI if (!player) return; - if (waypointId == 0) - Talk(TALK_SEEN, player); - else if (waypointId == _completionWaypoint) + switch (waypointId) { - Talk(TALK_EMOTE_TRACKED_COMPLETE, me); - Talk(TALK_CONFRONT, player); - if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) - summoner->ToPlayer()->KilledMonsterCredit(NPC_FROSTHOUND); // same credit for Alliance and Horde - _summons.DespawnAll(); + case 0: + Talk(TALK_SEEN, player); + break; + case 34: + Talk(TALK_EMOTE_TRACKED_COMPLETE, me); + Talk(TALK_CONFRONT, player); + if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) + summoner->ToPlayer()->KilledMonsterCredit(NPC_FROSTHOUND); + _summons.DespawnAll(); + break; + default: + break; } } @@ -108,7 +112,6 @@ struct npc_frosthound : public npc_escortAI private: SummonList _summons; - uint32 _completionWaypoint; }; enum eIronWatcher diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp index 230678a4e..d0ef8ada5 100644 --- a/src/server/scripts/Northrend/zone_zuldrak.cpp +++ b/src/server/scripts/Northrend/zone_zuldrak.cpp @@ -265,7 +265,6 @@ enum OverlordDrakuru NPC_TOTALLY_GENERIC_BUNNY = 29100, NPC_TOTALLY_GENERIC_BUNNY_JSB = 28960, GO_DRAKURUS_LAST_WISH = 202357, - GO_DRAKURUS_BONE = 191458, ACTION_SUMMON_DRAKURU_LAST_WISH = 1, ACTION_DESTROY_DRAKURU_LAST_WISH = 2, @@ -317,7 +316,7 @@ struct npc_overlord_drakuru_betrayal : public ScriptedAI { npc_overlord_drakuru_betrayal(Creature* creature) : ScriptedAI(creature), _summons(me), _state(BETRAYAL_NOT_STARTED) { - me->SetControlled(true, UNIT_STATE_ROOT); + me->SetCombatMovement(false); } void EnterEvadeMode(EvadeReason why) override @@ -376,7 +375,7 @@ struct npc_overlord_drakuru_betrayal : public ScriptedAI { if (Player* player = who->ToPlayer()) { - bool shouldStartEvent = (_state == BETRAYAL_NOT_STARTED) && IsPlayerOnQuest(player) && player->HasAura(SPELL_SCOURGE_DISGUISE) && player->IsWithinDistInMap(me, 80.0f) && !me->FindNearestGameObject(GO_DRAKURUS_BONE, 80.0f); + bool shouldStartEvent = (_state == BETRAYAL_NOT_STARTED) && IsPlayerOnQuest(player) && player->HasAura(SPELL_SCOURGE_DISGUISE) && player->IsWithinDistInMap(me, 80.0f); if (shouldStartEvent) { me->SetVisible(true); @@ -588,7 +587,6 @@ struct npc_overlord_drakuru_betrayal : public ScriptedAI lich->GetMotionMaster()->MovePoint(0, 6141.2393, -2011.2728, 589.8653); break; case EVENT_BETRAYAL_EPILOGUE_10: - _state = BETRAYAL_EVADE; EnterEvadeMode(EVADE_REASON_OTHER); break; } diff --git a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp index 0827a0e63..79ab9a318 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp @@ -141,15 +141,13 @@ public: void MoveInLineOfSight(Unit* who) override { - if (!who || me->getStandState() != UNIT_STAND_STATE_SLEEP || !who->IsPlayer() || - who->ToPlayer()->IsGameMaster() || me->GetDistance2d(who) > 90.0f || - !me->isInFront(who, M_PI / 4.0f) || !me->IsWithinLOSInMap(who)) + if (!who || me->getStandState() != UNIT_STAND_STATE_SLEEP || !who->IsPlayer() || me->GetDistance2d(who) > 90.0f || who->ToPlayer()->IsGameMaster()) return; me->SetInCombatWithZone(); me->SetStandState(UNIT_STAND_STATE_STAND); - ScheduleUniqueTimedEvent(5s, [&] { + ScheduleUniqueTimedEvent(5s, [&] { // 15s me->SetStandState(UNIT_STAND_STATE_SUBMERGED); DoCastSelf(SPELL_SUMMON_ESSENCE_OF_SUFFERING); }, EVENT_ESSENCE_OF_SUFFERING); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index f5ff6e968..df4e3a016 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -2019,14 +2019,11 @@ class spell_gen_animal_blood : public AuraScript { // Remove all auras with spell id 46221, except the one currently being applied while (Aura* aur = GetUnitOwner()->GetOwnedAura(SPELL_ANIMAL_BLOOD, ObjectGuid::Empty, ObjectGuid::Empty, 0, GetAura())) - GetUnitOwner()->RemoveOwnedAura(aur, AURA_REMOVE_BY_EXPIRE); + GetUnitOwner()->RemoveOwnedAura(aur); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) - return; - if (Unit* owner = GetUnitOwner()) if (owner->IsInWater()) owner->CastSpell(owner, SPELL_SPAWN_BLOOD_POOL, true); @@ -2047,7 +2044,7 @@ class spell_spawn_blood_pool : public SpellScript void SetDest(SpellDestination &dest) { Unit* caster = GetCaster(); - LiquidData liquidStatus = caster->GetMap()->GetLiquidData(caster->GetPhaseMask(), caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), caster->GetCollisionHeight(), {}); + LiquidData liquidStatus = caster->GetMap()->GetLiquidData(caster->GetPhaseMask(), caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), caster->GetCollisionHeight(), MAP_ALL_LIQUIDS); float level = liquidStatus.Level > INVALID_HEIGHT ? liquidStatus.Level : caster->GetPositionZ(); Position pos = Position(caster->GetPositionX(), caster->GetPositionY(), level, caster->GetOrientation()); diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp index d031d4465..8f7f403e0 100644 --- a/src/server/scripts/World/areatrigger_scripts.cpp +++ b/src/server/scripts/World/areatrigger_scripts.cpp @@ -170,7 +170,7 @@ public: { QuestStatus QLR = player->GetQuestStatus(QUEST_LAST_RITES); QuestStatus QBT = player->GetQuestStatus(QUEST_BREAKING_THROUGH); - if (!(QLR == QUEST_STATUS_INCOMPLETE || QLR == QUEST_STATUS_COMPLETE || QLR == QUEST_STATUS_REWARDED || + if (!(QLR == QUEST_STATUS_INCOMPLETE || QLR == QUEST_STATUS_COMPLETE || QBT == QUEST_STATUS_INCOMPLETE || QBT == QUEST_STATUS_COMPLETE)) return false; diff --git a/src/server/scripts/World/chat_log.cpp b/src/server/scripts/World/chat_log.cpp index 3feb0c528..a1af849c9 100644 --- a/src/server/scripts/World/chat_log.cpp +++ b/src/server/scripts/World/chat_log.cpp @@ -27,16 +27,16 @@ public: ChatLogScript() : PlayerScript("ChatLogScript", { - PLAYERHOOK_CAN_PLAYER_USE_CHAT, - PLAYERHOOK_CAN_PLAYER_USE_PRIVATE_CHAT, - PLAYERHOOK_CAN_PLAYER_USE_GROUP_CHAT, - PLAYERHOOK_CAN_PLAYER_USE_GUILD_CHAT, - PLAYERHOOK_CAN_PLAYER_USE_CHANNEL_CHAT, + PLAYERHOOK_ON_CHAT, + PLAYERHOOK_ON_CHAT_WITH_GROUP, + PLAYERHOOK_ON_CHAT_WITH_GUILD, + PLAYERHOOK_ON_CHAT_WITH_CHANNEL, + PLAYERHOOK_ON_CHAT_WITH_RECEIVER }) { } - bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 lang, std::string& msg) override + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg) override { std::string logType = ""; std::string chatType = ""; @@ -56,16 +56,14 @@ public: chatType = "yells"; break; default: - return true; + return; } LOG_INFO(logType, "Player {} {} (language {}): {}", player->GetName(), chatType, lang, msg); - - return true; } - bool OnPlayerCanUseChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Player* receiver) override + void OnPlayerChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Player* receiver) override { //! NOTE: //! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER" @@ -74,11 +72,9 @@ public: LOG_INFO(logType + msgType, "Player {} {} {}: {}", player->GetName(), msgType, receiver ? receiver->GetName() : "", msg); - - return true; } - bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override { //! NOTE: //! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER" @@ -101,7 +97,7 @@ public: msgType = "bg"; break; default: - return true; + return; } std::string role = (type == CHAT_MSG_PARTY_LEADER || type == CHAT_MSG_RAID_LEADER || type == CHAT_MSG_BATTLEGROUND_LEADER) ? "Leader player" : "Player"; @@ -110,11 +106,9 @@ public: LOG_INFO(logType + msgType, "{} {} {} {} with leader {}: {}", role, player->GetName(), action, msgType, targetGroup, msg); - - return true; } - bool OnPlayerCanUseChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override + void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override { //! NOTE: //! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER" @@ -130,16 +124,14 @@ public: msgType = "guild.officer"; break; default: - return true; + return; } LOG_INFO(logType + msgType, "Player {} tells {} \"{}\": {}", player->GetName(), msgType, guild ? guild->GetName() : "", msg); - - return true; } - bool OnPlayerCanUseChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel) override + void OnPlayerChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel) override { bool isSystem = channel && (channel->HasFlag(CHANNEL_FLAG_TRADE) || @@ -160,8 +152,6 @@ public: LOG_INFO("chat.channel." + channelName, "Player {} tells channel {}: {}", player->GetName(), channelName, msg); } - - return true; } }; diff --git a/src/server/shared/DataStores/DBCDatabaseLoader.cpp b/src/server/shared/DataStores/DBCDatabaseLoader.cpp index 44e65653d..883fe527f 100644 --- a/src/server/shared/DataStores/DBCDatabaseLoader.cpp +++ b/src/server/shared/DataStores/DBCDatabaseLoader.cpp @@ -29,8 +29,7 @@ DBCDatabaseLoader::DBCDatabaseLoader(char const* tableName, char const* dbcForma _stringPool(stringPool) { // Get sql index position - int32 indexPos = -1; - _recordSize = DBCFileLoader::GetFormatRecordSize(_dbcFormat, &indexPos); + _recordSize = DBCFileLoader::GetFormatRecordSize(_dbcFormat, &_sqlIndexPos); ASSERT(_recordSize); } @@ -72,11 +71,11 @@ char* DBCDatabaseLoader::Load(uint32& records, char**& indexTable) { Field* fields = result->Fetch(); uint32 indexValue = fields[_sqlIndexPos].Get(); - char* dataValue = indexTable[indexValue]; + char* oldDataValue = indexTable[indexValue]; // If exist in DBC file override from DB newIndexes[newRecords] = indexValue; - dataValue = &dataTable[newRecords++ * _recordSize]; + char* dataValue = &dataTable[newRecords++ * _recordSize]; uint32 dataOffset = 0; uint32 sqlColumnNumber = 0; @@ -100,7 +99,15 @@ char* DBCDatabaseLoader::Load(uint32& records, char**& indexTable) dataOffset += sizeof(uint8); break; case FT_STRING: - *reinterpret_cast(&dataValue[dataOffset]) = CloneStringToPool(fields[sqlColumnNumber].Get()); + // not override string if new string is empty + if (fields[sqlColumnNumber].Get().empty() && oldDataValue) + { + *reinterpret_cast(&dataValue[dataOffset]) = *reinterpret_cast(&oldDataValue[dataOffset]); + } + else + { + *reinterpret_cast(&dataValue[dataOffset]) = CloneStringToPool(fields[sqlColumnNumber].Get()); + } dataOffset += sizeof(char*); break; case FT_SORT: diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h index 4e7e8ca2c..98ddad98d 100644 --- a/src/server/shared/DataStores/DBCStructure.h +++ b/src/server/shared/DataStores/DBCStructure.h @@ -628,6 +628,33 @@ struct CharStartOutfitEntry //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 53-76 not required at server side }; +enum CharSectionFlags +{ + SECTION_FLAG_PLAYER = 0x01, + SECTION_FLAG_DEATH_KNIGHT = 0x04 +}; + +enum CharSectionType +{ + SECTION_TYPE_SKIN = 0, + SECTION_TYPE_FACE = 1, + SECTION_TYPE_FACIAL_HAIR = 2, + SECTION_TYPE_HAIR = 3, + SECTION_TYPE_UNDERWEAR = 4 +}; + +struct CharSectionsEntry +{ + //uint32 Id; + uint32 Race; + uint32 Gender; + uint32 GenType; + //char* TexturePath[3]; + uint32 Flags; + uint32 Type; + uint32 Color; +}; + struct CharTitlesEntry { uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId() @@ -903,6 +930,15 @@ struct EmotesTextEntry uint32 textid; }; +struct EmotesTextSoundEntry +{ + uint32 Id; // 0 + uint32 EmotesTextId; // 1 + uint32 RaceId; // 2 + uint32 SexId; // 3, 0 male / 1 female + uint32 SoundId; // 4 +}; + struct FactionEntry { uint32 ID; // 0 m_ID diff --git a/src/server/shared/DataStores/DBCfmt.h b/src/server/shared/DataStores/DBCfmt.h index 9a568d5bb..b87dddb52 100644 --- a/src/server/shared/DataStores/DBCfmt.h +++ b/src/server/shared/DataStores/DBCfmt.h @@ -29,6 +29,7 @@ char constexpr BankBagSlotPricesEntryfmt[] = "ni"; char constexpr BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii"; char constexpr BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx"; char constexpr CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char constexpr CharSectionsEntryfmt[] = "diiixxxiii"; char constexpr CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi"; char constexpr ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; // ChatChannelsEntryfmt, index not used (more compact store) char constexpr ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; @@ -48,6 +49,7 @@ char constexpr DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; char constexpr DurabilityQualityfmt[] = "nf"; char constexpr EmotesEntryfmt[] = "nxxiiix"; char constexpr EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx"; +char constexpr EmotesTextSoundEntryfmt[] = "niiii"; char constexpr FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx"; char constexpr FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; char constexpr GameObjectArtKitfmt[] = "nxxxxxxx"; diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index b5a979dea..527d5ae7b 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -1378,7 +1378,7 @@ enum Mechanics : uint32 (1<