diff --git a/.github/workflows/build_dbimport.yml b/.github/workflows/build_dbimport.yml index 7f8a1696b..34b8f4988 100644 --- a/.github/workflows/build_dbimport.yml +++ b/.github/workflows/build_dbimport.yml @@ -23,7 +23,7 @@ jobs: COMPILER: ${{ matrix.compiler }} if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache uses: actions/cache@v3 env: diff --git a/.github/workflows/check_pending_sql.yml b/.github/workflows/check_pending_sql.yml index df0dca4f0..f75913bb0 100644 --- a/.github/workflows/check_pending_sql.yml +++ b/.github/workflows/check_pending_sql.yml @@ -6,6 +6,6 @@ jobs: check-pending-sql: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Check pending SQL run: source ./apps/ci/ci-pending.sh diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 3dd61eb44..910cd6e49 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -11,6 +11,6 @@ jobs: runs-on: ${{ matrix.os }} name: check codestyle steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Check core codestyle run: source ./apps/ci/ci-codestyle.sh diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index 53135ab89..b068a80ba 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -23,9 +23,9 @@ jobs: COMPILER: ${{ matrix.compiler }} if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: var/ccache key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ github.sha }} diff --git a/.github/workflows/core_matrix_build.yml b/.github/workflows/core_matrix_build.yml index e0f6e40ac..9dc0595af 100644 --- a/.github/workflows/core_matrix_build.yml +++ b/.github/workflows/core_matrix_build.yml @@ -40,9 +40,9 @@ jobs: || github.event.label.name == 'run-build') ) steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: var/ccache key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ github.sha }} diff --git a/.github/workflows/core_modules_build.yml b/.github/workflows/core_modules_build.yml index 6f50e7306..0997b0b53 100644 --- a/.github/workflows/core_modules_build.yml +++ b/.github/workflows/core_modules_build.yml @@ -34,12 +34,12 @@ jobs: || github.event.label.name == 'run-build') ) steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Checkout modules run: ./apps/ci/ci-install-modules.sh if: matrix.modules == 'with' - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: var/ccache key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ matrix.modules }}-modules:${{ github.ref }}:${{ github.sha }} diff --git a/.github/workflows/cpp-check.yml b/.github/workflows/cpp-check.yml index d5c95a313..b29cb4816 100644 --- a/.github/workflows/cpp-check.yml +++ b/.github/workflows/cpp-check.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-22.04 name: cpp check steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: cpp check run: | sudo apt update -y diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 238102b70..70e658685 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -124,7 +124,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: var/docker/ccache key: ccache:${{ matrix.os }}:clang:without-modules:${{ github.ref }}:${{ github.sha }} diff --git a/.github/workflows/import_pending.yml b/.github/workflows/import_pending.yml index c9a7ffaaf..80f3d7c5e 100644 --- a/.github/workflows/import_pending.yml +++ b/.github/workflows/import_pending.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: persist-credentials: false - name: Extract branch name diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index 984fe9132..63ac5f983 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -25,9 +25,9 @@ jobs: && !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@v2 + - uses: actions/checkout@v3 - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/Library/Caches/ccache key: ccache:${{ matrix.os }}:${{ github.ref }}:${{ github.sha }} diff --git a/.github/workflows/tools_build.yml b/.github/workflows/tools_build.yml index 242dea748..944e2a38e 100644 --- a/.github/workflows/tools_build.yml +++ b/.github/workflows/tools_build.yml @@ -23,7 +23,7 @@ jobs: COMPILER: ${{ matrix.compiler }} if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache uses: actions/cache@v3 env: diff --git a/.github/workflows/windows_build.yml b/.github/workflows/windows_build.yml index 83a028e98..22f09f5c3 100644 --- a/.github/workflows/windows_build.yml +++ b/.github/workflows/windows_build.yml @@ -25,7 +25,9 @@ jobs: && !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@v2 + - uses: actions/checkout@v3 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.9 - name: Configure OS shell: bash env: @@ -40,6 +42,10 @@ jobs: run: | export CTOOLS_BUILD=all ./acore.sh compiler build + - name: Copy dll files + shell: bash + run: | + cp "/c/Program Files/OpenSSL/bin/legacy.dll" "env/dist" - name: Dry run authserver shell: bash run: | diff --git a/apps/ci/mac/ci-compile.sh b/apps/ci/mac/ci-compile.sh index d0d04faa3..6866acf8b 100755 --- a/apps/ci/mac/ci-compile.sh +++ b/apps/ci/mac/ci-compile.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -export OPENSSL_ROOT_DIR=$(brew --prefix openssl@1.1) +export OPENSSL_ROOT_DIR=$(brew --prefix openssl@3) export CCACHE_CPP2=true export CCACHE_MAXSIZE='500M' diff --git a/apps/installer/includes/os_configs/osx.sh b/apps/installer/includes/os_configs/osx.sh index d94e62f14..d3f762f57 100644 --- a/apps/installer/includes/os_configs/osx.sh +++ b/apps/installer/includes/os_configs/osx.sh @@ -26,4 +26,4 @@ if ! command -v cmake &>/dev/null ; then fi ########################################## -brew install openssl@1.1 readline boost bash-completion curl unzip mysql ccache +brew install openssl@3 readline boost bash-completion curl unzip mysql ccache diff --git a/data/sql/updates/db_world/2023_07_26_00.sql b/data/sql/updates/db_world/2023_07_26_00.sql new file mode 100644 index 000000000..d9613ed86 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_26_00.sql @@ -0,0 +1,2 @@ +-- DB update 2023_07_24_00 -> 2023_07_26_00 +UPDATE `spell_proc_event` SET `procFlags` = 4 WHERE `entry` = 23689; diff --git a/data/sql/updates/db_world/2023_07_26_01.sql b/data/sql/updates/db_world/2023_07_26_01.sql new file mode 100644 index 000000000..591ab3110 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_26_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_07_26_00 -> 2023_07_26_01 +-- +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 17671) AND (`source_type` = 0) AND (`id` IN (4)); diff --git a/data/sql/updates/db_world/2023_07_26_02.sql b/data/sql/updates/db_world/2023_07_26_02.sql new file mode 100644 index 000000000..3f1f53e99 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_26_02.sql @@ -0,0 +1,46 @@ +-- DB update 2023_07_26_01 -> 2023_07_26_02 +-- +UPDATE `item_template` SET `spellcooldown_1` = -1 WHERE (`entry` = 37111); +UPDATE `item_template` SET `spellcooldown_1` = -1, `spellcategorycooldown_1` = 2000 WHERE (`entry` = 47477); +UPDATE `item_template` SET `spellcooldown_1` = -1, `spellcategorycooldown_1` = 2000 WHERE (`entry` = 47316); +UPDATE `item_template` SET `spellcooldown_1` = -1, `spellcooldown_2` = -1, `spellcooldown_3` = -1 WHERE (`entry` = 45507); +UPDATE `item_template` SET `spellcooldown_2` = -1, `spellcooldown_3` = -1 WHERE (`entry` = 45522); +UPDATE `item_template` SET `spellcooldown_2` = -1, `spellcooldown_3` = -1 WHERE (`entry` = 45929); +UPDATE `item_template` SET `spellcooldown_2` = -1, `spellcooldown_3` = -1 WHERE (`entry` = 45931); +UPDATE `item_template` SET `spelltrigger_2` = 0, `spellcooldown_2` = -1, `spellcooldown_3` = -1 WHERE (`entry` = 45866); +UPDATE `item_template` SET `spellcooldown_1` = -1, `spellcategorycooldown_1` = 45000 WHERE (`entry` = 40255); +UPDATE `item_template` SET `spellcooldown_1` = -1 WHERE (`entry` = 40373); +UPDATE `item_template` SET `spellcooldown_1` = 0, `spellcategorycooldown_1` = -1 WHERE (`entry` = 37835); +UPDATE `item_template` SET `spellcooldown_1` = 0, `spellcategorycooldown_1` = -1 WHERE (`entry` = 39229); +UPDATE `item_template` SET `spellcooldown_1` = 0 WHERE (`entry` = 37390); +UPDATE `item_template` SET `spellcooldown_1` = 0 WHERE (`entry` = 37657); +UPDATE `item_template` SET `spellcooldown_1` = 0 WHERE (`entry` = 37660); + +UPDATE `item_template` SET `spellppmRate_1` = 0 WHERE (`entry` = 50348); +UPDATE `item_template` SET `spellppmRate_1` = 0 WHERE (`entry` = 50353); +UPDATE `item_template` SET `spellppmRate_1` = 0 WHERE (`entry` = 54588); + +UPDATE `spell_proc_event` SET `CustomChance` = 45 WHERE `entry` = 71545; +UPDATE `spell_proc_event` SET `CustomChance` = 35 WHERE `entry` = 71562; + +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 71585; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 64738; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 64792; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 62114; +UPDATE `spell_proc_event` SET `Cooldown` = 45000 WHERE `entry` = 58901; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 33648; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 49622; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 65013; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 65002; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 62115; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 67672; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 33648; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 60221; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 60519; +UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 63251; + +DELETE FROM `spell_proc_event` WHERE `entry` IN (75474, 71602, 64764); +INSERT INTO `spell_proc_event` (`entry`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `procFlags`, `procEx`, `procPhase`, `ppmRate`, `CustomChance`, `Cooldown`) VALUES +(75474,0,0,0,0,0,0,0,0,0,0,50000), +(64764,0,0,0,0,0,0,0,0,0,0,50000), +(71602,0,0,0,0,0,0,0,0,0,0,45000); diff --git a/data/sql/updates/db_world/2023_07_26_03.sql b/data/sql/updates/db_world/2023_07_26_03.sql new file mode 100644 index 000000000..5063ce6ca --- /dev/null +++ b/data/sql/updates/db_world/2023_07_26_03.sql @@ -0,0 +1,4 @@ +-- DB update 2023_07_26_02 -> 2023_07_26_03 +-- +DELETE FROM `areatrigger_teleport` WHERE `ID` = 2068; +INSERT INTO `areatrigger_teleport` (`ID`, `Name`, `target_map`, `target_position_x`, `target_position_y`, `target_position_z`, `target_orientation`) VALUES (2068, 'Blackrock Spire - Jump Exit', 0, -7558.39, -1309.43, 248.454, 1.5708); diff --git a/data/sql/updates/db_world/2023_07_26_04.sql b/data/sql/updates/db_world/2023_07_26_04.sql new file mode 100644 index 000000000..a6f3efd06 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_26_04.sql @@ -0,0 +1,5 @@ +-- DB update 2023_07_26_03 -> 2023_07_26_04 +-- +UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 12298; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 12298) AND (`source_type` = 0); diff --git a/data/sql/updates/db_world/2023_07_27_00.sql b/data/sql/updates/db_world/2023_07_27_00.sql new file mode 100644 index 000000000..86153162c --- /dev/null +++ b/data/sql/updates/db_world/2023_07_27_00.sql @@ -0,0 +1,29 @@ +-- DB update 2023_07_26_04 -> 2023_07_27_00 +-- path of Garn Mathers +SET @NPC := 30758 * 10; -- Garn mathers GUID * 10 +DELETE FROM `waypoint_data` WHERE `id` = @NPC; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`) VALUES +(@NPC, 1, -3050.0679, -4329.487, 8.319094, 0), +(@NPC, 2, -3044.8179, -4326.487, 7.819094, 0), +(@NPC, 3, -3036.245, -4321.0723, 7.388595, 0), +(@NPC, 4, -3023.495, -4328.3223, 7.888595, 0), +(@NPC, 5, -3007.757, -4334.8223, 6.9061613, 0), +(@NPC, 6, -2997.757, -4344.0723, 6.6561613, 0), +(@NPC, 7, -2981.6763, -4353.217, 8.946001, 0), +(@NPC, 8, -2970.2686, -4358.55, 10.112873, 0), +(@NPC, 9, -2972.253, -4368.476, 9.980476, 0), +(@NPC, 10, -2983.7305, -4381.0786, 10.497398, 0), +(@NPC, 11, -3000.9695, -4383.346, 10.6955185, 0), +(@NPC, 12, -3011.9897, -4373.612, 9.795075, 0), +(@NPC, 13, -3023.2007, -4366.656, 10.3360815, 0), +(@NPC, 14, -3026.9507, -4364.906, 10.0860815, 0), +(@NPC, 15, -3040.5425, -4358.04, 8.381775, 0), +(@NPC, 16, -3048.0571, -4343.4937, 8.053871, 0); + +DELETE FROM `creature` WHERE `id1` = 23679 AND `guid` = 30758; +INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES +(30758, 23679, 0, 0, 1, 0, 0, 1, 1, 1, -3050.214, -4329.639, 8.156482, 1.730132341384887695, 180, 0, 0, 1536, 0, 2, 0, 0, 0, '', 50375); + +DELETE FROM `creature_addon` WHERE `guid` = 30758; +INSERT INTO `creature_addon` (`guid`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES +(30758, @NPC, 0, 0, 1, 0, 0, ''); diff --git a/data/sql/updates/db_world/2023_07_27_01.sql b/data/sql/updates/db_world/2023_07_27_01.sql new file mode 100644 index 000000000..b7d3cc54e --- /dev/null +++ b/data/sql/updates/db_world/2023_07_27_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_07_27_00 -> 2023_07_27_01 +-- +UPDATE `creature_template` SET `ScriptName`='npc_crashin_thrashin_robot' WHERE `entry`=17299; diff --git a/data/sql/updates/db_world/2023_07_27_02.sql b/data/sql/updates/db_world/2023_07_27_02.sql new file mode 100644 index 000000000..ddbac2816 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_27_02.sql @@ -0,0 +1,5 @@ +-- DB update 2023_07_27_01 -> 2023_07_27_02 +-- +DELETE FROM `spell_linked_spell` WHERE `spell_trigger` = 29683 AND `spell_effect` = 32214; +INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES +(29683, 32214, 0, "Spotlight 20% player buff"); diff --git a/data/sql/updates/db_world/2023_07_27_03.sql b/data/sql/updates/db_world/2023_07_27_03.sql new file mode 100644 index 000000000..368b6fab3 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_27_03.sql @@ -0,0 +1,4 @@ +-- DB update 2023_07_27_02 -> 2023_07_27_03 +-- +UPDATE `creature` SET `wander_distance` = 0, `MovementType` = 0 WHERE `guid` = 15542; + diff --git a/data/sql/updates/db_world/2023_07_27_04.sql b/data/sql/updates/db_world/2023_07_27_04.sql new file mode 100644 index 000000000..f4c6251ad --- /dev/null +++ b/data/sql/updates/db_world/2023_07_27_04.sql @@ -0,0 +1,6 @@ +-- DB update 2023_07_27_03 -> 2023_07_27_04 +-- +DELETE FROM `smart_scripts` WHERE `entryorguid` = 17157 AND `source_type` = 0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `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 +(17157, 0, 0, 0, 0, 0, 100, 0, 9600, 12900, 30600, 43600, 0, 11, 33840, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Shattered Rumbler - In Combat - Cast \'Earth Rumble\' '), +(17157, 0, 1, 0, 8, 0, 100, 513, 32001, 0, 0, 0, 0, 80, 1715700, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shattered Rumbler - On Spellhit \'Throw Gordawg\'s Boulder\' - Run Script (No Repeat)'); diff --git a/data/sql/updates/db_world/2023_07_27_05.sql b/data/sql/updates/db_world/2023_07_27_05.sql new file mode 100644 index 000000000..50e340f12 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_27_05.sql @@ -0,0 +1,4 @@ +-- DB update 2023_07_27_04 -> 2023_07_27_05 +-- +DELETE FROM `smart_scripts` WHERE `entryorguid` = 94 AND `source_type` = 0; +UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 94; diff --git a/data/sql/updates/db_world/2023_07_28_00.sql b/data/sql/updates/db_world/2023_07_28_00.sql new file mode 100644 index 000000000..2692faaa8 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_28_00.sql @@ -0,0 +1,3 @@ +-- DB update 2023_07_27_05 -> 2023_07_28_00 +-- +UPDATE `creature` SET `position_x`=-33.3555, `position_y`=-927.892, `position_z`=54.5261, `orientation`=1.54421, `spawntimesecs`=600, `wander_distance`=1, `MovementType`=1, `VerifiedBuild`=50375 WHERE `guid`=15542; diff --git a/data/sql/updates/db_world/2023_07_29_00.sql b/data/sql/updates/db_world/2023_07_29_00.sql new file mode 100644 index 000000000..b1bb6e3f2 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_29_00.sql @@ -0,0 +1,4 @@ +-- DB update 2023_07_28_00 -> 2023_07_29_00 +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 38048; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES (38048, 'spell_gen_curse_of_pain'); diff --git a/data/sql/updates/db_world/2023_07_29_01.sql b/data/sql/updates/db_world/2023_07_29_01.sql new file mode 100644 index 000000000..92e865598 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_29_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_07_29_00 -> 2023_07_29_01 +-- +UPDATE `creature_model_info` SET `BoundingRadius`=9, `CombatReach`=15.75 WHERE `DisplayID`=17887; diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index be7c50cf7..4efa2d5db 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -1563,6 +1563,14 @@ AllowTwoSide.Interaction.Group = 0 AllowTwoSide.Interaction.Guild = 0 +# +# AllowTwoSide.Interaction.Arena +# Description: Allow joining arena teams between factions. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AllowTwoSide.Interaction.Arena = 0 + # # AllowTwoSide.Interaction.Auction # Description: Allow auctions between factions. diff --git a/src/server/game/Battlegrounds/Arena.cpp b/src/server/game/Battlegrounds/Arena.cpp index dfb84271d..bfc27f00d 100644 --- a/src/server/game/Battlegrounds/Arena.cpp +++ b/src/server/game/Battlegrounds/Arena.cpp @@ -17,6 +17,7 @@ #include "Arena.h" #include "ArenaTeamMgr.h" +#include "GroupMgr.h" #include "Log.h" #include "ObjectAccessor.h" #include "Player.h" @@ -93,6 +94,47 @@ void Arena::AddPlayer(Player* player) } UpdateArenaWorldState(); + + Group* group = player->GetGroup(); + if (group) + { + // Hackfix for crossfaction arenas, recreate group when joining + // Without this, players in a crossfaction arena group would not be able to cast beneficial spells on their teammates + + std::vector members; + bool isCrossfaction = false; + for (Group::member_citerator mitr = group->GetMemberSlots().begin(); mitr != group->GetMemberSlots().end(); ++mitr) + { + Player* member = ObjectAccessor::FindPlayer(mitr->guid); + if (!member || member->GetGUID() == player->GetGUID()) + { + continue; + } + members.push_back(member); + if (member->GetTeamId(true) != player->GetTeamId(true)) + { + isCrossfaction = true; + } + } + + if (isCrossfaction) + { + for (Player* member : members) + { + member->RemoveFromGroup(); + } + group->Disband(); + + group = new Group(); + SetBgRaid(player->GetBgTeamId(), group); + group->Create(player); + sGroupMgr->AddGroup(group); + for (Player* member : members) + { + group->AddMember(member); + } + } + } } void Arena::RemovePlayer(Player* /*player*/) diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp index 98455adfd..e48b6bbbf 100644 --- a/src/server/game/Handlers/ArenaTeamHandler.cpp +++ b/src/server/game/Handlers/ArenaTeamHandler.cpp @@ -133,7 +133,7 @@ void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket& recvData) if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUID())) return; - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeamId() != GetPlayer()->GetTeamId()) + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA) && player->GetTeamId() != GetPlayer()->GetTeamId()) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); return; @@ -185,7 +185,7 @@ void WorldSession::HandleArenaTeamAcceptOpcode(WorldPacket& /*recvData*/) } // Only allow members of the other faction to join the team if cross faction interaction is enabled - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeamId() != sCharacterCache->GetCharacterTeamByGuid(arenaTeam->GetCaptain())) + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA) && _player->GetTeamId() != sCharacterCache->GetCharacterTeamByGuid(arenaTeam->GetCaptain())) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED); return; diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index 50a29c1be..ec5c3ae92 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -414,18 +414,14 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData) if (!signatures) return; - // not let enemies sign guild charter - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeamId() != sCharacterCache->GetCharacterTeamByGuid(petition->ownerGuid)) - { - if (type != GUILD_CHARTER_TYPE) - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - else - Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); - return; - } - if (type != GUILD_CHARTER_TYPE) { + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA) && GetPlayer()->GetTeamId() != sCharacterCache->GetCharacterTeamByGuid(petition->ownerGuid)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + return; + } + if (_player->GetLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName().c_str(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); @@ -450,6 +446,12 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData) } else { + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeamId() != sCharacterCache->GetCharacterTeamByGuid(petition->ownerGuid)) + { + Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); + return; + } + if (_player->GetGuildId()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, _player->GetName()); @@ -567,17 +569,14 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket& recvData) if (!petition) return; - if (GetPlayer()->GetTeamId() != player->GetTeamId()) - { - if (petition->petitionType != GUILD_CHARTER_TYPE) - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - else - Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); - return; - } - if (petition->petitionType != GUILD_CHARTER_TYPE) { + if (GetPlayer()->GetTeamId() != player->GetTeamId() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + return; + } + if (player->GetLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { // player is too low level to join an arena team @@ -604,6 +603,12 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket& recvData) } else { + if (GetPlayer()->GetTeamId() != player->GetTeamId() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) + { + Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); + return; + } + if (player->GetGuildId()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, _player->GetName()); diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index 784a1168d..06e5dd520 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -79,6 +79,7 @@ enum WorldBoolConfigs CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL, CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP, CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD, + CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA, CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION, CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL, CONFIG_ALLOW_TWO_SIDE_WHO_LIST, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 8ac213c6e..74ef94fa2 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -731,6 +731,7 @@ void World::LoadConfigSettings(bool reload) _bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfigMgr->GetOption("AllowTwoSide.Interaction.Channel", false); _bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfigMgr->GetOption("AllowTwoSide.Interaction.Group", false); _bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfigMgr->GetOption("AllowTwoSide.Interaction.Guild", false); + _bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_ARENA] = sConfigMgr->GetOption("AllowTwoSide.Interaction.Arena", false); _bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfigMgr->GetOption("AllowTwoSide.Interaction.Auction", false); _bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = sConfigMgr->GetOption("AllowTwoSide.Interaction.Mail", false); _bool_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfigMgr->GetOption("AllowTwoSide.WhoList", false); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp index c78c7fa7c..13778decd 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp @@ -121,8 +121,6 @@ struct boss_moroes : public BossAI context.Repeat(5s); }).Schedule(1min, 2min, GROUP_PRECOMBAT_TALK, [this](TaskContext context) { - //this was not scheduled in the previous commit - //does this have to be removed? Talk(SAY_OUT_OF_COMBAT); context.Repeat(1min, 2min); }); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp index 9625e2303..a86c05a0c 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp @@ -15,13 +15,6 @@ * with this program. If not, see . */ -/* ScriptData -SDName: Boss_Netherspite -SD%Complete: 90 -SDComment: Not sure about timing and portals placing -SDCategory: Karazhan -EndScriptData */ - #include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -29,19 +22,35 @@ EndScriptData */ #include "SpellAuraEffects.h" #include "SpellScript.h" -enum Netherspite +enum Emotes { - EMOTE_PHASE_PORTAL = 0, - EMOTE_PHASE_BANISH = 1, + EMOTE_PHASE_PORTAL = 0, + EMOTE_PHASE_BANISH = 1 +}; - SPELL_NETHERBURN_AURA = 30522, - SPELL_VOIDZONE = 37063, - SPELL_NETHER_INFUSION = 38688, - SPELL_NETHERBREATH = 38523, - SPELL_BANISH_VISUAL = 39833, - SPELL_BANISH_ROOT = 42716, - SPELL_EMPOWERMENT = 38549, - SPELL_NETHERSPITE_ROAR = 38684, +enum Spells +{ + SPELL_NETHERBURN_AURA = 30522, + SPELL_VOIDZONE = 37063, + SPELL_NETHER_INFUSION = 38688, + SPELL_NETHERBREATH = 38523, + SPELL_BANISH_VISUAL = 39833, + SPELL_BANISH_ROOT = 42716, + SPELL_EMPOWERMENT = 38549, + SPELL_NETHERSPITE_ROAR = 38684 +}; + +enum Portals +{ + RED_PORTAL = 0, // Perseverence + GREEN_PORTAL = 1, // Serenity + BLUE_PORTAL = 2 // Dominance +}; + +enum Groups +{ + PORTAL_PHASE = 0, + VANISH_PHASE = 1 }; const float PortalCoord[3][3] = @@ -51,302 +60,255 @@ const float PortalCoord[3][3] = {-11094.493164f, -1591.969238f, 279.949188f} // Back side }; -enum Netherspite_Portal -{ - RED_PORTAL = 0, // Perseverence - GREEN_PORTAL = 1, // Serenity - BLUE_PORTAL = 2 // Dominance -}; - -const uint32 PortalID[3] = {17369, 17367, 17368}; +const uint32 PortalID[3] = {17369, 17367, 17368}; const uint32 PortalVisual[3] = {30487, 30490, 30491}; -const uint32 PortalBeam[3] = {30465, 30464, 30463}; -const uint32 PlayerBuff[3] = {30421, 30422, 30423}; -const uint32 NetherBuff[3] = {30466, 30467, 30468}; +const uint32 PortalBeam[3] = {30465, 30464, 30463}; +const uint32 PlayerBuff[3] = {30421, 30422, 30423}; +const uint32 NetherBuff[3] = {30466, 30467, 30468}; const uint32 PlayerDebuff[3] = {38637, 38638, 38639}; -class boss_netherspite : public CreatureScript +struct boss_netherspite : public BossAI { -public: - boss_netherspite() : CreatureScript("boss_netherspite") { } + boss_netherspite(Creature* creature) : BossAI(creature, DATA_NETHERSPITE) {} - CreatureAI* GetAI(Creature* creature) const override + bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker { - return GetKarazhanAI(creature); + if (!u1 || !u2 || !target) + return false; + + float xn, yn, xp, yp, xh, yh; + xn = u1->GetPositionX(); + yn = u1->GetPositionY(); + xp = u2->GetPositionX(); + yp = u2->GetPositionY(); + xh = target->GetPositionX(); + yh = target->GetPositionY(); + + // check if target is between (not checking distance from the beam yet) + if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp)) + return false; + // check distance from the beam + return (std::abs((xn - xp) * yh + (yp - yn) * xh - xn * yp + xp * yn) / dist(xn, yn, xp, yp) < 1.5f); } - struct boss_netherspiteAI : public ScriptedAI + float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance { - boss_netherspiteAI(Creature* creature) : ScriptedAI(creature) + return std::sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb)); + } + + void Reset() override + { + BossAI::Reset(); + berserk = false; + HandleDoors(true); + DestroyPortals(); + } + + void SummonPortals() + { + uint8 r = rand() % 4; + uint8 pos[3]; + pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0); + pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1)); + pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0) + for (int i = 0; i < 3; ++i) { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - bool PortalPhase; - bool Berserk; - uint32 PhaseTimer; // timer for phase switching - uint32 VoidZoneTimer; - uint32 NetherInfusionTimer; // berserking timer - uint32 NetherbreathTimer; - uint32 EmpowermentTimer; - uint32 PortalTimer; // timer for beam checking - ObjectGuid PortalGUID[3]; // guid's of portals - ObjectGuid BeamerGUID[3]; // guid's of auxiliary beaming portals - ObjectGuid BeamTarget[3]; // guid's of portals' current targets - - bool IsBetween(WorldObject* u1, WorldObject* target, WorldObject* u2) // the in-line checker - { - if (!u1 || !u2 || !target) - return false; - - float xn, yn, xp, yp, xh, yh; - xn = u1->GetPositionX(); - yn = u1->GetPositionY(); - xp = u2->GetPositionX(); - yp = u2->GetPositionY(); - xh = target->GetPositionX(); - yh = target->GetPositionY(); - - // check if target is between (not checking distance from the beam yet) - if (dist(xn, yn, xh, yh) >= dist(xn, yn, xp, yp) || dist(xp, yp, xh, yh) >= dist(xn, yn, xp, yp)) - return false; - // check distance from the beam - return (std::abs((xn - xp) * yh + (yp - yn) * xh - xn * yp + xp * yn) / dist(xn, yn, xp, yp) < 1.5f); - } - - float dist(float xa, float ya, float xb, float yb) // auxiliary method for distance - { - return std::sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb)); - } - - void Reset() override - { - Berserk = false; - NetherInfusionTimer = 540000; - VoidZoneTimer = 15000; - NetherbreathTimer = 3000; - - HandleDoors(true); - DestroyPortals(); - } - - void SummonPortals() - { - uint8 r = rand() % 4; - uint8 pos[3]; - pos[RED_PORTAL] = ((r % 2) ? (r > 1 ? 2 : 1) : 0); - pos[GREEN_PORTAL] = ((r % 2) ? 0 : (r > 1 ? 2 : 1)); - pos[BLUE_PORTAL] = (r > 1 ? 1 : 2); // Blue Portal not on the left side (0) - - for (int i = 0; i < 3; ++i) - if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TEMPSUMMON_TIMED_DESPAWN, 60000)) - { - PortalGUID[i] = portal->GetGUID(); - portal->AddAura(PortalVisual[i], portal); - } - } - - void DestroyPortals() - { - for (int i = 0; i < 3; ++i) + if (Creature* portal = me->SummonCreature(PortalID[i], PortalCoord[pos[i]][0], PortalCoord[pos[i]][1], PortalCoord[pos[i]][2], 0, TEMPSUMMON_TIMED_DESPAWN, 60000)) { - if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i])) - portal->DisappearAndDie(); - if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i])) - portal->DisappearAndDie(); - PortalGUID[i].Clear(); - BeamTarget[i].Clear(); + PortalGUID[i] = portal->GetGUID(); + portal->AddAura(PortalVisual[i], portal); } } + } - void UpdatePortals() // Here we handle the beams' behavior + void DestroyPortals() + { + for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) // j = color - if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[j])) + if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i])) + { + portal->DisappearAndDie(); + } + if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i])) + { + portal->DisappearAndDie(); + } + PortalGUID[i].Clear(); + BeamTarget[i].Clear(); + } + } + + void UpdatePortals() // Here we handle the beams' behavior + { + for (int j = 0; j < 3; ++j) // j = color + { + if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[j])) + { + // the one who's been cast upon before + Unit* current = ObjectAccessor::GetUnit(*portal, BeamTarget[j]); + // temporary store for the best suitable beam reciever + Unit* target = me; + + if (Map* map = me->GetMap()) { - // the one who's been cast upon before - Unit* current = ObjectAccessor::GetUnit(*portal, BeamTarget[j]); - // temporary store for the best suitable beam reciever - Unit* target = me; + Map::PlayerList const& players = map->GetPlayers(); - if (Map* map = me->GetMap()) + // get the best suitable target + for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) { - Map::PlayerList const& players = map->GetPlayers(); - - // get the best suitable target - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - { - Player* p = i->GetSource(); - if (p && p->IsAlive() // alive - && (!target || target->GetDistance2d(portal) > p->GetDistance2d(portal)) // closer than current best - && !p->HasAura(PlayerDebuff[j]) // not exhausted - && !p->HasAura(PlayerBuff[(j + 1) % 3]) // not on another beam - && !p->HasAura(PlayerBuff[(j + 2) % 3]) - && IsBetween(me, p, portal)) // on the beam - target = p; - } + Player* p = i->GetSource(); + if (p && p->IsAlive() // alive + && (!target || target->GetDistance2d(portal) > p->GetDistance2d(portal)) // closer than current best + && !p->HasAura(PlayerDebuff[j]) // not exhausted + && !p->HasAura(PlayerBuff[(j + 1) % 3]) // not on another beam + && !p->HasAura(PlayerBuff[(j + 2) % 3]) + && IsBetween(me, p, portal)) // on the beam + target = p; } - // buff the target - if (target->GetTypeId() == TYPEID_PLAYER) - target->AddAura(PlayerBuff[j], target); - else - target->AddAura(NetherBuff[j], target); - // cast visual beam on the chosen target if switched - // simple target switching isn't working -> using BeamerGUID to cast (workaround) - if (!current || target != current) - { - BeamTarget[j] = target->GetGUID(); - // remove currently beaming portal - if (Creature* beamer = ObjectAccessor::GetCreature(*portal, BeamerGUID[j])) - { - beamer->CastSpell(target, PortalBeam[j], false); - beamer->DisappearAndDie(); - BeamerGUID[j].Clear(); - } - // create new one and start beaming on the target - if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 60000)) - { - beamer->CastSpell(target, PortalBeam[j], false); - BeamerGUID[j] = beamer->GetGUID(); - } - } - // aggro target if Red Beam - if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TYPEID_PLAYER) - me->GetThreatMgr().AddThreat(target, 100000.0f + DoGetThreat(me->GetVictim())); } + // buff the target + if (target->GetTypeId() == TYPEID_PLAYER) + { + target->AddAura(PlayerBuff[j], target); + } + else + { + target->AddAura(NetherBuff[j], target); + } + // cast visual beam on the chosen target if switched + // simple target switching isn't working -> using BeamerGUID to cast (workaround) + if (!current || target != current) + { + BeamTarget[j] = target->GetGUID(); + // remove currently beaming portal + if (Creature* beamer = ObjectAccessor::GetCreature(*portal, BeamerGUID[j])) + { + beamer->CastSpell(target, PortalBeam[j], false); + beamer->DisappearAndDie(); + BeamerGUID[j].Clear(); + } + // create new one and start beaming on the target + if (Creature* beamer = portal->SummonCreature(PortalID[j], portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), portal->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 60000)) + { + beamer->CastSpell(target, PortalBeam[j], false); + BeamerGUID[j] = beamer->GetGUID(); + } + } + // aggro target if Red Beam + if (j == RED_PORTAL && me->GetVictim() != target && target->GetTypeId() == TYPEID_PLAYER) + { + me->GetThreatMgr().AddThreat(target, 100000.0f + DoGetThreat(me->GetVictim())); + } + } } + } - void SwitchToPortalPhase() + void SwitchToPortalPhase() + { + scheduler.CancelGroup(VANISH_PHASE); + me->RemoveAurasDueToSpell(SPELL_BANISH_ROOT); + me->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL); + SummonPortals(); + scheduler.Schedule(60s, [this](TaskContext /*context*/) { - me->RemoveAurasDueToSpell(SPELL_BANISH_ROOT); - me->RemoveAurasDueToSpell(SPELL_BANISH_VISUAL); - SummonPortals(); - PhaseTimer = 60000; - PortalPhase = true; - PortalTimer = 10000; - EmpowermentTimer = 10000; - Talk(EMOTE_PHASE_PORTAL); - } - - void SwitchToBanishPhase() - { - me->RemoveAurasDueToSpell(SPELL_EMPOWERMENT); - me->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA); - DoCast(me, SPELL_BANISH_VISUAL, true); - DoCast(me, SPELL_BANISH_ROOT, true); - DestroyPortals(); - PhaseTimer = 30000; - PortalPhase = false; - Talk(EMOTE_PHASE_BANISH); - - for (uint8 i = 0; i < 3; ++i) - me->RemoveAurasDueToSpell(NetherBuff[i]); - } - - void HandleDoors(bool open) // Massive Door switcher - { - if (GameObject* Door = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_GO_MASSIVE_DOOR) )) - Door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY); - } - - void JustEngagedWith(Unit* /*who*/) override - { - HandleDoors(false); - SwitchToPortalPhase(); - DoZoneInCombat(); - } - - void JustDied(Unit* /*killer*/) override - { - HandleDoors(true); - DestroyPortals(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) + if (!me->IsNonMeleeSpellCast(false)) + { + SwitchToBanishPhase(); return; - - // Void Zone - if (VoidZoneTimer <= diff) - { - DoCast(SelectTarget(SelectTargetMethod::Random, 1, 45, true), SPELL_VOIDZONE, true); - VoidZoneTimer = 15000; } - else - VoidZoneTimer -= diff; + }).Schedule(10s, PORTAL_PHASE, [this](TaskContext context) + { + UpdatePortals(); + context.Repeat(1s); + }).Schedule(10s, PORTAL_PHASE, [this](TaskContext context) + { + DoCastSelf(SPELL_EMPOWERMENT); + me->AddAura(SPELL_NETHERBURN_AURA, me); + context.Repeat(90s); + }); + Talk(EMOTE_PHASE_PORTAL); + } - // NetherInfusion Berserk - if (!Berserk && NetherInfusionTimer <= diff) + void SwitchToBanishPhase() + { + scheduler.CancelGroup(PORTAL_PHASE); + me->RemoveAurasDueToSpell(SPELL_EMPOWERMENT); + me->RemoveAurasDueToSpell(SPELL_NETHERBURN_AURA); + DoCastSelf(SPELL_BANISH_VISUAL, true); + DoCastSelf(SPELL_BANISH_ROOT, true); + DestroyPortals(); + scheduler.Schedule(30s, [this](TaskContext /*context*/) + { + if (!me->IsNonMeleeSpellCast(false)) { - me->AddAura(SPELL_NETHER_INFUSION, me); - DoCast(me, SPELL_NETHERSPITE_ROAR); - Berserk = true; + SwitchToPortalPhase(); + return; } - else - NetherInfusionTimer -= diff; - - if (PortalPhase) // PORTAL PHASE - { - // Distribute beams and buffs - if (PortalTimer <= diff) - { - UpdatePortals(); - PortalTimer = 1000; - } - else - PortalTimer -= diff; - - // Empowerment & Nether Burn - if (EmpowermentTimer <= diff) - { - DoCast(me, SPELL_EMPOWERMENT); - me->AddAura(SPELL_NETHERBURN_AURA, me); - EmpowermentTimer = 90000; - } - else - EmpowermentTimer -= diff; - - if (PhaseTimer <= diff) - { - if (!me->IsNonMeleeSpellCast(false)) - { - SwitchToBanishPhase(); - return; - } - } - else - PhaseTimer -= diff; - } - else // BANISH PHASE - { - // Netherbreath - if (NetherbreathTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true)) - DoCast(target, SPELL_NETHERBREATH); - NetherbreathTimer = urand(5000, 7000); - } - else - NetherbreathTimer -= diff; - - if (PhaseTimer <= diff) - { - if (!me->IsNonMeleeSpellCast(false)) - { - SwitchToPortalPhase(); - return; - } - } - else - PhaseTimer -= diff; - } - - DoMeleeAttackIfReady(); + }).Schedule(10s, VANISH_PHASE, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_NETHERBREATH, 0, 40.0f, true); + context.Repeat(5s, 7s); + }); + Talk(EMOTE_PHASE_BANISH); + for (uint8 i = 0; i < 3; ++i) + { + me->RemoveAurasDueToSpell(NetherBuff[i]); } - }; + } + + void HandleDoors(bool open) + { + if (GameObject* door = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_GO_MASSIVE_DOOR))) + { + door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY); + } + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + HandleDoors(false); + SwitchToPortalPhase(); + DoZoneInCombat(); + scheduler.Schedule(15s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_VOIDZONE, 1, 45.0f, true, true); + context.Repeat(15s); + }).Schedule(9min, [this](TaskContext /*context*/) + { + if (!berserk) + { + DoCastSelf(SPELL_NETHER_INFUSION); + DoCastAOE(SPELL_NETHERSPITE_ROAR); + berserk = true; + } + }); + } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + HandleDoors(true); + DestroyPortals(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); + } + +private: + bool berserk; + ObjectGuid PortalGUID[3]; // guid's of portals + ObjectGuid BeamerGUID[3]; // guid's of auxiliary beaming portals + ObjectGuid BeamTarget[3]; // guid's of portals' current targets }; class spell_nether_portal_perseverence : public AuraScript @@ -366,6 +328,6 @@ class spell_nether_portal_perseverence : public AuraScript void AddSC_boss_netherspite() { - new boss_netherspite(); + RegisterKarazhanCreatureAI(boss_netherspite); RegisterSpellScript(spell_nether_portal_perseverence); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index 9478bf54b..f44a93d7d 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -25,6 +25,7 @@ EndScriptData */ #include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "TaskScheduler.h" #include "karazhan.h" enum Spells @@ -52,6 +53,12 @@ enum Says EMOTE_BREATH = 4 }; +enum Groups +{ + GROUP_GROUND = 0, + GROUP_FLYING = 1 +}; + float IntroWay[8][3] = { {-11053.37f, -1794.48f, 149.00f}, @@ -62,218 +69,270 @@ float IntroWay[8][3] = {-11128.73f, -1929.75f, 125.00f}, {-11140.00f, -1915.00f, 122.00f}, {-11163.00f, -1903.00f, 91.473f} -}; +}; //TODO: move to table -class boss_nightbane : public CreatureScript +struct boss_nightbane : public BossAI { -public: - boss_nightbane() : CreatureScript("boss_nightbane") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_nightbane(Creature* creature) : BossAI(creature, DATA_NIGHTBANE) { - return GetKarazhanAI(creature); + _intro = true; + _skeletonCount = 5; + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - struct boss_nightbaneAI : public ScriptedAI + void Reset() override { - boss_nightbaneAI(Creature* creature) : ScriptedAI(creature) + BossAI::Reset(); + _skeletonscheduler.CancelAll(); + Phase = 1; + MovePhase = 0; + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + me->SetSpeed(MOVE_RUN, 2.0f); + me->SetDisableGravity(_intro); + me->SetWalk(false); + me->setActive(true); + + if (instance) { - instance = creature->GetInstanceScript(); - Intro = true; + if (instance->GetData(DATA_NIGHTBANE) == DONE) + me->DisappearAndDie(); + else + instance->SetData(DATA_NIGHTBANE, NOT_STARTED); } - InstanceScript* instance; + HandleTerraceDoors(true); - uint32 Phase; + _flying = false; + _movement = false; - bool RainBones; - bool Skeletons; - - uint32 BellowingRoarTimer; - uint32 CharredEarthTimer; - uint32 DistractingAshTimer; - uint32 SmolderingBreathTimer; - uint32 TailSweepTimer; - uint32 RainofBonesTimer; - uint32 SmokingBlastTimer; - uint32 FireballBarrageTimer; - uint32 SearingCindersTimer; - - uint32 FlyCount; - uint32 FlyTimer; - - bool Intro; - bool Flying; - bool Movement; - - uint32 MovePhase; - - void Reset() override + if (!_intro) { - BellowingRoarTimer = 30000; - CharredEarthTimer = 15000; - DistractingAshTimer = 20000; - SmolderingBreathTimer = 10000; - TailSweepTimer = 12000; - RainofBonesTimer = 10000; - SmokingBlastTimer = 20000; - FireballBarrageTimer = 13000; - SearingCindersTimer = 14000; - + //when boss is reset and we're past the intro + //cannot despawn, but have to move to a location where he normally is + //me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0); + Position preSpawnPosis = me->GetHomePosition(); + me->NearTeleportTo(preSpawnPosis); + instance->SetData(DATA_NIGHTBANE, NOT_STARTED); + _intro = true; Phase = 1; - FlyCount = 0; MovePhase = 0; + } - me->SetSpeed(MOVE_RUN, 2.0f); - me->SetDisableGravity(Intro); - me->SetWalk(false); - me->setActive(true); + ScheduleHealthCheckEvent({25, 50, 70}, [&]{ + TakeOff(); + }); + } - if (instance) + void HandleTerraceDoors(bool open) + { + if (instance) + { + instance->HandleGameObject(instance->GetGuidData(DATA_MASTERS_TERRACE_DOOR_1), open); + instance->HandleGameObject(instance->GetGuidData(DATA_MASTERS_TERRACE_DOOR_2), open); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + if (instance) + instance->SetData(DATA_NIGHTBANE, IN_PROGRESS); + + HandleTerraceDoors(false); + Talk(YELL_AGGRO); + ScheduleGround(); + } + + void ScheduleGround() { + scheduler.Schedule(30s, GROUP_GROUND, [this](TaskContext context) + { + DoCastAOE(SPELL_BELLOWING_ROAR); + context.Repeat(30s, 40s); + }).Schedule(15s, GROUP_GROUND, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_CHARRED_EARTH, 0, 100.0f, true); + context.Repeat(20s); + }).Schedule(10s, GROUP_GROUND, [this](TaskContext context) + { + DoCastVictim(SPELL_SMOLDERING_BREATH); + context.Repeat(20s); + }).Schedule(12s, GROUP_GROUND, [this](TaskContext context) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) { - if (instance->GetData(DATA_NIGHTBANE) == DONE) - me->DisappearAndDie(); - else - instance->SetData(DATA_NIGHTBANE, NOT_STARTED); - } - - HandleTerraceDoors(true); - - Flying = false; - Movement = false; - - if (!Intro) - { - me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0); - me->GetMotionMaster()->MoveTargetedHome(); - } - } - - void HandleTerraceDoors(bool open) - { - if (instance) - { - instance->HandleGameObject(instance->GetGuidData(DATA_MASTERS_TERRACE_DOOR_1), open); - instance->HandleGameObject(instance->GetGuidData(DATA_MASTERS_TERRACE_DOOR_2), open); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - if (instance) - instance->SetData(DATA_NIGHTBANE, IN_PROGRESS); - - HandleTerraceDoors(false); - Talk(YELL_AGGRO); - } - - void AttackStart(Unit* who) override - { - if (!Intro && !Flying) - ScriptedAI::AttackStart(who); - } - - void JustDied(Unit* /*killer*/) override - { - if (instance) - instance->SetData(DATA_NIGHTBANE, DONE); - - HandleTerraceDoors(true); - } - - void MoveInLineOfSight(Unit* who) override - { - if (!Intro && !Flying) - ScriptedAI::MoveInLineOfSight(who); - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type != POINT_MOTION_TYPE) - return; - - if (Intro) - { - if (id >= 8) + if (!me->HasInArc(M_PI, target)) { - Intro = false; - me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0); - return; + DoCast(target, SPELL_TAIL_SWEEP); } + } + context.Repeat(15s); + }).Schedule(14s, GROUP_GROUND, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_SEARING_CINDERS); + context.Repeat(10s); + }); + } + void ScheduleFly() { + _skeletonSpawnCounter = 0; + + scheduler.Schedule(2s, GROUP_FLYING, [this](TaskContext) + { + DoCastVictim(SPELL_RAIN_OF_BONES); + _skeletonscheduler.Schedule(50ms, [this](TaskContext context) + { + //spawns skeletons every second until skeletonCount is reached + if(_skeletonSpawnCounter < _skeletonCount) + { + DoCastVictim(SPELL_SUMMON_SKELETON, true); + _skeletonSpawnCounter++; + context.Repeat(2s); + } + }); + }).Schedule(20s, GROUP_FLYING, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_DISTRACTING_ASH); + context.Repeat(2s); //timer wrong? + }).Schedule(25s, GROUP_FLYING, [this](TaskContext context) + { + //5 seconds added due to double trigger? + //trigger for timer in original + in rain of bones + //timers need some investigation + DoCastVictim(SPELL_SMOKING_BLAST); + context.Repeat(1500ms); //timer wrong? + }).Schedule(13s, GROUP_FLYING, [this](TaskContext context) + { + DoCastOnFarAwayPlayers(SPELL_FIREBALL_BARRAGE, false, 80.0f); + context.Repeat(20s); + }); + } + + void AttackStart(Unit* who) override + { + if (!_intro && !_flying) + ScriptedAI::AttackStart(who); + } + + void JustDied(Unit* /*killer*/) override + { + if (instance) + instance->SetData(DATA_NIGHTBANE, DONE); + + HandleTerraceDoors(true); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!_intro && !_flying) + ScriptedAI::MoveInLineOfSight(who); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (_intro) + { + if (id >= 8) + { + _intro = false; + //me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0); + //doesn't need home position because we have to "despawn" boss on reset + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetInCombatWithZone(); + return; + } + + MovePhase = id + 1; + return; + } + + if (_flying) + { + if (id == 0) + { + Talk(EMOTE_BREATH); + _flying = false; + Phase = 2; + return; + } + + if (id < 8) MovePhase = id + 1; + else + { + Phase = 1; + _flying = false; + _movement = true; return; } + } + } - if (Flying) + void JustSummoned(Creature* summon) override + { + summon->AI()->AttackStart(me->GetVictim()); + summons.Summon(summon); + } + + void DoCastOnFarAwayPlayers(uint32 spellid, bool triggered, float tresholddistance) + { + //resembles DoCastToAllHostilePlayers a bit/lot + ThreatContainer::StorageType targets = me->GetThreatMgr().GetThreatList(); + for (ThreatContainer::StorageType::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) { - if (id == 0) + if (unit->IsPlayer() && !unit->IsWithinDist(me, tresholddistance, false)) { - Talk(EMOTE_BREATH); - Flying = false; - Phase = 2; - return; - } - - if (id < 8) - MovePhase = id + 1; - else - { - Phase = 1; - Flying = false; - Movement = true; - return; + me->CastSpell(unit, spellid, triggered); } } } + } - void JustSummoned(Creature* summoned) override + void TakeOff() + { + Talk(YELL_FLY_PHASE); + scheduler.CancelGroup(GROUP_GROUND); + + me->InterruptSpell(CURRENT_GENERIC_SPELL); + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + me->SetDisableGravity(true); + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MovePoint(0, IntroWay[2][0], IntroWay[2][1], IntroWay[2][2]); + + _flying = true; + + ScheduleFly(); + + //handle landing again + scheduler.Schedule(45s, 60s, [this](TaskContext) { - summoned->AI()->AttackStart(me->GetVictim()); - } + Talk(YELL_LAND_PHASE); - void TakeOff() - { - Talk(YELL_FLY_PHASE); - - me->InterruptSpell(CURRENT_GENERIC_SPELL); - me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - me->SetDisableGravity(true); me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MovePoint(0, IntroWay[2][0], IntroWay[2][1], IntroWay[2][2]); + me->GetMotionMaster()->MovePoint(3, IntroWay[3][0], IntroWay[3][1], IntroWay[3][2]); - Flying = true; - - FlyTimer = urand(45000, 60000); //timer wrong between 45 and 60 seconds - ++FlyCount; - - RainofBonesTimer = 5000; //timer wrong (maybe) - RainBones = false; - Skeletons = false; - } - - void UpdateAI(uint32 diff) override - { - if (Intro) + _flying = true; + scheduler.CancelGroup(GROUP_FLYING); + scheduler.Schedule(2s, [this](TaskContext) { - if (MovePhase) - { - if (MovePhase >= 7) - { - me->SetDisableGravity(false); - me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]); - } - else - { - me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]); - } - MovePhase = 0; - } - return; - } + ScheduleGround(); + }); + }); + } - if (Flying && MovePhase) + void UpdateAI(uint32 diff) override + { + if (_intro) + { + if (MovePhase) { if (MovePhase >= 7) { @@ -282,158 +341,70 @@ public: me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]); } else + { me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]); - + } MovePhase = 0; } - - if (!UpdateVictim()) - return; - - if (Flying) - return; - - // Phase 1 "GROUND FIGHT" - if (Phase == 1) - { - if (Movement) - { - DoStartMovement(me->GetVictim()); - Movement = false; - } - - if (BellowingRoarTimer <= diff) - { - DoCastVictim(SPELL_BELLOWING_ROAR); - BellowingRoarTimer = urand(30000, 40000); - } - else - BellowingRoarTimer -= diff; - - if (SmolderingBreathTimer <= diff) - { - DoCastVictim(SPELL_SMOLDERING_BREATH); - SmolderingBreathTimer = 20000; - } - else - SmolderingBreathTimer -= diff; - - if (CharredEarthTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_CHARRED_EARTH); - CharredEarthTimer = 20000; - } - else - CharredEarthTimer -= diff; - - if (TailSweepTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - if (!me->HasInArc(M_PI, target)) - DoCast(target, SPELL_TAIL_SWEEP); - TailSweepTimer = 15000; - } - else - TailSweepTimer -= diff; - - if (SearingCindersTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_SEARING_CINDERS); - SearingCindersTimer = 10000; - } - else - SearingCindersTimer -= diff; - - uint32 Prozent = uint32(me->GetHealthPct()); - - if (Prozent < 75 && FlyCount == 0) // first take off 75% - TakeOff(); - - if (Prozent < 50 && FlyCount == 1) // secound take off 50% - TakeOff(); - - if (Prozent < 25 && FlyCount == 2) // third take off 25% - TakeOff(); - - DoMeleeAttackIfReady(); - } - - //Phase 2 "FLYING FIGHT" - if (Phase == 2) - { - if (!RainBones) - { - if (!Skeletons) - { - for (uint8 i = 0; i <= 3; ++i) - { - DoCastVictim(SPELL_SUMMON_SKELETON); - Skeletons = true; - } - } - - if (RainofBonesTimer < diff && !RainBones) // only once at the beginning of phase 2 - { - DoCastVictim(SPELL_RAIN_OF_BONES); - RainBones = true; - SmokingBlastTimer = 20000; - } - else - RainofBonesTimer -= diff; - - if (DistractingAshTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_DISTRACTING_ASH); - DistractingAshTimer = 2000; //timer wrong - } - else - DistractingAshTimer -= diff; - } - - if (RainBones) - { - if (SmokingBlastTimer <= diff) - { - DoCastVictim(SPELL_SMOKING_BLAST); - SmokingBlastTimer = 1500; //timer wrong - } - else - SmokingBlastTimer -= diff; - } - - if (FireballBarrageTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0)) - DoCast(target, SPELL_FIREBALL_BARRAGE); - FireballBarrageTimer = 20000; - } - else - FireballBarrageTimer -= diff; - - if (FlyTimer <= diff) //landing - { - Talk(YELL_LAND_PHASE); - - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MovePoint(3, IntroWay[3][0], IntroWay[3][1], IntroWay[3][2]); - - Flying = true; - } - else - FlyTimer -= diff; - } + return; } - }; -}; + if (_flying && MovePhase) + { + if (MovePhase >= 7) + { + me->SetDisableGravity(false); + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]); + } + else + me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]); + + MovePhase = 0; + } + + if (!UpdateVictim()) + return; + + if (_flying) + return; + + scheduler.Update(diff); + _skeletonscheduler.Update(diff); + + // Phase 1 "GROUND FIGHT" + if (Phase == 1) + { + if (_movement) + { + DoStartMovement(me->GetVictim()); + _movement = false; + } + + DoMeleeAttackIfReady(); + } + } + +private: + uint32 Phase; + + TaskScheduler _skeletonscheduler; + + bool _intro; + bool _flying; + bool _movement; + + uint32 MovePhase; + uint8 _skeletonCount; + uint8 _skeletonSpawnCounter; +}; class go_blackened_urn : public GameObjectScript { public: go_blackened_urn() : GameObjectScript("go_blackened_urn") { } + //if we summon an entity instead of using a sort of invisible entity, we could unsummon boss on reset + //right now that doesn't work because of how the urn works bool OnGossipHello(Player* player, GameObject* go) override { if (InstanceScript* pInstance = go->GetInstanceScript()) @@ -449,6 +420,6 @@ public: void AddSC_boss_nightbane() { - new boss_nightbane(); + RegisterKarazhanCreatureAI(boss_nightbane); new go_blackened_urn(); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp index 7d50c5c6e..569ae5c5c 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp @@ -292,6 +292,7 @@ public: { instance->SetData(DATA_ARCHIMONDEEVENT, NOT_STARTED); + me->SetReactState(REACT_AGGRESSIVE); DoomfireSpiritGUID.Clear(); WorldTreeGUID.Clear(); WispCount = 0; @@ -618,6 +619,7 @@ public: break; } case EVENT_BELOW_10_PERCENT_HP: + me->SetReactState(REACT_PASSIVE); DoCastProtection(); // Protection of Elune against Finger and Hand of Death BelowTenPercent = true; me->GetMotionMaster()->Clear(false); diff --git a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp index 45db5585b..020a9555f 100644 --- a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp @@ -218,9 +218,9 @@ struct boss_magtheridon : public BossAI Talk(SAY_EMOTE_FREE); Talk(SAY_FREE); scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown + _magReleased = true; scheduler.Schedule(3s, [this](TaskContext) { - _magReleased = true; //redundancy ScheduleCombatEvents(); }); } @@ -239,6 +239,7 @@ struct boss_magtheridon : public BossAI { Talk(SAY_EMOTE_FREE); Talk(SAY_FREE); + _magReleased = true; }).Schedule(123s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/) { ScheduleCombatEvents(); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 4001a5327..6a24eb84f 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4884,6 +4884,39 @@ class spell_gen_shriveling_gaze : public AuraScript } }; +// 38048 - Curse of Pain +enum CurseOfPain +{ + SPELL_CURSE_OF_PAIN = 38048, +}; + +class spell_gen_curse_of_pain : public AuraScript +{ + PrepareAuraScript(spell_gen_curse_of_pain); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_CURSE_OF_PAIN }); + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + if (target && target->ToPlayer()) + { + if (target->GetHealthPct() < 50.f) + { + target->RemoveAurasDueToSpell(SPELL_CURSE_OF_PAIN); + } + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_gen_curse_of_pain::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } +}; + void AddSC_generic_spell_scripts() { RegisterSpellScript(spell_silithyst); @@ -5029,4 +5062,5 @@ void AddSC_generic_spell_scripts() RegisterSpellScript(spell_freezing_circle); RegisterSpellScript(spell_gen_threshalisk_charge); RegisterSpellScript(spell_gen_shriveling_gaze); + RegisterSpellScript(spell_gen_curse_of_pain); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 6d091c141..c42d4e84d 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -974,6 +974,9 @@ class spell_q6124_6129_apply_salve : public SpellScript if (newEntry) { creatureTarget->UpdateEntry(newEntry); + creatureTarget->GetMotionMaster()->Clear(); + creatureTarget->GetMotionMaster()->MoveFleeing(caster); + creatureTarget->SetUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1); creatureTarget->DespawnOrUnsummon(DESPAWN_TIME); caster->KilledMonsterCredit(newEntry); } diff --git a/src/server/scripts/World/npc_professions.cpp b/src/server/scripts/World/npc_professions.cpp index 07c7acba3..020268ef6 100644 --- a/src/server/scripts/World/npc_professions.cpp +++ b/src/server/scripts/World/npc_professions.cpp @@ -486,7 +486,7 @@ public: if (creature->IsTrainer()) AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - if (player->HasSkill(SKILL_ALCHEMY) && player->GetBaseSkillValue(SKILL_ALCHEMY) >= 350 && player->GetLevel() > 67) + if (player->HasSkill(SKILL_ALCHEMY) && player->GetBaseSkillValue(SKILL_ALCHEMY) >= 325 && player->GetLevel() > 67) { if (player->GetQuestRewardStatus(Q_MASTER_TRANSMUTE) || player->GetQuestRewardStatus(Q_MASTER_ELIXIR) || player->GetQuestRewardStatus(Q_MASTER_POTION)) { diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 2a0469507..22b62bd41 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -32,6 +32,7 @@ #include "ScriptedGossip.h" #include "SmartAI.h" #include "SpellAuras.h" +#include "TaskScheduler.h" #include "WaypointMgr.h" #include "World.h" @@ -2653,6 +2654,32 @@ public: } }; +struct npc_crashin_thrashin_robot : public ScriptedAI +{ +public: + npc_crashin_thrashin_robot(Creature* creature) : ScriptedAI(creature) + { + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + _scheduler.Schedule(180s, [this](TaskContext /*context*/) + { + me->KillSelf(); + }); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + + ScriptedAI::UpdateAI(diff); + } + +private: + TaskScheduler _scheduler; +}; + void AddSC_npcs_special() { // Ours @@ -2680,4 +2707,5 @@ void AddSC_npcs_special() new npc_spring_rabbit(); new npc_stable_master(); RegisterCreatureAI(npc_arcanite_dragonling); + RegisterCreatureAI(npc_crashin_thrashin_robot); }