Merge pull request #190 from mod-playerbots/test-staging

Test staging sync
This commit is contained in:
Keleborn
2026-04-10 15:16:35 -07:00
committed by GitHub
81 changed files with 1018 additions and 1027 deletions
+3 -7
View File
@@ -1,8 +1,10 @@
name: nopch-build
on:
push:
branches:
- 'master'
- 'test-staging'
pull_request:
types:
- opened
@@ -10,13 +12,6 @@ on:
- synchronize
concurrency:
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -52,3 +47,4 @@ jobs:
CC: ${{ matrix.compiler.CC }}
CXX: ${{ matrix.compiler.CXX }}
pch: false
modules: true # optional: include module compilation if desired
+4 -10
View File
@@ -1,8 +1,10 @@
name: pch-build
on:
push:
branches:
- 'master'
- 'test-staging'
pull_request:
types:
- opened
@@ -10,13 +12,6 @@ on:
- synchronize
concurrency:
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -39,9 +34,7 @@ jobs:
CC: clang-18
CXX: clang++-18
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }}-${{ matrix.compiler }}-pch
env:
COMPILER: ${{ matrix.compiler }}
name: ${{ matrix.os }}-${{ matrix.compiler.CC }}-pch
if: github.repository == 'mod-playerbots/azerothcore-wotlk' && !github.event.pull_request.draft
steps:
- uses: actions/checkout@v4
@@ -50,3 +43,4 @@ jobs:
CC: ${{ matrix.compiler.CC }}
CXX: ${{ matrix.compiler.CXX }}
pch: true
modules: true # optional: include modules in PCH build
+32 -66
View File
@@ -4,17 +4,15 @@ name: ubuntu-build
on:
push:
branches: [ "Playerbot" ]
branches: [ "Playerbot", "test-staging" ]
pull_request:
branches: [ "Playerbot" ]
branches: [ "Playerbot", "test-staging" ]
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
@@ -28,73 +26,41 @@ jobs:
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: 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: Set reusable strings
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- 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: Checkout Playerbot Module
uses: actions/checkout@v3
with:
repository: mod-playerbots/mod-playerbots
# Map AC branch → PB branch
ref: ${{ github.ref_name == 'Playerbot' && 'master' || 'test-staging' }}
path: modules/mod-playerbots
- 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: Install Requirements
run: |
sudo apt-get update
sudo apt-get install -y git cmake make gcc g++ clang \
libmysqlclient-dev libssl-dev libbz2-dev \
libreadline-dev libncurses-dev mysql-server libboost-all-dev
# - 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 }}
- name: Configure CMake
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
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
+2 -2
View File
@@ -4,9 +4,9 @@ name: ubuntu-build
on:
push:
branches: [ "Playerbot" ]
branches: [ "Playerbot", "test-staging" ]
pull_request:
branches: [ "Playerbot" ]
branches: [ "Playerbot", "test-staging" ]
jobs:
build:
+1
View File
@@ -3,6 +3,7 @@ on:
push:
branches:
- 'master'
- 'test-staging'
pull_request:
types:
- opened
+1
View File
@@ -8,6 +8,7 @@ on:
push:
branches:
- 'master'
- 'test-staging'
pull_request:
types:
- opened
+4 -10
View File
@@ -3,47 +3,41 @@ on:
push:
branches:
- master
- test-staging # add this if you want pending SQL imported on this branch too
jobs:
import-pending:
strategy:
fail-fast: false
runs-on: ubuntu-24.04
permissions: write-all
permissions:
contents: write # 'write-all' is not a valid permission, should specify what is needed
if: github.repository == 'azerothcore/azerothcore-wotlk' && !github.event.pull_request.draft
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
# If we're fetching all the history in a later step it makes sense to
# pre-load it now
fetch-depth: 0
ref: ${{ github.ref_name }}
- uses: denoland/setup-deno@v1
with:
# Specifies latest 1.x
deno-version: "~1.0"
- name: Import and commit pending sql
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
# Get the latest changes from git
git pull --rebase origin "${{ github.ref_name }}"
bash bin/acore-db-pendings
deno run --allow-all --unstable apps/ci/ci-pending-changelogs.ts
git add -A .
git commit -am "chore(DB): import pending files" -m "Referenced commit(s): ${GITHUB_SHA}" || true
env:
# Noting that the branch name can only be master, as per the event
# triggering this action
BRANCH: ${{ github.ref_name }}
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.AC_GITHUB_TOKEN }}
# Noting that the branch name can only be master, as per the event
# triggering this action
branch: ${{ github.ref_name }}
branch: ${{ github.ref_name }}
+26 -5
View File
@@ -1,12 +1,17 @@
name: macos-build
on:
push:
branches: [ "Playerbot" ]
branches:
- "Playerbot"
- "test-staging"
pull_request:
branches: [ "Playerbot" ]
branches:
- "Playerbot"
- "test-staging"
concurrency:
group: ${{ github.head_ref }} || concat(${{ github.ref_name }}, ${{ github.workflow }})
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
@@ -23,7 +28,16 @@ jobs:
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Checkout AzerothCore
uses: actions/checkout@v4
- name: Checkout Playerbot Module
uses: actions/checkout@v4
with:
repository: mod-playerbots/mod-playerbots
ref: ${{ github.ref_name == 'Playerbot' && 'master' || 'test-staging' }}
path: modules/mod-playerbots
- name: Cache
uses: actions/cache@v4
with:
@@ -32,15 +46,22 @@ jobs:
restore-keys: |
ccache:${{ matrix.os }}:${{ github.ref_name }}
ccache:${{ matrix.os }}
- name: reset ccache stats
shell: bash
run: ccache -z || true
- name: Install latest bash
run: brew install bash
- name: Configure OS
shell: bash
run: source ./acore.sh install-deps
- name: Build
shell: bash
run: source ./apps/ci/mac/ci-compile.sh
- name: ccache stats
shell: bash
run: ccache -s || true
run: ccache -s || true
+25 -11
View File
@@ -1,18 +1,12 @@
name: windows-build
on:
push:
branches: [ "Playerbot" ]
branches: [ "Playerbot", "test-staging" ]
pull_request:
branches: [ "Playerbot" ]
branches: [ "Playerbot", "test-staging" ]
concurrency:
# One concurrency group per workflow + ref.
#
# - PRs use `refs/pull/<PR_NUMBER>/merge`, so new commits cancel older
# in-progress runs for the same PR.
# - When a PR is merged, a push to the target branch starts a new group,
# canceling any still-running PR CI.
# - Branch pushes are isolated by ref.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -26,18 +20,38 @@ jobs:
name: ${{ matrix.os }}
env:
BOOST_ROOT: C:\local\boost_1_82_0
steps:
- uses: actions/checkout@v4
- name: Checkout AzerothCore
uses: actions/checkout@v4
- name: Checkout Playerbot Module
uses: actions/checkout@v4
with:
repository: mod-playerbots/mod-playerbots
ref: ${{ github.ref_name == 'Playerbot' && 'master' || 'test-staging' }}
path: modules/mod-playerbots
- name: Move repo to short path
shell: bash
run: |
mkdir C:/ac
cp -r . C:/ac/
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.13
- name: Configure OS
shell: bash
env:
CONTINUOUS_INTEGRATION: true
run: |
cd C:/ac
./acore.sh install-deps
- name: Build
shell: bash
run: |
cd C:/ac
export CTOOLS_BUILD=all
./acore.sh compiler build
./acore.sh compiler build
@@ -0,0 +1,6 @@
-- DB update 2026_02_24_00 -> 2026_03_30_00
--
ALTER TABLE `bugreport`
ADD COLUMN `State` TINYINT NOT NULL DEFAULT 1,
ADD COLUMN `Assignee` VARCHAR(255) DEFAULT NULL,
ADD COLUMN `Comment` LONGTEXT DEFAULT NULL;
@@ -0,0 +1,19 @@
-- DB update 2026_03_30_00 -> 2026_04_03_00
--
CREATE TABLE `spam_reports` (
`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`SpamType` TINYINT UNSIGNED NOT NULL COMMENT '0 = mail, 1 = chat, 2 = calendar',
`SpammerGuid` INT UNSIGNED NOT NULL DEFAULT '0',
`Unk1` INT UNSIGNED NULL DEFAULT '0',
`MailIdOrMessageType` INT UNSIGNED NULL DEFAULT '0',
`ChannelId` INT UNSIGNED NULL COMMENT 'Only used if SpamType = 1',
`SecondsSinceMessage` INT UNSIGNED NULL COMMENT 'Only used if SpamType = 1',
`Description` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
`Time` INT NULL DEFAULT NULL COMMENT 'Time of report',
PRIMARY KEY (`ID`) USING BTREE
)
CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci
ENGINE = InnoDB
ROW_FORMAT = DEFAULT
;
@@ -0,0 +1,6 @@
-- DB update 2026_03_28_00 -> 2026_03_28_01
-- Achievement add command feedback strings
DELETE FROM `acore_string` WHERE `entry` IN (30126, 30127);
INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES
(30126, 'Achievement {} ({}) added to player {}.', '업적 {} ({})이(가) 플레이어 {}에게 추가되었습니다.', 'Le haut fait {} ({}) a été ajouté au joueur {}.', 'Erfolg {} ({}) wurde Spieler {} hinzugefügt.', '成就 {} ({}) 已添加给玩家 {}。', '成就 {} ({}) 已新增給玩家 {}。', 'El logro {} ({}) ha sido añadido al jugador {}.', 'El logro {} ({}) ha sido añadido al jugador {}.', 'Достижение {} ({}) добавлено игроку {}.'),
(30127, 'Achievement {} ({}) will be added to player {} on next login.', '업적 {} ({})이(가) 다음 로그인 시 플레이어 {}에게 추가됩니다.', 'Le haut fait {} ({}) sera ajouté au joueur {} à la prochaine connexion.', 'Erfolg {} ({}) wird Spieler {} beim nächsten Login hinzugefügt.', '成就 {} ({}) 将在玩家 {} 下次登录时添加。', '成就 {} ({}) 將在玩家 {} 下次登入時新增。', 'El logro {} ({}) será añadido al jugador {} en el próximo inicio de sesión.', 'El logro {} ({}) será añadido al jugador {} en el próximo inicio de sesión.', 'Достижение {} ({}) будет добавлено игроку {} при следующем входе.');
+119
View File
@@ -0,0 +1,119 @@
-- DB update 2026_03_28_01 -> 2026_03_28_02
-- Move Outland gossip handlers from C++ to database
-- NPCs: Shattrath Flask Vendors (23484, 23483), Zephyr (25967), Drake Dealer Hurlunk (23489)
-- =====================================================
-- 1. npc_shattrathflaskvendors - Aldor vendor (23484), menu 8751
-- Show vendor option only if Exalted with Aldor (932), Sha'tar (935), Cenarion Expedition (942)
-- Text 11085 = qualified, Text 11083 = rejection (default)
-- =====================================================
-- Condition on gossip_menu: show text 11085 if Exalted with all 3 factions
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=8751 AND `SourceEntry`=11085;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 8751, 11085, 0, 0, 5, 0, 932, 128, 0, 0, 0, 0, '', 'Haldor the Compulsive - Show text 11085 if Exalted with Aldor'),
(14, 8751, 11085, 0, 0, 5, 0, 935, 128, 0, 0, 0, 0, '', 'Haldor the Compulsive - Show text 11085 if Exalted with Sha''tar'),
(14, 8751, 11085, 0, 0, 5, 0, 942, 128, 0, 0, 0, 0, '', 'Haldor the Compulsive - Show text 11085 if Exalted with Cenarion Expedition');
-- Condition on gossip_menu_option: show vendor option only if Exalted with all 3 factions
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8751 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8751, 0, 0, 0, 5, 0, 932, 128, 0, 0, 0, 0, '', 'Haldor the Compulsive - Show vendor option if Exalted with Aldor'),
(15, 8751, 0, 0, 0, 5, 0, 935, 128, 0, 0, 0, 0, '', 'Haldor the Compulsive - Show vendor option if Exalted with Sha''tar'),
(15, 8751, 0, 0, 0, 5, 0, 942, 128, 0, 0, 0, 0, '', 'Haldor the Compulsive - Show vendor option if Exalted with Cenarion Expedition');
-- Remove ScriptName
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=23484;
-- =====================================================
-- 2. npc_shattrathflaskvendors - Scryers vendor (23483), menu 8752
-- Show vendor option only if Exalted with Scryers (934), Sha'tar (935), Cenarion Expedition (942)
-- Text 11085 = qualified, Text 11084 = rejection (default)
-- =====================================================
-- Add qualified text 11085 to menu 8752 (only rejection text 11084 exists)
DELETE FROM `gossip_menu` WHERE `MenuID`=8752 AND `TextID`=11085;
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES
(8752, 11085);
-- Condition on gossip_menu: show text 11085 if Exalted with all 3 factions
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=14 AND `SourceGroup`=8752 AND `SourceEntry`=11085;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 8752, 11085, 0, 0, 5, 0, 934, 128, 0, 0, 0, 0, '', 'Arcanist Xorith - Show text 11085 if Exalted with Scryers'),
(14, 8752, 11085, 0, 0, 5, 0, 935, 128, 0, 0, 0, 0, '', 'Arcanist Xorith - Show text 11085 if Exalted with Sha''tar'),
(14, 8752, 11085, 0, 0, 5, 0, 942, 128, 0, 0, 0, 0, '', 'Arcanist Xorith - Show text 11085 if Exalted with Cenarion Expedition');
-- Condition on gossip_menu_option: show vendor option only if Exalted with all 3 factions
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8752 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8752, 0, 0, 0, 5, 0, 934, 128, 0, 0, 0, 0, '', 'Arcanist Xorith - Show vendor option if Exalted with Scryers'),
(15, 8752, 0, 0, 0, 5, 0, 935, 128, 0, 0, 0, 0, '', 'Arcanist Xorith - Show vendor option if Exalted with Sha''tar'),
(15, 8752, 0, 0, 0, 5, 0, 942, 128, 0, 0, 0, 0, '', 'Arcanist Xorith - Show vendor option if Exalted with Cenarion Expedition');
-- Remove ScriptName
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=23483;
-- =====================================================
-- 3. npc_zephyr (25967), menu 9205
-- Show teleport option if Revered+ with Keepers of Time (989)
-- On select: player casts spell 37778 (Teleport: Caverns of Time)
-- =====================================================
-- Condition on gossip_menu_option: show option if Revered or Exalted with Keepers of Time
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9205 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 9205, 0, 0, 0, 5, 0, 989, 192, 0, 0, 0, 0, '', 'Zephyr - Show teleport option if Revered+ with Keepers of Time');
-- SAI: on gossip select (menu 9205, option 0) -> invoker self-casts spell 37778
DELETE FROM `smart_scripts` WHERE `entryorguid`=25967 AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(25967, 0, 0, 0, 62, 0, 100, 512, 9205, 0, 0, 0, 0, 0, 134, 37778, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Zephyr - On Gossip Select - Invoker Cast Teleport Caverns of Time');
-- Update creature_template: set SmartAI, remove ScriptName
UPDATE `creature_template` SET `ScriptName`='', `AIName`='SmartAI' WHERE `entry`=25967;
-- =====================================================
-- 4. npc_drake_dealer_hurlunk (23489), menu 8754
-- Show vendor option only if Exalted with Netherwing (1015)
-- =====================================================
-- Condition on gossip_menu_option: show vendor option if Exalted with Netherwing
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8754 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8754, 0, 0, 0, 5, 0, 1015, 128, 0, 0, 0, 0, '', 'Drake Dealer Hurlunk - Show vendor option if Exalted with Netherwing');
-- Remove ScriptName
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=23489;
-- =====================================================
-- 5. npcs_flanis_swiftwing_and_kagrosh
-- Flanis Swiftwing (21727), menu 8356 - give item 30658 if quest 10583 incomplete
-- Kagrosh (21725), menu 8371 - give item 30659 if quest 10601 incomplete
-- =====================================================
-- Condition on menu 8356 option 0: quest 10583 incomplete AND player doesn't have item 30658
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8356 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8356, 0, 0, 0, 47, 0, 10583, 8, 0, 0, 0, 0, '', 'Flanis Swiftwing - Show option if quest 10583 is in progress'),
(15, 8356, 0, 0, 0, 2, 0, 30658, 1, 0, 1, 0, 0, '', 'Flanis Swiftwing - Show option if player does not have item 30658');
-- Condition on menu 8371 option 0: quest 10601 incomplete AND player doesn't have item 30659
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8371 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8371, 0, 0, 0, 47, 0, 10601, 8, 0, 0, 0, 0, '', 'Kagrosh - Show option if quest 10601 is in progress'),
(15, 8371, 0, 0, 0, 2, 0, 30659, 1, 0, 1, 0, 0, '', 'Kagrosh - Show option if player does not have item 30659');
-- SAI for Flanis (21727): on gossip select -> close gossip + add item 30658
DELETE FROM `smart_scripts` WHERE `entryorguid`=21727 AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(21727, 0, 0, 1, 62, 0, 100, 512, 8356, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Flanis Swiftwing - On Gossip Select - Close Gossip'),
(21727, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 56, 30658, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Flanis Swiftwing - Linked - Add Item 30658');
-- SAI for Kagrosh (21725): on gossip select -> close gossip + add item 30659
DELETE FROM `smart_scripts` WHERE `entryorguid`=21725 AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(21725, 0, 0, 1, 62, 0, 100, 512, 8371, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Kagrosh - On Gossip Select - Close Gossip'),
(21725, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 56, 30659, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Kagrosh - Linked - Add Item 30659');
-- Update creature_template: set SmartAI, remove ScriptName
UPDATE `creature_template` SET `ScriptName`='', `AIName`='SmartAI' WHERE `entry` IN (21725, 21727);
@@ -0,0 +1,97 @@
-- DB update 2026_03_28_02 -> 2026_03_28_03
-- Move Northrend gossip handlers from C++ to database
-- NPCs: Iruk (26219), Razael & Lyana (23998, 23778), Roxi Ramrocket (31247), Avatar of Freya (27801)
-- =====================================================
-- 1. npc_iruk (26219) - zone_borean_tundra
-- Show gossip option if quest 11961 is incomplete
-- On select: player self-casts spell 46816 (Create Totem of Issliruk)
-- =====================================================
-- Condition on gossip_menu_option: show option if quest 11961 is in progress
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9280 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 9280, 0, 0, 0, 47, 0, 11961, 8, 0, 0, 0, 0, '', 'Iruk - Show option if quest 11961 is in progress');
-- SAI: on gossip select (menu 9280, option 0) -> close gossip + invoker self-cast spell 46816
DELETE FROM `smart_scripts` WHERE `entryorguid`=26219 AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(26219, 0, 0, 1, 62, 0, 100, 512, 9280, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Iruk - On Gossip Select - Close Gossip'),
(26219, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 134, 46816, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Iruk - Linked - Invoker Cast Create Totem of Issliruk');
-- Update creature_template
UPDATE `creature_template` SET `ScriptName`='', `AIName`='SmartAI' WHERE `entry`=26219;
-- =====================================================
-- 2. npc_razael_and_lyana - zone_howling_fjord
-- Razael (23998), menu 8870 -> ActionMenuID 8869 (already wired)
-- Lyana (23778), menu 8879 -> ActionMenuID 8878 (already wired)
-- Both require quest 11221 incomplete, give TalkedToCreature credit on select
-- =====================================================
-- Condition on menu 8870 option 0: quest 11221 in progress
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8870 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8870, 0, 0, 0, 47, 0, 11221, 8, 0, 0, 0, 0, '', 'Razael - Show gossip option if quest 11221 is in progress');
-- Condition on menu 8879 option 0: quest 11221 in progress
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=8879 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 8879, 0, 0, 0, 47, 0, 11221, 8, 0, 0, 0, 0, '', 'Lyana - Show gossip option if quest 11221 is in progress');
-- SAI for Razael (23998): on gossip select (menu 8870, option 0) -> quest credit 23998
DELETE FROM `smart_scripts` WHERE `entryorguid`=23998 AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(23998, 0, 0, 0, 62, 0, 100, 512, 8870, 0, 0, 0, 0, 0, 33, 23998, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Razael - On Gossip Select - Quest Credit 23998');
-- Update Razael creature_template
UPDATE `creature_template` SET `ScriptName`='', `AIName`='SmartAI' WHERE `entry`=23998;
-- SAI for Lyana (23778): append gossip handler to existing SAI (id 0 = OOC say already exists)
DELETE FROM `smart_scripts` WHERE `entryorguid`=23778 AND `source_type`=0 AND `id`=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
(23778, 0, 1, 0, 62, 0, 100, 512, 8879, 0, 0, 0, 0, 0, 33, 23778, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Lyana - On Gossip Select - Quest Credit 23778');
-- Update Lyana creature_template (already has SmartAI)
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=23778;
-- =====================================================
-- 3. npc_roxi_ramrocket (31247) - zone_storm_peaks
-- Trainer option already in DB (menu 10210, OptionID 0, type 5)
-- Add vendor option gated by HasSpell (60866 Mechano-Hog OR 60867 Mekgineer's Chopper)
-- =====================================================
-- Add vendor gossip_menu_option
DELETE FROM `gossip_menu_option` WHERE `MenuID`=10210 AND `OptionID`=1;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(10210, 1, 1, 'I want to browse your goods.', 3370, 3, 128, 0, 0, 0, 0, '', 0, 0);
-- Condition on vendor option: HasSpell 60866 (Mechano-Hog) OR HasSpell 60867 (Mekgineer's Chopper)
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=10210 AND `SourceEntry`=1;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 10210, 1, 0, 0, 25, 0, 60866, 0, 0, 0, 0, 0, '', 'Roxi Ramrocket - Show vendor option if player has Mechano-Hog'),
(15, 10210, 1, 0, 1, 25, 0, 60867, 0, 0, 0, 0, 0, '', 'Roxi Ramrocket - Show vendor option if player has Mekgineer''s Chopper');
-- Remove ScriptName
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=31247;
-- =====================================================
-- 4. npc_avatar_of_freya (27801) - zone_sholazar_basin
-- 3-step gossip chain already wired: 9720 -> 9721 -> 9722 -> close
-- Condition on first option: quest 12621 incomplete
-- SAI on final select: invoker self-cast spell 52045
-- =====================================================
-- Condition on menu 9720 option 0: quest 12621 in progress
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=9720 AND `SourceEntry`=0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 9720, 0, 0, 0, 47, 0, 12621, 8, 0, 0, 0, 0, '', 'Avatar of Freya - Show gossip option if quest 12621 is in progress');
-- SAI: on gossip select (menu 9722, option 0) -> close gossip + invoker self-cast spell 52045
DELETE FROM `smart_scripts` WHERE `entryorguid`=27801 AND `source_type`=0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(27801, 0, 0, 1, 62, 0, 100, 512, 9722, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of Freya - On Gossip Select - Close Gossip'),
(27801, 0, 1, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 134, 52045, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of Freya - Linked - Invoker Cast Freya Conversation');
-- Update creature_template
UPDATE `creature_template` SET `ScriptName`='', `AIName`='SmartAI' WHERE `entry`=27801;
+117
View File
@@ -0,0 +1,117 @@
-- DB update 2026_03_28_03 -> 2026_03_29_00
-- Move gossip handling from C++ scripts to database for Augustus the Touched,
-- Parqual Fintallas, and Lokhtos Darkbargainer.
-- Augustus migration based on TC work by dr-j (commit cefed89c38bc)
-- Parqual migration based on TC work by offl (issue #24993, commit 7908b00311)
-- =============================================================================
-- 1. Augustus the Touched (entry 12384)
-- Conditional vendor option if quest 6164 (Augustus' Receipt Book) rewarded.
-- Two gossip texts: 4979 before quest, 4980 after quest.
-- =============================================================================
-- Remove C++ ScriptName
UPDATE `creature_template` SET `ScriptName` = '' WHERE `entry` = 12384;
-- Add gossip_menu entry for post-quest text 4980
DELETE FROM `gossip_menu` WHERE `MenuID` = 4085 AND `TextID` = 4980;
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES (4085, 4980);
-- Conditions on gossip_menu text: 4979 before quest, 4980 after quest
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 14 AND `SourceGroup` = 4085 AND `SourceEntry` IN (4979, 4980);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 4085, 4979, 0, 0, 8, 0, 6164, 0, 0, 1, 0, 0, '', 'Augustus the Touched - Show text 4979 if quest 6164 NOT rewarded'),
(14, 4085, 4980, 0, 0, 8, 0, 6164, 0, 0, 0, 0, 0, '', 'Augustus the Touched - Show text 4980 if quest 6164 rewarded');
-- Condition: show vendor option (MenuID 4085, OptionID 0) only if quest 6164 rewarded
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 15 AND `SourceGroup` = 4085 AND `SourceEntry` = 0;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 4085, 0, 0, 0, 8, 0, 6164, 0, 0, 0, 0, 0, '', 'Augustus the Touched - Show vendor option only if quest 6164 rewarded');
-- =============================================================================
-- 2. Parqual Fintallas (entry 4488)
-- Test of Lore quiz: 4 answers, wrong ones cast Shame, correct completes quest.
-- =============================================================================
-- Remove C++ ScriptName, set SmartAI
UPDATE `creature_template` SET `ScriptName` = '', `AIName` = 'SmartAI' WHERE `entry` = 4488;
-- Add gossip_menu entry for quiz text (5822) shown during quiz
DELETE FROM `gossip_menu` WHERE `MenuID` = 4764 AND `TextID` = 5822;
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES (4764, 5822);
-- Condition on gossip_menu text 5822: quest 6628 taken + no Shame aura
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 14 AND `SourceGroup` = 4764 AND `SourceEntry` = 5822;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 4764, 5822, 0, 0, 9, 0, 6628, 0, 0, 0, 0, 0, '', 'Parqual Fintallas - Show quiz text 5822 if quest 6628 taken'),
(14, 4764, 5822, 0, 0, 1, 0, 6767, 0, 0, 1, 0, 0, '', 'Parqual Fintallas - Show quiz text 5822 if player does not have Mark of Shame aura');
-- Conditions on quiz options 0, 1, 2, 3: quest 6628 taken + no Shame aura
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 15 AND `SourceGroup` = 4764 AND `SourceEntry` IN (0, 1, 2, 3);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
-- Option 0: Kel'Thuzad (wrong answer)
(15, 4764, 0, 0, 0, 9, 0, 6628, 0, 0, 0, 0, 0, '', 'Parqual Fintallas - Show option 0 if quest 6628 taken'),
(15, 4764, 0, 0, 0, 1, 0, 6767, 0, 0, 1, 0, 0, '', 'Parqual Fintallas - Show option 0 if no Mark of Shame aura'),
-- Option 1: Gul'dan (wrong answer)
(15, 4764, 1, 0, 0, 9, 0, 6628, 0, 0, 0, 0, 0, '', 'Parqual Fintallas - Show option 1 if quest 6628 taken'),
(15, 4764, 1, 0, 0, 1, 0, 6767, 0, 0, 1, 0, 0, '', 'Parqual Fintallas - Show option 1 if no Mark of Shame aura'),
-- Option 2: Kil'jaeden (wrong answer)
(15, 4764, 2, 0, 0, 9, 0, 6628, 0, 0, 0, 0, 0, '', 'Parqual Fintallas - Show option 2 if quest 6628 taken'),
(15, 4764, 2, 0, 0, 1, 0, 6767, 0, 0, 1, 0, 0, '', 'Parqual Fintallas - Show option 2 if no Mark of Shame aura'),
-- Option 3: Ner'zhul (correct answer)
(15, 4764, 3, 0, 0, 9, 0, 6628, 0, 0, 0, 0, 0, '', 'Parqual Fintallas - Show option 3 if quest 6628 taken'),
(15, 4764, 3, 0, 0, 1, 0, 6767, 0, 0, 1, 0, 0, '', 'Parqual Fintallas - Show option 3 if no Mark of Shame aura');
-- SAI for Parqual Fintallas
DELETE FROM `smart_scripts` WHERE `entryorguid` = 4488 AND `source_type` = 0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
-- Option 0 (Kel'Thuzad - wrong): close gossip, then cast Mark of Shame
(4488, 0, 0, 1, 62, 0, 100, 0, 4764, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - On Gossip Select 0 (Kel''Thuzad) - Close Gossip'),
(4488, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 6767, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - Linked - Cast Mark of Shame on Invoker'),
-- Option 1 (Gul'dan - wrong): close gossip, then cast Mark of Shame
(4488, 0, 2, 3, 62, 0, 100, 0, 4764, 1, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - On Gossip Select 1 (Gul''dan) - Close Gossip'),
(4488, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 6767, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - Linked - Cast Mark of Shame on Invoker'),
-- Option 2 (Kil'jaeden - wrong): close gossip, then cast Mark of Shame
(4488, 0, 4, 5, 62, 0, 100, 0, 4764, 2, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - On Gossip Select 2 (Kil''jaeden) - Close Gossip'),
(4488, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 6767, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - Linked - Cast Mark of Shame on Invoker'),
-- Option 3 (Ner'zhul - correct): close gossip, then credit quest 6628
(4488, 0, 6, 7, 62, 0, 100, 0, 4764, 3, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - On Gossip Select 3 (Ner''zhul) - Close Gossip'),
(4488, 0, 7, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 15, 6628, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Parqual Fintallas - Linked - Area Explored Or Event Happens Quest 6628');
-- =============================================================================
-- 3. Lokhtos Darkbargainer (entry 12944)
-- Rep-gated vendor + conditional Thorium Brotherhood contract creation.
-- =============================================================================
-- Remove C++ ScriptName, set SmartAI
UPDATE `creature_template` SET `ScriptName` = '', `AIName` = 'SmartAI' WHERE `entry` = 12944;
-- Replace gossip_menu text: remove default 5834, add rep-conditional texts 3673/3677
DELETE FROM `gossip_menu` WHERE `MenuID` = 4781 AND `TextID` IN (5834, 3673, 3677);
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES
(4781, 3673),
(4781, 3677);
-- Conditions on gossip_menu text: 3673 below Friendly, 3677 at Friendly+
-- Friendly(4)=16, Honored(5)=32, Revered(6)=64, Exalted(7)=128 => mask 240
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 14 AND `SourceGroup` = 4781 AND `SourceEntry` IN (3673, 3677);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 4781, 3673, 0, 0, 5, 0, 59, 240, 0, 1, 0, 0, '', 'Lokhtos Darkbargainer - Show text 3673 if Thorium Brotherhood rep < Friendly'),
(14, 4781, 3677, 0, 0, 5, 0, 59, 240, 0, 0, 0, 0, '', 'Lokhtos Darkbargainer - Show text 3677 if Thorium Brotherhood rep >= Friendly');
-- Condition on vendor option (MenuID 4781, OptionID 0): rep >= Friendly
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 15 AND `SourceGroup` = 4781 AND `SourceEntry` IN (0, 1);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
-- Option 0 (vendor): requires Friendly rep
(15, 4781, 0, 0, 0, 5, 0, 59, 240, 0, 0, 0, 0, '', 'Lokhtos Darkbargainer - Show vendor option if Thorium Brotherhood rep >= Friendly'),
-- Option 1 (contract): requires quest 7604 NOT rewarded + no item 18628 (incl. bank) + has item 17203
(15, 4781, 1, 0, 0, 8, 0, 7604, 0, 0, 1, 0, 0, '', 'Lokhtos Darkbargainer - Show contract option if quest 7604 NOT rewarded'),
(15, 4781, 1, 0, 0, 2, 0, 18628, 1, 1, 1, 0, 0, '', 'Lokhtos Darkbargainer - Show contract option if player does NOT have Thorium Brotherhood Contract'),
(15, 4781, 1, 0, 0, 2, 0, 17203, 1, 0, 0, 0, 0, '', 'Lokhtos Darkbargainer - Show contract option if player has Sulfuron Ingot');
-- SAI for Lokhtos Darkbargainer: contract spell on gossip select option 1
DELETE FROM `smart_scripts` WHERE `entryorguid` = 12944 AND `source_type` = 0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
-- Option 1 (Get contract): close gossip, then invoker casts contract creation spell
(12944, 0, 0, 1, 62, 0, 100, 0, 4781, 1, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Lokhtos Darkbargainer - On Gossip Select 1 (Contract) - Close Gossip'),
(12944, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 134, 23059, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Lokhtos Darkbargainer - Linked - Invoker Cast Create Thorium Brotherhood Contract');
@@ -0,0 +1,3 @@
-- DB update 2026_03_29_00 -> 2026_03_29_01
-- Fix Ashtongue Channeler saved health (was incorrectly 1)
UPDATE `creature` SET `curhealth` = 87973 WHERE `id1` = 23421;
@@ -0,0 +1,46 @@
-- DB update 2026_03_29_01 -> 2026_03_29_02
--
-- Set EFFECT_PULL_TOWARDS, EFFECT_PULL_TOWARDS_DEST knockback effects
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x3CCB3F7B(CHARM|DISORIENTED|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|DISCOVERY|IMMUNE_SHIELD|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-410;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x3CCB3F5B(CHARM|DISORIENTED|DISTRACT|FEAR|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|DISCOVERY|IMMUNE_SHIELD|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-407;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CF3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHIELD|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-372;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB7F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|BLEED|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-369;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='school=0x10(FROST), mech=0x26CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-366;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='school=0x4(FIRE), mech=0x26CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-364;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=AVOID_AOE|IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-363;
UPDATE `creature_immunities` SET `Effects`='98,114,124,144,145', `Comment`='mech=0x26CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=NO_TAUNT|IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),114(ATTACK_ME),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST), auras=11(BIND)' WHERE `ID`=-362;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-361;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F7E(DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-359;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F7D(CHARM|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-357;
UPDATE `creature_immunities` SET `Effects`='98,114,124,144,145', `Comment`='mech=0x26CB3F7B(CHARM|DISORIENTED|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=NO_TAUNT|IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),114(ATTACK_ME),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST), auras=11(BIND)' WHERE `ID`=-356;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F7B(CHARM|DISORIENTED|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-355;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F77(CHARM|DISORIENTED|DISARM|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-353;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB3F5F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-350;
UPDATE `creature_immunities` SET `Effects`='98,114,124,144,145', `Comment`='mech=0x26CB3B7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=NO_TAUNT|IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),114(ATTACK_ME),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST), auras=11(BIND)' WHERE `ID`=-342;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB377F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-340;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB375F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|ROOT|SILENCE|SLEEP|SNARE|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-339;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB031F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|SILENCE|SLEEP|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-336;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x26CB031D(CHARM|DISARM|DISTRACT|FEAR|SILENCE|SLEEP|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-335;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x268B3F7B(CHARM|DISORIENTED|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|HORROR|INTERRUPT|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-327;
UPDATE `creature_immunities` SET `Effects`='98,114,124,144,145', `Comment`='mech=0x24CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|SAPPED), flags=NO_TAUNT|IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),114(ATTACK_ME),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST), auras=11(BIND)' WHERE `ID`=-287;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x24CB3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-286;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x24CB3F5B(CHARM|DISORIENTED|DISTRACT|FEAR|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-275;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x24CB375F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|ROOT|SILENCE|SLEEP|SNARE|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-267;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x24CB207F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-264;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x248B3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|HORROR|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-256;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x24812E7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SLEEP|SNARE|STUN|KNOCKOUT|POLYMORPH|HORROR|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-236;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x2401267F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SLEEP|SNARE|KNOCKOUT|POLYMORPH|DAZE|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-223;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x22CB337F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHACKLE|TURN|HORROR|INTERRUPT|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-219;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x20CF3F7F(CHARM|DISORIENTED|DISARM|DISTRACT|FEAR|GRIP|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|POLYMORPH|BANISH|SHIELD|SHACKLE|TURN|HORROR|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-211;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x20C10A11(CHARM|FEAR|SLEEP|STUN|POLYMORPH|TURN|HORROR|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-200;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x20011B51(CHARM|FEAR|ROOT|SILENCE|SLEEP|STUN|FREEZE|POLYMORPH|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-177;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x20000022(DISORIENTED|GRIP|SAPPED), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-173;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x6030005(CHARM|DISARM|POLYMORPH|BANISH|INTERRUPT|DAZE), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-166;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x4030005(CHARM|DISARM|POLYMORPH|BANISH|DAZE), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-151;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x2C23F57(CHARM|DISORIENTED|DISARM|FEAR|ROOT|SILENCE|SLEEP|SNARE|STUN|FREEZE|KNOCKOUT|BANISH|TURN|HORROR|INTERRUPT), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-143;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x2811D50(FEAR|ROOT|SILENCE|SNARE|STUN|FREEZE|POLYMORPH|HORROR|INTERRUPT), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-138;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x800010(FEAR|HORROR), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-96;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x20720(GRIP|SILENCE|SLEEP|SNARE|BANISH), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-87;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x900(SILENCE|STUN), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-50;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='mech=0x20(GRIP), flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-27;
UPDATE `creature_immunities` SET `Effects`='98,124,144,145', `Comment`='flags=IMMUNITY_KNOCKBACK, effects=98(KNOCK_BACK),124(PULL_TOWARDS),144(KNOCK_BACK_DEST),145(PULL_TOWARDS_DEST)' WHERE `ID`=-3;
@@ -0,0 +1,10 @@
-- DB update 2026_03_29_02 -> 2026_03_30_00
-- Move Majordomo Executus Ragnaros summoning gossip chain to database
-- Previously handled entirely in C++ script (sGossipHello/sGossipSelect)
-- Add gossip_menu entries (MenuID -> TextID) for the gossip chain
DELETE FROM `gossip_menu` WHERE `MenuID` IN (4093, 4108, 4109);
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES
(4093, 4995),
(4109, 5011),
(4108, 5012);
@@ -0,0 +1,3 @@
-- DB update 2026_03_30_00 -> 2026_03_31_00
-- Valithria Dreamwalker
UPDATE `creature_template` SET `flags_extra` = `flags_extra` & ~128 WHERE `entry` = 37950;
@@ -0,0 +1,4 @@
-- DB update 2026_03_31_00 -> 2026_04_03_00
--
-- from mechanic_immune_mask 646000477 to school=0x10(FROST)
UPDATE `creature_template` SET `CreatureImmunitiesId`=-6 WHERE `entry`=510;
@@ -0,0 +1,26 @@
-- DB update 2026_04_03_00 -> 2026_04_03_01
DELETE FROM `waypoint_data` WHERE `id` = 2669000;
INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
(2669000, 1, 478.743, -505.576, 104.724, 0, 0, 1, 0, 100, 0),
(2669000, 2, 318.177, -503.8898, 104.5326, 0, 0, 1, 0, 100, 0);
DELETE FROM `smart_scripts` WHERE `entryorguid` = 26690 AND `source_type` = 0 AND `id` IN (2);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(26690, 0, 2, 0, 109, 0, 100, 0, 0, 2669000, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ymirjar Warrior - On Path 2669000 Finished - Set In Combat With Zone');
DELETE FROM `smart_scripts` WHERE `entryorguid` = 26691 AND `source_type` = 0 AND `id` IN (2);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(26691, 0, 2, 0, 109, 0, 100, 0, 0, 2669000, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ymirjar Witch Doctor - On Path 2669000 Finished - Set In Combat With Zone');
DELETE FROM `smart_scripts` WHERE `entryorguid` = 26692 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`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(26692, 0, 3, 0, 109, 0, 100, 0, 0, 2669000, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Ymirjar Harpooner - On Path 2669000 Finished - Set In Combat With Zone');
UPDATE `spell_area` SET `gender` = 2 WHERE `spell` = 47546;
DELETE FROM `waypoint_data` WHERE `id` IN (2689303, 2689304);
INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
(2689303, 1, 520.483, -541.563, 119.842, 0, 0, 2, 0, 100, 0),
(2689303, 2, 496.434, -517.578, 120, 0, 0, 2, 0, 100, 0),
(2689304, 1, 520.483, -541.563, 119.842, 0, 0, 2, 0, 100, 0),
(2689304, 2, 500.243, -501.693, 120, 0, 0, 2, 0, 100, 0);
@@ -0,0 +1,3 @@
-- DB update 2026_04_03_01 -> 2026_04_03_02
-- Add CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT to Toxic Tunnel (Naxxramas)
UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 0x00002000 WHERE `entry` = 16400;
@@ -0,0 +1,6 @@
-- DB update 2026_04_03_02 -> 2026_04_03_03
-- Fix Skadi Poisoned Spear not applying periodic DOT in Heroic mode.
-- Spell 59331 is the heroic variant of 50255 (mapped via spelldifficulty_dbc),
-- but the spell script was only registered for the normal version.
DELETE FROM `spell_script_names` WHERE `spell_id` = 59331 AND `ScriptName` = 'spell_skadi_poisoned_spear';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (59331, 'spell_skadi_poisoned_spear');
@@ -612,6 +612,15 @@ AllowLoggingIPAddressesInDatabase = 1
Allow.IP.Based.Action.Logging = 0
#
# LogSpamReports
# Description: Allow logging spam reports from players in the chat, mail or calendar into the database.
# Default: 1 - (Enabled)
# 0 - (Disabled)
#
LogSpamReports = 1
#
# Appender config values: Given an appender "name"
# Appender.name
@@ -353,6 +353,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ALL_AT_LOGIN_FLAGS, "UPDATE characters SET at_login = at_login | ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_BUG_REPORT, "INSERT INTO bugreport (type, content) VALUES(?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_SPAM_REPORT, "INSERT INTO spam_reports (SpamType, SpammerGuid, Unk1, MailIdOrMessageType, ChannelId, SecondsSinceMessage, Description, Time) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petition_id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petition_id, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC);
@@ -277,6 +277,7 @@ enum CharacterDatabaseStatements : uint32
CHAR_UPD_REM_AT_LOGIN_FLAG,
CHAR_UPD_ALL_AT_LOGIN_FLAGS,
CHAR_INS_BUG_REPORT,
CHAR_INS_SPAM_REPORT,
CHAR_UPD_PETITION_NAME,
CHAR_INS_PETITION_SIGNATURE,
CHAR_UPD_ACCOUNT_ONLINE,
+3 -2
View File
@@ -23,8 +23,9 @@ PossessedAI::PossessedAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_
NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c)
{
me->SetReactState(REACT_PASSIVE);
// TODO: Remove once WorldObject casting is ported (triggers won't create combat refs from spell casts)
me->SetIsCombatDisallowed(true);
// TODO: Remove once WorldObject spell casting is ported (triggers won't create combat refs from spell casts)
if (me->IsTrigger())
me->SetIsCombatDisallowed(true);
}
int32 NullCreatureAI::Permissible(Creature const* creature)
@@ -44,6 +44,7 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
mCanRepeatPath = false;
mEvadeDisabled = false;
mSuppressEvade = false;
mCanAutoAttack = true;
@@ -698,6 +699,9 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
{
if (mSuppressEvade)
return;
if (mEvadeDisabled)
{
GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);
@@ -181,6 +181,7 @@ public:
void SetSwim(bool swim = true);
void SetEvadeDisabled(bool disable = true);
void SetSuppressEvade(bool suppress) { mSuppressEvade = suppress; }
void SetInvincibilityHpLevel(uint32 level) { mInvincibilityHpLevel = level; }
@@ -249,6 +250,7 @@ private:
uint32 GetWPCount() { return mWayPoints ? mWayPoints->Nodes.size() : 0; }
bool mCanRepeatPath;
bool mEvadeDisabled;
bool mSuppressEvade;
bool mCanAutoAttack;
bool mForcedPaused;
uint32 mInvincibilityHpLevel;
@@ -1039,7 +1039,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!me)
break;
// Suppress evade during script-initiated combat stop so
// JustExitedCombat does not trigger EnterEvadeMode.
if (SmartAI* sai = CAST_AI(SmartAI, me->AI()))
sai->SetSuppressEvade(true);
me->CombatStop(true);
if (SmartAI* sai = CAST_AI(SmartAI, me->AI()))
sai->SetSuppressEvade(false);
break;
}
case SMART_ACTION_CALL_GROUPEVENTHAPPENS:
@@ -745,6 +745,13 @@ void BattlegroundIC::HandleContestedNodes(ICNodePoint* nodePoint)
(*itr)->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
}
else if (nodePoint->nodeType == NODE_TYPE_REFINERY || nodePoint->nodeType == NODE_TYPE_QUARRY)
{
// nodePoint->faction is the assaulting team (set before this call);
// remove the siege damage buff from the team that previously controlled the node.
uint32 auraSpellId = (nodePoint->nodeType == NODE_TYPE_REFINERY) ? SPELL_OIL_REFINERY : SPELL_QUARRY;
RemoveAuraOnTeam(auraSpellId, GetOtherTeamId(nodePoint->faction));
}
else if (nodePoint->nodeType == NODE_TYPE_WORKSHOP)
{
DelObject(BG_IC_GO_SEAFORIUM_BOMBS_1);
@@ -663,6 +663,8 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
}
SetIsCombatDisallowed(cInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT));
SetDetectionDistance(cInfo->detection_range);
// Update movement
@@ -56,7 +56,7 @@ enum CreatureFlagsExtra : uint32
CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players
CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x00000800, // creature will use offhand attacks
CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor
CREATURE_FLAG_EXTRA_IGNORE_COMBAT = 0x00002000,
CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT = 0x00002000, // creature is not allowed to enter combat
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH = 0x00010000, // creature ignores feign death
@@ -44,7 +44,7 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" };
case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return { "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" };
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return { "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "" };
case CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT: return { "CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT", "CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT", "creature is not allowed to enter combat" };
case CREATURE_FLAG_EXTRA_WORLDEVENT: return { "CREATURE_FLAG_EXTRA_WORLDEVENT", "CREATURE_FLAG_EXTRA_WORLDEVENT", "custom flag for world event creatures (left room for merging)" };
case CREATURE_FLAG_EXTRA_GUARD: return { "CREATURE_FLAG_EXTRA_GUARD", "CREATURE_FLAG_EXTRA_GUARD", "Creature is guard" };
case CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH: return { "CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH", "CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH", "creature ignores feign death" };
@@ -88,7 +88,7 @@ AC_API_EXPORT CreatureFlagsExtra EnumUtils<CreatureFlagsExtra>::FromIndex(std::s
case 10: return CREATURE_FLAG_EXTRA_GHOST_VISIBILITY;
case 11: return CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK;
case 12: return CREATURE_FLAG_EXTRA_NO_SELL_VENDOR;
case 13: return CREATURE_FLAG_EXTRA_IGNORE_COMBAT;
case 13: return CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT;
case 14: return CREATURE_FLAG_EXTRA_WORLDEVENT;
case 15: return CREATURE_FLAG_EXTRA_GUARD;
case 16: return CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH;
@@ -129,7 +129,7 @@ AC_API_EXPORT std::size_t EnumUtils<CreatureFlagsExtra>::ToIndex(CreatureFlagsEx
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return 10;
case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return 11;
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return 12;
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return 13;
case CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT: return 13;
case CREATURE_FLAG_EXTRA_WORLDEVENT: return 14;
case CREATURE_FLAG_EXTRA_GUARD: return 15;
case CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH: return 16;
+1 -1
View File
@@ -13049,7 +13049,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid targetPlayerGUID) const
if (state == lfg::LFG_STATE_FINISHED_DUNGEON)
return ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE;
if (grp->isRollLootActive())
if (grp->isRollLootActive() && ObjectAccessor::FindConnectedPlayer(targetPlayerGUID))
return ERR_PARTY_LFG_BOOT_LOOT_ROLLS;
/// @todo: Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer.
+4 -1
View File
@@ -5697,6 +5697,9 @@ void Unit::RemoveAllAurasExceptType(AuraType type)
// Xinef: We should not remove passive auras on evade, if npc has player owner (scripted one cast auras)
void Unit::RemoveEvadeAuras()
{
if (IsCharmedOwnedByPlayerOrPlayer())
return;
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
Aura const* aura = iter->second->GetBase();
@@ -6768,7 +6771,7 @@ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* victim, uint32 procAttacker, ui
}
else if (healInfo && healInfo->GetHeal())
spellTypeMask = PROC_SPELL_TYPE_HEAL;
else if (damageInfo && damageInfo->GetDamage())
else if (damageInfo && (damageInfo->GetDamage() || damageInfo->GetAbsorb()))
spellTypeMask = PROC_SPELL_TYPE_DAMAGE;
else if (procSpellInfo)
spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL;
+32 -29
View File
@@ -607,35 +607,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R
}
// Remove player from loot rolls
for (Rolls::iterator it = RollId.begin(); it != RollId.end();)
{
Roll* roll = *it;
Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid);
if (itr2 == roll->playerVote.end())
{
++it;
continue;
}
if (itr2->second == GREED || itr2->second == DISENCHANT)
--roll->totalGreed;
else if (itr2->second == NEED)
--roll->totalNeed;
else if (itr2->second == PASS)
--roll->totalPass;
if (itr2->second != NOT_VALID)
--roll->totalPlayersRolling;
roll->playerVote.erase(itr2);
// Xinef: itr can be erased inside
// Xinef: player is removed from all vote lists so it will not pass above playerVote == playerVote.end statement during second iteration
if (CountRollVote(guid, roll->itemGUID, MAX_ROLL_TYPE))
it = RollId.begin();
else
++it;
}
RemovePlayerFromRolls(guid);
// Update subgroups
member_witerator slot = _getMemberWSlot(guid);
@@ -1429,6 +1401,37 @@ void Group::EndRoll(Loot* pLoot, Map* allowedMap)
}
}
void Group::RemovePlayerFromRolls(ObjectGuid guid)
{
for (Rolls::iterator it = RollId.begin(); it != RollId.end();)
{
Roll* roll = *it;
Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid);
if (itr2 == roll->playerVote.end())
{
++it;
continue;
}
if (itr2->second == GREED || itr2->second == DISENCHANT)
--roll->totalGreed;
else if (itr2->second == NEED)
--roll->totalNeed;
else if (itr2->second == PASS)
--roll->totalPass;
if (itr2->second != NOT_VALID)
--roll->totalPlayersRolling;
roll->playerVote.erase(itr2);
if (CountRollVote(guid, roll->itemGUID, MAX_ROLL_TYPE))
it = RollId.begin();
else
++it;
}
}
void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
{
Roll* roll = *rollI;
+1
View File
@@ -302,6 +302,7 @@ public:
void CountTheRoll(Rolls::iterator roll, Map* allowedMap);
bool CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise);
void EndRoll(Loot* loot, Map* allowedMap);
void RemovePlayerFromRolls(ObjectGuid guid);
Rolls GetRolls() const { return RollId; }
+13 -3
View File
@@ -754,11 +754,21 @@ void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket& recvData)
void WorldSession::HandleCalendarComplain(WorldPackets::Calendar::CalendarComplain& packet)
{
ObjectGuid guid = _player->GetGUID();
if (sWorld->getBoolConfig(CONFIG_LOGSPAMREPORTS))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_SPAM_REPORT);
LOG_DEBUG("network", "CMSG_CALENDAR_COMPLAIN [{}] EventId [{}] guid [{}]", guid.ToString(), packet.EventId, packet.ComplainGuid.ToString());
stmt->SetData(0, 2); // SpamType 2 = Calendar
stmt->SetData(1, packet.ComplainGuid.GetCounter());
stmt->SetData(2, 0);
stmt->SetData(3, 0);
stmt->SetData(4, 0);
stmt->SetData(5, 0);
stmt->SetData(6, "EventId: " + std::to_string(packet.EventId));
stmt->SetData(7, GameTime::GetGameTime().count());
// what to do with complains?
CharacterDatabase.Execute(stmt);
}
}
void WorldSession::HandleCalendarGetNumPending(WorldPacket& /*recvData*/)
+15 -2
View File
@@ -1157,8 +1157,21 @@ void WorldSession::HandleComplainOpcode(WorldPackets::Misc::Complain& packet)
// Complaint Received message
SendPacket(WorldPackets::Misc::ComplainResult().Write());
LOG_DEBUG("network", "REPORT SPAM: type {}, {}, unk1 {}, unk2 {}, unk3 {}, unk4 {}, message {}",
packet.SpamType, packet.SpammerGuid.ToString(), packet.Unk1, packet.Unk2, packet.Unk3, packet.Unk4, packet.Description);
if (sWorld->getBoolConfig(CONFIG_LOGSPAMREPORTS))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_SPAM_REPORT);
stmt->SetData(0, packet.SpamType);
stmt->SetData(1, packet.SpammerGuid.GetCounter());
stmt->SetData(2, packet.Unk1);
stmt->SetData(3, packet.MailIdOrMessageType);
stmt->SetData(4, packet.ChannelId);
stmt->SetData(5, packet.SecondsSinceMessage);
stmt->SetData(6, packet.Description);
stmt->SetData(7, GameTime::GetGameTime().count());
CharacterDatabase.Execute(stmt);
}
}
void WorldSession::HandleRealmSplitOpcode(WorldPacket& recv_data)
+4
View File
@@ -142,6 +142,8 @@ bool WorldSession::SendLearnNewTaxiNode(Creature* unit)
update << uint8(1);
SendPacket(&update);
sScriptMgr->OnPlayerLearnTaxiNode(GetPlayer(), curloc);
return true;
}
else
@@ -154,6 +156,8 @@ void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid)
{
WorldPacket msg(SMSG_NEW_TAXI_PATH, 0);
SendPacket(&msg);
sScriptMgr->OnPlayerLearnTaxiNode(GetPlayer(), nodeid);
}
}
+4 -4
View File
@@ -405,10 +405,10 @@ LootItem::LootItem(LootStoreItem const& li)
randomSuffix = GenerateEnchSuffixFactor(itemid);
randomPropertyId = Item::GenerateItemRandomPropertyId(itemid);
count = 0;
is_looted = 0;
is_blocked = 0;
is_underthreshold = 0;
is_counted = 0;
is_looted = false;
is_blocked = false;
is_underthreshold = false;
is_counted = false;
rollWinnerGUID = ObjectGuid::Empty;
groupid = li.groupid;
}
+5 -1
View File
@@ -1445,6 +1445,10 @@ enum AcoreStrings
LANG_DEBUG_FACTIONCHANGE_GOLD_FAIL = 30122,
LANG_DEBUG_FACTIONCHANGE_GOLD_OK = 30123,
LANG_DEBUG_FACTIONCHANGE_GOLD_NOLIMIT = 30124,
LANG_DEBUG_FACTIONCHANGE_NA = 30125
LANG_DEBUG_FACTIONCHANGE_NA = 30125,
// Achievement commands
LANG_ACHIEVEMENT_ADD_ONLINE = 30126,
LANG_ACHIEVEMENT_ADD_OFFLINE = 30127
};
#endif
@@ -367,6 +367,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
creature->StopMoving();
_lastSplineId = 0;
_smoothSplineLaunched = false;
_hasBeenStalled = true;
}
// Set home position to current position.
@@ -931,6 +931,11 @@ void ScriptMgr::OnPlayerGetReputationPriceDiscount(Player const* player, Faction
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_GET_REPUTATION_PRICE_DISCOUNT, script->OnPlayerGetReputationPriceDiscount(player, factionTemplate, discount));
}
void ScriptMgr::OnPlayerLearnTaxiNode(Player const* player, uint32 nodeId)
{
CALL_ENABLED_HOOKS(PlayerScript, PLAYERHOOK_ON_LEARN_TAXI_NODE, script->OnPlayerLearnTaxiNode(player, nodeId));
}
PlayerScript::PlayerScript(const char* name, std::vector<uint16> enabledHooks)
: ScriptObject(name, PLAYERHOOK_END)
{
@@ -216,6 +216,7 @@ enum PlayerHook
PLAYERHOOK_ON_SEND_LIST_INVENTORY,
PLAYERHOOK_ON_GIVE_REPUTATION,
PLAYERHOOK_ON_GET_REPUTATION_PRICE_DISCOUNT,
PLAYERHOOK_ON_LEARN_TAXI_NODE,
PLAYERHOOK_END
};
@@ -827,6 +828,14 @@ public:
* @param discount Float value of the discount, as a multiplier of the base price
*/
virtual void OnPlayerGetReputationPriceDiscount(Player const* /*player*/, FactionTemplateEntry const* /*factionTemplate*/, float& /*discount*/) {}
/**
* @brief This hook is called when a player learns a new flight path node.
*
* @param player Contains information about the Player
* @param nodeId The id of the learned taxi node
*/
virtual void OnPlayerLearnTaxiNode(Player const* /*player*/, uint32 /*nodeId*/) {}
};
#endif
+1
View File
@@ -487,6 +487,7 @@ public: /* PlayerScript */
void OnPlayerSendListInventory(Player* player, ObjectGuid vendorGuid, uint32& vendorEntry);
void OnPlayerGetReputationPriceDiscount(Player const* player, Creature const* creature, float& discount);
void OnPlayerGetReputationPriceDiscount(Player const* player, FactionTemplateEntry const* factionTemplate, float& discount);
void OnPlayerLearnTaxiNode(Player const* player, uint32 nodeId);
// Anti cheat
void AnticheatSetCanFlybyServer(Player* player, bool apply);
@@ -16,6 +16,7 @@
*/
#include "CalendarPackets.h"
#include "Packet.h"
void WorldPackets::Calendar::GetEvent::Read()
{
@@ -149,14 +149,14 @@ void WorldPackets::Misc::Complain::Read()
{
case 0:
_worldPacket >> Unk1; // const 0
_worldPacket >> Unk2; // probably mail id
_worldPacket >> Unk3; // const 0
_worldPacket >> MailIdOrMessageType; // probably mail id
_worldPacket >> ChannelId; // const 0
break;
case 1:
_worldPacket >> Unk1; // probably language
_worldPacket >> Unk2; // message type?
_worldPacket >> Unk3; // probably channel id
_worldPacket >> Unk4; // unk random value
_worldPacket >> MailIdOrMessageType;
_worldPacket >> ChannelId;
_worldPacket >> SecondsSinceMessage;
_worldPacket >> Description; // spam description string (messagetype, channel name, player name, message)
break;
}
+6 -6
View File
@@ -218,13 +218,13 @@ namespace WorldPackets
void Read() override;
uint8 SpamType = 0; // 0 - mail, 1 - chat
uint8 SpamType = 0; // 0 - mail, 1 - chat
ObjectGuid SpammerGuid;
uint32 Unk1 = 0;
uint32 Unk2 = 0;
uint32 Unk3 = 0;
uint32 Unk4 = 0;
std::string Description = "";
uint32 Unk1 = 0;
uint32 MailIdOrMessageType = 0;
uint32 ChannelId = 0;
uint32 SecondsSinceMessage = 0;
std::string Description = "";
};
class ComplainResult final : public ServerPacket
+4
View File
@@ -731,6 +731,10 @@ void WorldSession::LogoutPlayer(bool save)
// a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) d) LeaveGroupOnLogout is enabled
if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && !_player->GetGroup()->isLFGGroup() && m_Socket && sWorld->getBoolConfig(CONFIG_LEAVE_GROUP_ON_LOGOUT))
_player->RemoveFromGroup();
// Remove player from active loot rolls in LFG groups (player stays in group but should not block rolls)
else if (Group* group = _player->GetGroup())
if (group->isLFGGroup())
group->RemovePlayerFromRolls(_player->GetGUID());
// pussywizard: checked second time after being removed from a group
if (!_player->IsBeingTeleportedFar() && !_player->m_InstanceValid && !_player->IsGameMaster())
+6 -1
View File
@@ -2471,6 +2471,11 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
TempSummonType summonType = (duration <= 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
Unit* summoner = m_originalCaster;
if (summoner->IsPet())
if (Unit* owner = summoner->GetOwner())
summoner = owner;
for (uint32 count = 0; count < numSummons; ++count)
{
Position pos;
@@ -2480,7 +2485,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
// randomize position for multiple summons
pos = m_caster->GetRandomPoint(*destTarget, radius);
summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration, 0, nullptr, personalSpawn);
summon = summoner->SummonCreature(entry, pos, summonType, duration, 0, nullptr, personalSpawn);
if (!summon)
continue;
+2
View File
@@ -603,6 +603,8 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<bool>(CONFIG_IP_BASED_ACTION_LOGGING, "Allow.IP.Based.Action.Logging", false);
SetConfigValue<bool>(CONFIG_LOGSPAMREPORTS, "LogSpamReports", true);
// Whether to use LoS from game objects
SetConfigValue<bool>(CONFIG_CHECK_GOBJECT_LOS, "CheckGameObjectLoS", true);
+1
View File
@@ -112,6 +112,7 @@ enum ServerConfigs
CONFIG_ENABLE_CONTINENT_TRANSPORT_PRELOADING,
CONFIG_MINIGOB_MANABONK,
CONFIG_IP_BASED_ACTION_LOGGING,
CONFIG_LOGSPAMREPORTS,
CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA,
CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA,
CONFIG_CHECK_GOBJECT_LOS,
+20 -6
View File
@@ -15,8 +15,10 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AchievementMgr.h"
#include "Chat.h"
#include "CommandScript.h"
#include "Language.h"
#include "Player.h"
using namespace Acore::ChatCommands;
@@ -30,7 +32,7 @@ public:
{
static ChatCommandTable achievementCommandTable =
{
{ "add", HandleAchievementAddCommand, SEC_GAMEMASTER, Console::No },
{ "add", HandleAchievementAddCommand, SEC_GAMEMASTER, Console::Yes },
{ "checkall", HandleAchievementCheckAllCommand, SEC_ADMINISTRATOR, Console::Yes }
};
static ChatCommandTable commandTable =
@@ -40,15 +42,27 @@ public:
return commandTable;
}
static bool HandleAchievementAddCommand(ChatHandler* handler, AchievementEntry const* achievementEntry)
static bool HandleAchievementAddCommand(ChatHandler* handler, AchievementEntry const* achievementEntry, Optional<PlayerIdentifier> player)
{
Player* target = handler->getSelectedPlayer();
if (!target)
if (!player)
player = PlayerIdentifier::FromTargetOrSelf(handler);
if (!player)
{
handler->SendErrorMessage(LANG_NO_CHAR_SELECTED);
handler->SendErrorMessage(LANG_PLAYER_NOT_FOUND);
return false;
}
target->CompletedAchievement(achievementEntry);
if (player->IsConnected())
{
player->GetConnectedPlayer()->CompletedAchievement(achievementEntry);
handler->PSendSysMessage(LANG_ACHIEVEMENT_ADD_ONLINE, achievementEntry->ID, achievementEntry->name[0], player->GetName());
}
else
{
sAchievementMgr->CompletedAchievementForOfflinePlayer(player->GetGUID().GetCounter(), achievementEntry);
handler->PSendSysMessage(LANG_ACHIEVEMENT_ADD_OFFLINE, achievementEntry->ID, achievementEntry->name[0], player->GetName());
}
return true;
}
@@ -452,59 +452,6 @@ private:
uint32 _mightyBlowTimer;
};
// npc_lokhtos_darkbargainer
enum LokhtosItems
{
ITEM_THRORIUM_BROTHERHOOD_CONTRACT = 18628,
ITEM_SULFURON_INGOT = 17203
};
enum LokhtosQuests
{
QUEST_A_BINDING_CONTRACT = 7604
};
enum LokhtosSpells
{
SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059
};
struct npc_lokhtos_darkbargainer : public ScriptedAI
{
npc_lokhtos_darkbargainer(Creature* creature) : ScriptedAI(creature) { }
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
CloseGossipMenuFor(player);
player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false);
}
if (action == GOSSIP_ACTION_TRADE)
player->GetSession()->SendListInventory(me->GetGUID());
}
void sGossipHello(Player* player) override
{
if (me->IsQuestGiver())
player->PrepareQuestMenu(me->GetGUID());
if (me->IsVendor() && player->GetReputationRank(59) >= REP_FRIENDLY)
AddGossipItemFor(player, 4781, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 &&
!player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) &&
player->HasItemCount(ITEM_SULFURON_INGOT))
AddGossipItemFor(player, 4781, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->GetReputationRank(59) < REP_FRIENDLY)
SendGossipMenuFor(player, 3673, me->GetGUID());
else
SendGossipMenuFor(player, 3677, me->GetGUID());
}
};
// npc_rocknot
enum RocknotSays
{
@@ -641,7 +588,6 @@ void AddSC_blackrock_depths()
new at_ring_of_law();
RegisterBlackrockDepthsCreatureAI(npc_grimstone);
RegisterBlackrockDepthsCreatureAI(npc_phalanx);
RegisterBlackrockDepthsCreatureAI(npc_lokhtos_darkbargainer);
RegisterBlackrockDepthsCreatureAI(npc_rocknot);
RegisterBlackrockDepthsCreatureAI(brd_ironhand_guardian);
}
@@ -95,13 +95,7 @@ enum Events
enum Misc
{
TEXT_ID_SUMMON_1 = 4995,
TEXT_ID_SUMMON_2 = 5011,
TEXT_ID_SUMMON_3 = 5012,
GOSSIP_ITEM_SUMMON_1 = 4093,
GOSSIP_ITEM_SUMMON_2 = 4109,
GOSSIP_ITEM_SUMMON_3 = 4108,
MENU_ID_RAGNAROS_SUMMON = 4108,
FACTION_MAJORDOMO_FRIENDLY = 1080,
SUMMON_GROUP_ADDS = 1,
@@ -507,46 +501,14 @@ struct boss_majordomo : public BossAI
}
}
void sGossipHello(Player* player) override
void sGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
SendGossipMenuFor(player, TEXT_ID_SUMMON_1, me->GetGUID());
}
void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
if (menuId == MENU_ID_RAGNAROS_SUMMON)
{
case GOSSIP_ACTION_INFO_DEF:
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, TEXT_ID_SUMMON_2, me->GetGUID());
break;
}
case GOSSIP_ACTION_INFO_DEF+1:
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, TEXT_ID_SUMMON_2, me->GetGUID());
break;
}
case GOSSIP_ACTION_INFO_DEF+2:
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_3, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
SendGossipMenuFor(player, TEXT_ID_SUMMON_3, me->GetGUID());
break;
}
case GOSSIP_ACTION_INFO_DEF+3:
{
CloseGossipMenuFor(player);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
Talk(SAY_RAG_SUM_1, player);
DoAction(ACTION_START_RAGNAROS_INTRO);
break;
}
default:
CloseGossipMenuFor(player);
break;
CloseGossipMenuFor(player);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
Talk(SAY_RAG_SUM_1, player);
DoAction(ACTION_START_RAGNAROS_INTRO);
}
}
@@ -149,7 +149,7 @@ struct boss_moroes : public BossAI
_vanished = true;
Talk(SAY_SPECIAL);
DoCastSelf(SPELL_VANISH);
me->SetImmuneToAll(true);
me->SetImmuneToAll(true, true);
scheduler.Schedule(5s, 7s, [this](TaskContext)
{
me->SetImmuneToAll(false);
@@ -187,7 +187,6 @@ struct boss_kalecgos : public BossAI
me->SetRegeneratingHealth(false);
me->RemoveAllAuras();
me->SetReactState(REACT_PASSIVE);
me->CombatStop();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetFaction(FACTION_FRIENDLY);
}, 1s);
@@ -296,39 +296,8 @@ public:
};
};
/*######
## npc_augustus_the_touched
######*/
class npc_augustus_the_touched : public CreatureScript
{
public:
npc_augustus_the_touched() : CreatureScript("npc_augustus_the_touched") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_TRADE)
player->GetSession()->SendListInventory(creature->GetGUID());
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
if (creature->IsVendor() && player->GetQuestRewardStatus(6164))
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
};
void AddSC_eastern_plaguelands()
{
new npc_eris_hevenfire();
new npc_balance_of_light_and_shadow();
new npc_augustus_the_touched();
}
@@ -293,63 +293,6 @@ public:
};
};
/*######
## npc_parqual_fintallas
######*/
enum ParqualFintallas
{
SPELL_MARK_OF_SHAME = 6767,
QUEST_ID_TEST_OF_LORE = 6628,
GOSSIP_MENU_ID_TEST_OF_LORE = 4764,
GOSSIP_TEXTID_PARQUAL_FINTALLAS = 5821,
GOSSIP_TEXTID_TEST_OF_LORE = 5822,
};
class npc_parqual_fintallas : public CreatureScript
{
public:
npc_parqual_fintallas() : CreatureScript("npc_parqual_fintallas") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
CloseGossipMenuFor(player);
creature->CastSpell(player, SPELL_MARK_OF_SHAME, false);
}
if (action == GOSSIP_ACTION_INFO_DEF + 2)
{
CloseGossipMenuFor(player);
player->AreaExploredOrEventHappens(6628);
}
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsQuestGiver())
{
player->PrepareQuestMenu(creature->GetGUID());
}
if (player->GetQuestStatus(QUEST_ID_TEST_OF_LORE) == QUEST_STATUS_INCOMPLETE && !player->HasAura(SPELL_MARK_OF_SHAME))
{
AddGossipItemFor(player, GOSSIP_MENU_ID_TEST_OF_LORE, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
AddGossipItemFor(player, GOSSIP_MENU_ID_TEST_OF_LORE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
AddGossipItemFor(player, GOSSIP_MENU_ID_TEST_OF_LORE, 3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, GOSSIP_TEXTID_TEST_OF_LORE, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, GOSSIP_TEXTID_PARQUAL_FINTALLAS, creature->GetGUID());
}
return true;
}
};
/*######
## ALLIANCE
#######*/
@@ -4037,7 +3980,6 @@ void AddSC_undercity()
{
new npc_lady_sylvanas_windrunner();
new npc_highborne_lamenter();
new npc_parqual_fintallas();
new npc_varian_wrynn();
new npc_thrall_bfu();
@@ -78,6 +78,7 @@ struct boss_falric : public BossAI
me->m_Events.AddEventAtOffset([this]()
{
_startingFight = false;
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
}, 8s);
}
@@ -78,6 +78,7 @@ struct boss_marwyn : public BossAI
me->m_Events.AddEventAtOffset([this]()
{
_startingFight = false;
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
}, 8s);
}
@@ -1499,7 +1499,6 @@ enum eFightEvents
EVENT_LK_SUMMON_LA,
EVENT_LK_SUMMON_NEXT_ICE_WALL,
EVENT_SAY_OPENING,
EVENT_DECREASE_REQ_COUNT_BY_100,
};
struct npc_hor_lich_king : public NullCreatureAI
@@ -1515,13 +1514,14 @@ struct npc_hor_lich_king : public NullCreatureAI
EventMap events;
SummonList summons;
uint8 currentWall;
uint8 reqKillCount;
uint8 summonsCount;
uint8 div2;
void Reset() override
{
currentWall = 0;
reqKillCount = 0;
summonsCount = 0;
div2 = 0;
events.Reset();
events.RescheduleEvent(EVENT_LK_CHECK_COMBAT, 1s);
}
@@ -1529,24 +1529,21 @@ struct npc_hor_lich_king : public NullCreatureAI
{
if (action == ACTION_START_LK_FIGHT_REAL)
events.ScheduleEvent(EVENT_LK_START_FOLLOWING, 1500ms);
else if ((action == ACTION_INFORM_TRASH_DIED && reqKillCount) || action == ACTION_CHECK_TRASH_DIED)
}
void WallCompleted()
{
++currentWall;
instance->SetData(ACTION_DELETE_ICE_WALL, 1);
if (currentWall <= 3)
{
if ((action == ACTION_CHECK_TRASH_DIED && reqKillCount == 0) || (action == ACTION_INFORM_TRASH_DIED && (--reqKillCount) == 0))
{
events.CancelEvent(EVENT_DECREASE_REQ_COUNT_BY_100); // just in case, magic happens sometimes
++currentWall;
instance->SetData(ACTION_DELETE_ICE_WALL, 1);
if (currentWall <= 3)
{
events.ScheduleEvent(EVENT_LK_SUMMON_NEXT_ICE_WALL, 1s);
events.ScheduleEvent(EVENT_LK_SUMMON, currentWall == 3 ? 11s : 7500ms);
}
else
me->RemoveAura(SPELL_REMORSELESS_WINTER);
if (Creature* c = instance->GetCreature(NPC_SYLVANAS_PART2))
c->AI()->DoAction(ACTION_INFORM_WALL_DESTROYED);
}
events.ScheduleEvent(EVENT_LK_SUMMON_NEXT_ICE_WALL, 1s);
events.ScheduleEvent(EVENT_LK_SUMMON, currentWall == 3 ? 11s : 7500ms);
}
else
me->RemoveAura(SPELL_REMORSELESS_WINTER);
if (Creature* c = instance->GetCreature(NPC_SYLVANAS_PART2))
c->AI()->DoAction(ACTION_INFORM_WALL_DESTROYED);
}
void MovementInform(uint32 type, uint32 /*id*/) override
@@ -1569,17 +1566,14 @@ struct npc_hor_lich_king : public NullCreatureAI
else if (currentWall == 4)
{
Talk(SAY_LK_NOWHERE_TO_RUN);
instance->SetData(DATA_LICH_KING, DONE);
instance->SetBossState(DATA_LICH_KING, DONE);
}
}
}
void JustSummoned(Creature* s) override
{
++reqKillCount;
if (events.HasTimeUntilEvent(EVENT_DECREASE_REQ_COUNT_BY_100))
events.RescheduleEvent(EVENT_DECREASE_REQ_COUNT_BY_100, 10s);
++summonsCount;
summons.Summon(s);
s->SetHomePosition(PathWaypoints[WP_STOP[currentWall + 1]]);
s->GetMotionMaster()->MovePoint(0, PathWaypoints[WP_STOP[currentWall + 1]]);
@@ -1592,6 +1586,14 @@ struct npc_hor_lich_king : public NullCreatureAI
s->SetHomePosition(PathWaypoints[WP_STOP[currentWall + 1]]);
}
void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) override
{
if (!summonsCount)
return;
if (--summonsCount == 0)
WallCompleted();
}
void SummonedCreatureDespawn(Creature* s) override
{
summons.Despawn(s);
@@ -1623,7 +1625,7 @@ struct npc_hor_lich_king : public NullCreatureAI
{
me->GetMotionMaster()->MovementExpired();
me->StopMoving();
reqKillCount = 255;
summonsCount = 255;
leader->InterruptNonMeleeSpells(true);
me->CastSpell(leader, SPELL_HARVEST_SOUL);
events.ScheduleEvent(EVENT_LK_KILL_LEADER, 3s);
@@ -1720,15 +1722,6 @@ struct npc_hor_lich_king : public NullCreatureAI
events.ScheduleEvent(EVENT_LK_SUMMON_LA, 17s + 700ms);
break;
}
if (currentWall <= 3)
{
reqKillCount = 100;
events.RescheduleEvent(EVENT_DECREASE_REQ_COUNT_BY_100, 10s);
}
break;
case EVENT_DECREASE_REQ_COUNT_BY_100:
reqKillCount = (reqKillCount <= 100 ? 0 : reqKillCount - 100);
DoAction(ACTION_CHECK_TRASH_DIED);
break;
case EVENT_LK_SUMMON_GHOULS:
DoCastAOE(SPELL_SUMMON_RAGING_GHOULS);
@@ -2003,9 +1996,6 @@ struct npc_hor_raging_ghoul : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
me->SetCorpseDelay(10);
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS))
lichKing->AI()->DoAction(ACTION_INFORM_TRASH_DIED);
}
};
@@ -2059,9 +2049,6 @@ struct npc_hor_risen_witch_doctor : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
me->SetCorpseDelay(10);
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS))
lichKing->AI()->DoAction(ACTION_INFORM_TRASH_DIED);
}
};
@@ -2110,9 +2097,6 @@ struct npc_hor_lumbering_abomination : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
me->SetCorpseDelay(10);
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS))
lichKing->AI()->DoAction(ACTION_INFORM_TRASH_DIED);
}
};
@@ -27,14 +27,22 @@
enum Data
{
DATA_INTRO,
// Boss encounters (indices for SetBossState)
DATA_FALRIC,
DATA_MARWYN,
DATA_LICH_KING,
MAX_ENCOUNTER,
// Non-boss data (SetData/GetData only)
DATA_INTRO,
DATA_FROSTSWORN_GENERAL,
DATA_LK_INTRO,
DATA_LICH_KING,
DATA_BATTERED_HILT,
MAX_ENCOUNTER,
DATA_WAVE_NUMBER,
DATA_LK_BATTLE,
DATA_SHIP_CAPTAIN,
// Actions
ACTION_SHOW_TRASH,
ACTION_SPIRITUAL_REFLECTIONS_COPY,
ACTION_SPIRITUAL_REFLECTIONS_ACTIVATE,
@@ -42,9 +50,6 @@ enum Data
ACTION_START_LK_FIGHT,
ACTION_STOP_LK_FIGHT,
ACTION_DELETE_ICE_WALL,
DATA_WAVE_NUMBER,
DATA_LK_BATTLE,// in progress
DATA_SHIP_CAPTAIN,
};
enum Creatures
@@ -249,8 +254,6 @@ enum hMisc
ACTION_START_INTRO,
ACTION_SKIP_INTRO,
ACTION_START_LK_FIGHT_REAL,
ACTION_INFORM_TRASH_DIED,
ACTION_CHECK_TRASH_DIED,
ACTION_INFORM_WALL_DESTROYED,
QUEST_DELIVRANCE_FROM_THE_PIT_A2 = 24710,
@@ -468,6 +468,7 @@ public:
leader->AI()->DoAction(ACTION_START_INTRO);
break;
case ACTION_START_LK_FIGHT:
SetBossState(DATA_LICH_KING, IN_PROGRESS);
_isLichKingFightActive = true;
DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT);
DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT);
@@ -516,15 +517,13 @@ public:
lichKing->SetSpeed(MOVE_RUN, lichKing->GetCreatureTemplate()->speed_run);
}
_isLichKingFightActive = false;
SetBossState(DATA_LICH_KING, FAIL);
_outroTimer = 0;
_outroStep = 0;
[[fallthrough]];
case ACTION_DELETE_ICE_WALL:
HandleGameObject(GO_ICE_WALL, true);
break;
case DATA_LICH_KING:
SetBossState(DATA_LICH_KING, static_cast<EncounterState>(data));
break;
case DATA_BATTERED_HILT:
{
if (GetPersistentData(PERSISTENT_DATA_BATTERED_HILT))
@@ -688,14 +688,14 @@ public:
if (_instance->GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) != IN_PROGRESS)
return;
// Blizzlike: ship wipes when all players are in cannons (vehicles) with nobody on deck
// See: azerothcore/azerothcore-wotlk#17856
bool playerOnDeck = false;
me->GetMap()->DoForAllPlayers([&](Player* player)
{
if (!player->GetVehicle() && player->IsAlive())
playerOnDeck = true;
});
// Wipe if no player is on the deck
if (!playerOnDeck)
{
// Script runs on enemy ship. We want to kill our ship.
@@ -653,6 +653,8 @@ public:
_lastTalkTimeBuff = 0;
_bFrostmournePhase = false;
_bFordringMustFallYell = false;
me->SetRegeneratingHealth(true);
me->SetIsCombatDisallowed(false);
_Reset();
DoAction(ACTION_RESTORE_LIGHT);
@@ -792,12 +794,15 @@ public:
if (_phase == PHASE_THREE && HealthBelowPct(10) && !me->HasUnitState(UNIT_STATE_CASTING))
{
_phase = PHASE_OUTRO;
me->SetRegeneratingHealth(false);
me->SetIsCombatDisallowed(true);
EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE);
summons.DoAction(ACTION_TELEPORT_BACK, pred);
events.Reset();
summons.DespawnAll();
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
me->CombatStop(true);
me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_FURY_OF_FROSTMOURNE);
me->InterruptNonMeleeSpells(true);
me->CastSpell((Unit*)nullptr, SPELL_FURY_OF_FROSTMOURNE, false);
@@ -1253,6 +1258,9 @@ public:
void EnterEvadeMode(EvadeReason why) override
{
if (_phase == PHASE_OUTRO || _phase == PHASE_FROSTMOURNE)
return;
EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE);
summons.DoAction(ACTION_TELEPORT_BACK, pred);
instance->SetBossState(DATA_THE_LICH_KING, FAIL);
@@ -341,18 +341,12 @@ public:
_done = true;
Talk(SAY_VALITHRIA_SUCCESS);
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_instance->DoRemoveAurasDueToSpellOnPlayers(70766);
me->RemoveAurasDueToSpell(SPELL_CORRUPTION_VALITHRIA);
me->CastSpell(me, SPELL_ACHIEVEMENT_CHECK, true);
me->CastSpell((Unit*)nullptr, SPELL_DREAMWALKERS_RAGE, false);
_events.Reset();
_events.ScheduleEvent(EVENT_DREAM_SLIP, 3500ms);
_instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, DONE);
if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER)))
trigger->AI()->EnterEvadeMode();
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_LICH_KING)))
lichKing->AI()->Reset();
lichKing->AI()->EnterEvadeMode();
}
else if (!_over75PercentTalkDone && me->HealthAbovePctHealed(75, heal))
{
@@ -361,11 +355,8 @@ public:
}
else if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == NOT_STARTED)
{
if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER)))
{
trigger->AI()->DoAction(ACTION_ENTER_COMBAT);
_instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, IN_PROGRESS);
}
if (Creature* archmage = me->FindNearestCreature(NPC_RISEN_ARCHMAGE, 30.0f))
DoZoneInCombat(archmage); // archmage chain will put trigger in combat
}
}
@@ -388,7 +379,7 @@ public:
Talk(SAY_VALITHRIA_DEATH);
_instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER)))
trigger->AI()->EnterEvadeMode();
trigger->AI()->DoAction(ACTION_DEATH);
}
}
}
@@ -404,6 +395,8 @@ public:
me->SetDisplayId(11686);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->DespawnOrUnsummon(4s);
if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER)))
Unit::Kill(me, trigger);
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_LICH_KING)))
lichKing->CastSpell(lichKing, SPELL_SPAWN_CHEST, false);
_instance->SetData(DATA_WEEKLY_QUEST_ID, 0); // show hidden npc if necessary
@@ -434,13 +427,8 @@ public:
void UpdateAI(uint32 diff) override
{
// does not enter combat
if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == NOT_STARTED)
{
uint32 startingHealth = me->GetMaxHealth() * 0.5f;
if (me->GetHealth() != startingHealth) // healing when boss cannot be engaged (lower spire not finished, cheating) doesn't start the fight, prevent winning this way
me->SetHealth(startingHealth);
if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != IN_PROGRESS)
return;
}
_events.Update(diff);
@@ -508,31 +496,26 @@ public:
void Reset() override
{
events.Reset();
summons.DespawnAll();
if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != DONE)
instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, NOT_STARTED);
_Reset();
me->SetReactState(REACT_PASSIVE);
checkTimer = 5000;
}
void JustEngagedWith(Unit* target) override
void JustEnteredCombat(Unit* target) override
{
if (IsEngaged())
return;
if (!instance->CheckRequiredBosses(DATA_VALITHRIA_DREAMWALKER, target->ToPlayer()))
{
me->setActive(true);
EnterEvadeMode();
EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK);
instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT);
return;
}
if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == DONE)
{
me->CombatStop();
return;
}
EngagementStart(target);
me->setActive(true);
me->SetInCombatWithZone();
DoZoneInCombat();
instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, IN_PROGRESS);
if (Creature* valithria = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VALITHRIA_DREAMWALKER)))
valithria->AI()->DoAction(ACTION_ENTER_COMBAT);
@@ -547,66 +530,31 @@ public:
(*itr)->AI()->DoAction(ACTION_ENTER_COMBAT);
}
void AttackStart(Unit* target) override
{
if (target->IsPlayer())
BossAI::AttackStart(target);
}
void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER) override
{
CreatureAI::EnterEvadeMode(why);
}
void MoveInLineOfSight(Unit* /*who*/) override {}
bool CanAIAttack(Unit const* target) const override
void JustExitedCombat() override
{
return target->IsPlayer();
}
EngagementOver();
void JustReachedHome() override
{
if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != DONE)
DoAction(ACTION_DEATH); // setActive(false) in ValithriaDespawner
else
_JustReachedHome();
me->setActive(false);
if (!me->IsAlive())
return;
if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == DONE)
return;
DoAction(ACTION_DEATH);
}
void DoAction(int32 action) override
{
if (action == ACTION_DEATH)
{
instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, NOT_STARTED);
me->m_Events.AddEventAtOffset(new ValithriaDespawner(me), 5s);
else if (action == ACTION_ENTER_COMBAT)
{
if (!me->IsInCombat())
me->SetInCombatWithZone();
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VALITHRIA_LICH_KING)))
lichKing->AI()->EnterEvadeMode();
}
}
void UpdateAI(uint32 diff) override
{
if (!me->IsInCombat())
return;
if (checkTimer <= diff)
{
checkTimer = 3000;
me->SetInCombatWithZone();
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* target = ref->GetVictim())
if (target->IsAlive() && target->IsPlayer() && me->GetExactDist(target) < 200.0f && !target->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_ALL))
return;
}
EnterEvadeMode();
}
else
checkTimer -= diff;
}
private:
uint16 checkTimer;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -712,7 +660,7 @@ public:
struct npc_risen_archmageAI : public ScriptedAI
{
npc_risen_archmageAI(Creature* creature) : ScriptedAI(creature),
_instance(creature->GetInstanceScript())
_instance(creature->GetInstanceScript()), _isInitialArchmage(false)
{
}
@@ -725,23 +673,34 @@ public:
{
_events.Reset();
_events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5s, 15s);
_events.ScheduleEvent(EVENT_MANA_VOID, 15s, 25s);
_events.ScheduleEvent(EVENT_MANA_VOID, 20s, 25s);
_events.ScheduleEvent(EVENT_COLUMN_OF_FROST, 10s, 20s);
_isInitialArchmage = me->GetSpawnId() != 0;
}
void JustEngagedWith(Unit* /*target*/) override
void JustEnteredCombat(Unit* who) override
{
me->FinishSpell(CURRENT_CHANNELED_SPELL, false);
me->SetInCombatWithZone();
if (me->GetSpawnId())
if (IsEngaged())
return;
me->InterruptNonMeleeSpells(false);
EngagementStart(who);
if (_isInitialArchmage)
{
if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_LICH_KING)))
DoZoneInCombat(lichKing);
if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER)))
trigger->AI()->DoAction(ACTION_ENTER_COMBAT);
DoZoneInCombat(trigger);
}
}
void DoAction(int32 action) override
{
if (action == ACTION_ENTER_COMBAT && !me->IsInCombat())
me->SetInCombatWithZone();
if (action == ACTION_ENTER_COMBAT)
DoZoneInCombat();
}
void JustSummoned(Creature* summon) override
@@ -754,10 +713,8 @@ public:
void UpdateAI(uint32 diff) override
{
if (!me->IsInCombat())
if (me->GetSpawnId())
if (!me->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
me->CastSpell(me, SPELL_CORRUPTION, true);
if (!me->IsInCombat() && me->IsAlive() && _isInitialArchmage && !me->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
DoCastSelf(SPELL_CORRUPTION);
if (!UpdateVictim())
return;
@@ -796,6 +753,7 @@ public:
private:
EventMap _events;
InstanceScript* _instance;
bool _isInitialArchmage;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -345,11 +345,17 @@ public:
return;
}
uint32 corpseDelay = creature->GetCorpseDelay();
uint32 respawnDelay = creature->GetRespawnDelay();
creature->SetCorpseDelay(1);
creature->SetRespawnDelay(2);
if (CreatureData const* data = creature->GetCreatureData())
creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation);
creature->DespawnOrUnsummon();
creature->SetRespawnTime(5);
creature->SetCorpseDelay(corpseDelay);
creature->SetRespawnDelay(respawnDelay);
}
};
@@ -730,7 +736,7 @@ public:
{
me->SetReactState(REACT_DEFENSIVE);
_didUnderTenPercentText = false;
_wipeCheckTimer = 3000;
_wipeCheckTimer = 1000;
_handledWP4 = false;
_events.Reset();
@@ -868,6 +874,27 @@ public:
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!_wipeCheckTimer)
{
_wipeCheckTimer = 1000;
Player* player = nullptr;
Acore::AnyPlayerInObjectRangeCheck check(me, 60.0f);
Acore::PlayerSearcher<Acore::AnyPlayerInObjectRangeCheck> searcher(me, player, check);
Cell::VisitObjects(me, searcher, 60.0f);
// wipe
if (!player)
{
damage *= 100;
if (damage >= me->GetHealth())
{
FrostwingGauntletRespawner respawner;
Acore::CreatureWorker<FrostwingGauntletRespawner> worker(me, respawner);
Cell::VisitObjects(me, worker, 333.0f);
return;
}
}
}
if (HealthBelowPct(10))
{
if (!_didUnderTenPercentText)
@@ -885,37 +912,21 @@ public:
}
}
void UpdateEscortAI(uint32 /*diff*/) override {}
void UpdateEscortAI(uint32 diff) override
{
if (_wipeCheckTimer <= diff)
_wipeCheckTimer = 0;
else
_wipeCheckTimer -= diff;
}
void UpdateAI(uint32 diff) override
{
npc_escortAI::UpdateAI(diff);
//Position pos = me->GetHomePosition();
if (!me->isActiveObject()/* && me->GetExactDist(&pos) < 5.0f*/) // during event
if (!me->isActiveObject())
return;
if (_wipeCheckTimer <= diff)
{
_wipeCheckTimer = 3000;
Player* player = nullptr;
Acore::AnyPlayerInObjectRangeCheck check(me, 140.0f);
Acore::PlayerSearcher<Acore::AnyPlayerInObjectRangeCheck> searcher(me, player, check);
Cell::VisitObjects(me, searcher, 140.0f);
// wipe
if (!player || me->GetExactDist(4357.0f, 2606.0f, 350.0f) > 125.0f)
{
//Talk(SAY_CROK_DEATH);
FrostwingGauntletRespawner respawner;
Acore::CreatureWorker<FrostwingGauntletRespawner> worker(me, respawner);
Cell::VisitObjects(me, worker, 333.0f);
return;
}
}
else
_wipeCheckTimer -= diff;
UpdateVictim();
_events.Update(diff);
@@ -968,7 +979,7 @@ public:
bool CanAIAttack(Unit const* target) const override
{
// do not see targets inside Frostwing Halls when we are not there
return !target->IsPlayer() && (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f) && target->GetEntry() != NPC_SINDRAGOSA;
return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f);
}
private:
@@ -995,18 +1006,30 @@ public:
struct boss_sister_svalnaAI : public BossAI
{
boss_sister_svalnaAI(Creature* creature) : BossAI(creature, DATA_SISTER_SVALNA)
boss_sister_svalnaAI(Creature* creature) : BossAI(creature, DATA_SISTER_SVALNA),
_isEventInProgress(false)
{
}
void InitializeAI() override
{
if (!me->isDead())
Reset();
me->SetReactState(REACT_PASSIVE);
}
void Reset() override
{
_Reset();
me->SetImmuneToAll(true);
me->SetReactState(REACT_DEFENSIVE);
_isEventInProgress = false;
}
void JustReachedHome() override
{
_JustReachedHome();
me->SetReactState(REACT_PASSIVE);
me->SetCanFly(true);
me->SetDisableGravity(true);
me->SendMovementFlagUpdate();
me->SetDisableGravity(false);
}
void JustDied(Unit* /*killer*/) override
@@ -1080,6 +1103,8 @@ public:
break;
case ACTION_START_GAUNTLET:
me->setActive(true);
me->SetImmuneToAll(true);
_isEventInProgress = true;
events.ScheduleEvent(EVENT_SVALNA_START, 25s);
break;
case ACTION_RESURRECT_CAPTAINS:
@@ -1106,16 +1131,21 @@ public:
}
}
void JustExitedCombat() override
{
if (_isEventInProgress)
return;
CreatureAI::JustExitedCombat();
}
void MovementInform(uint32 type, uint32 id) override
{
if (type != EFFECT_MOTION_TYPE || id != POINT_LAND)
return;
_isEventInProgress = false;
me->setActive(false);
me->SetImmuneToAll(false);
me->SetCanFly(false);
me->SetDisableGravity(false);
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat(nullptr, 150.0f);
}
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
@@ -1140,43 +1170,51 @@ public:
void UpdateAI(uint32 diff) override
{
if (!me->isActiveObject())
if (!UpdateVictim() && !_isEventInProgress)
return;
UpdateVictim();
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
while (uint32 eventId = events.ExecuteEvent())
{
case EVENT_SVALNA_START:
Talk(SAY_SVALNA_EVENT_START);
break;
case EVENT_SVALNA_RESURRECT:
Talk(SAY_SVALNA_RESURRECT_CAPTAINS);
me->CastSpell(me, SPELL_REVIVE_CHAMPION, false);
break;
case EVENT_SVALNA_COMBAT:
Talk(SAY_SVALNA_AGGRO);
break;
case EVENT_IMPALING_SPEAR:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false, -SPELL_IMPALING_SPEAR))
{
DoCast(me, SPELL_AETHER_SHIELD);
me->AddAura(70203, me);
DoCast(target, SPELL_IMPALING_SPEAR);
}
events.ScheduleEvent(EVENT_IMPALING_SPEAR, 20s, 25s);
break;
default:
break;
switch (eventId)
{
case EVENT_SVALNA_START:
Talk(SAY_SVALNA_EVENT_START);
break;
case EVENT_SVALNA_RESURRECT:
Talk(SAY_SVALNA_RESURRECT_CAPTAINS);
me->CastSpell(me, SPELL_REVIVE_CHAMPION, false);
break;
case EVENT_SVALNA_COMBAT:
me->SetReactState(REACT_DEFENSIVE);
Talk(SAY_SVALNA_AGGRO);
break;
case EVENT_IMPALING_SPEAR:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false, -SPELL_IMPALING_SPEAR))
{
DoCast(me, SPELL_AETHER_SHIELD);
me->AddAura(70203, me);
DoCast(target, SPELL_IMPALING_SPEAR);
}
events.ScheduleEvent(EVENT_IMPALING_SPEAR, 20s, 25s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
}
private:
bool _isEventInProgress;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -113,8 +113,6 @@ Position const FirstWaveLocations[FIRST_WAVE_SIZE] =
{ 481.388f, -507.109f, 104.724f, 3.26377f },
};
Position const SecondaryWavesInitialPoint = { 478.743f, -505.576f, 104.724f };
enum GraufPoints
{
POINT_BREACH = 0,
@@ -122,11 +120,19 @@ enum GraufPoints
POINT_RIGHT = 2,
};
uint32 const PATH_INITIAL = 2689300;
uint32 const PATH_RIGHT = 2689301;
uint32 const PATH_LEFT = 2689302;
enum GraufPaths
{
PATH_INITIAL = 2689300,
PATH_RIGHT = 2689301,
PATH_LEFT = 2689302,
PATH_BREACH_RIGHT = 2689303,
PATH_BREACH_LEFT = 2689304,
PATH_GAUNTLET_ADDS = 2669000,
};
float const BreachFacing = 2.670354f;
float const BreathFacingRight = 3.124139f;
float const BreathFacingLeft = 3.228859f;
enum Events
{
@@ -139,6 +145,7 @@ enum Events
// Grauf
EVENT_GRAUF_START = 10,
EVENT_GRAUF_LEAVE_BREACH = 11,
EVENT_GRAUF_BREATH_START = 12,
EVENT_GRAUF_REMOVE_AURA = 13,
};
@@ -193,7 +200,10 @@ public:
case NPC_YMIRJAR_WITCH_DOCTOR:
case NPC_YMIRJAR_HARPOONER:
if (_firstWaveSummoned)
summon->GetMotionMaster()->MovePoint(1, SecondaryWavesInitialPoint);
{
summon->LoadPath(PATH_GAUNTLET_ADDS);
summon->GetMotionMaster()->MoveWaypoint(PATH_GAUNTLET_ADDS, false);
}
break;
default:
break;
@@ -404,6 +414,7 @@ public:
_summons.DespawnAll();
me->SetReactState(REACT_PASSIVE);
me->SetSpeedRate(MOVE_RUN, 2.5f);
_flyingToSide = false;
}
void DoAction(int32 param) override
@@ -430,9 +441,19 @@ public:
{
if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized())
{
me->SetFacingTo(BreachFacing);
Talk(EMOTE_ON_RANGE);
_events.ScheduleEvent(EVENT_GRAUF_LEAVE_BREACH, 10s);
if (_flyingToSide)
{
_flyingToSide = false;
me->SetFacingTo(_lastSide == POINT_LEFT ? BreathFacingLeft : BreathFacingRight);
Talk(EMOTE_DEEP_BREATH);
_events.ScheduleEvent(EVENT_GRAUF_BREATH_START, 2s);
}
else
{
me->SetFacingTo(BreachFacing);
Talk(EMOTE_ON_RANGE);
_events.ScheduleEvent(EVENT_GRAUF_LEAVE_BREACH, 10s);
}
}
}
@@ -443,16 +464,20 @@ public:
{
case EVENT_GRAUF_LEAVE_BREACH:
_lastSide = RAND(POINT_LEFT, POINT_RIGHT);
me->GetMotionMaster()->MovePath(_lastSide == POINT_LEFT ? PATH_LEFT : PATH_RIGHT, FORCED_MOVEMENT_RUN);
if (_lastSide == POINT_LEFT)
DoCast(me, SPELL_FREEZING_CLOUD_LEFT_PERIODIC);
else
DoCast(me, SPELL_FREEZING_CLOUD_RIGHT_PERIODIC);
_flyingToSide = true;
me->GetMotionMaster()->MovePath(
_lastSide == POINT_LEFT ? PATH_BREACH_LEFT : PATH_BREACH_RIGHT,
FORCED_MOVEMENT_RUN);
break;
case EVENT_GRAUF_BREATH_START:
me->GetMotionMaster()->MovePath(
_lastSide == POINT_LEFT ? PATH_LEFT : PATH_RIGHT,
FORCED_MOVEMENT_RUN);
DoCast(me, _lastSide == POINT_LEFT
? SPELL_FREEZING_CLOUD_LEFT_PERIODIC
: SPELL_FREEZING_CLOUD_RIGHT_PERIODIC);
if (Creature* skadi = _instance->GetCreature(DATA_SKADI_THE_RUTHLESS))
skadi->AI()->DoAction(ACTION_DRAKE_BREATH);
_events.ScheduleEvent(EVENT_GRAUF_REMOVE_AURA, 10s);
break;
case EVENT_GRAUF_REMOVE_AURA:
@@ -480,6 +505,7 @@ public:
EventMap _events;
SummonList _summons;
uint8 _lastSide = POINT_LEFT;
bool _flyingToSide = false;
};
};
@@ -507,7 +533,7 @@ class spell_skadi_launch_harpoon : public SpellScript
}
};
// 50255 - Poisoned Spear
// 50255, 59331 - Poisoned Spear
class spell_skadi_poisoned_spear : public SpellScript
{
PrepareSpellScript(spell_skadi_poisoned_spear);
@@ -157,8 +157,7 @@ public:
{
if (pSummoned)
{
pSummoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f);
pSummoned->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
pSummoned->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f, MOTION_SLOT_ACTIVE, true, false);
spheres.Summon(pSummoned);
if (pInstance)
pInstance->SetGuidData(DATA_ADD_TRASH_MOB, pSummoned->GetGUID());
@@ -239,50 +239,6 @@ public:
}
};
/*######
## npc_iruk
######*/
enum Iruk
{
GOSSIP_MENU_ID_NPC_IRUK = 9280,
GOSSIP_OPTION_SEARCH_CORPSE = 0,
NPC_TEXT_THIS_YOUNG_TUSKARR = 12585,
QUEST_SPIRITS_WATCH_OVER_US = 11961,
SPELL_CREATE_TOTEM_OF_ISSLIRUK = 46816
};
class npc_iruk : public CreatureScript
{
public:
npc_iruk() : CreatureScript("npc_iruk") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetQuestStatus(QUEST_SPIRITS_WATCH_OVER_US) == QUEST_STATUS_INCOMPLETE)
AddGossipItemFor(player, GOSSIP_MENU_ID_NPC_IRUK, GOSSIP_OPTION_SEARCH_CORPSE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, NPC_TEXT_THIS_YOUNG_TUSKARR, creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
player->CastSpell(player, SPELL_CREATE_TOTEM_OF_ISSLIRUK, true);
CloseGossipMenuFor(player);
}
return true;
}
};
/*######
## npc_nerubar_victim
######*/
@@ -1379,7 +1335,6 @@ void AddSC_borean_tundra()
RegisterSpellScript(spell_q11919_q11940_drake_hunt_aura);
new npc_sinkhole_kill_credit();
new npc_khunok_the_behemoth();
new npc_iruk();
new npc_nerubar_victim();
new npc_lurgglbr();
RegisterSpellScript(spell_arcane_chains_character_force_cast);
@@ -20,7 +20,6 @@
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SpellInfo.h"
#include "SpellScript.h"
@@ -227,73 +226,6 @@ public:
}
};
/*######
## npc_razael_and_lyana
######*/
enum Razael
{
QUEST_REPORTS_FROM_THE_FIELD = 11221,
NPC_RAZAEL = 23998,
NPC_LYANA = 23778,
GOSSIP_TEXTID_RAZAEL1 = 11562,
GOSSIP_TEXTID_RAZAEL2 = 11564,
GOSSIP_TEXTID_LYANA1 = 11586,
GOSSIP_TEXTID_LYANA2 = 11588
};
class npc_razael_and_lyana : public CreatureScript
{
public:
npc_razael_and_lyana() : CreatureScript("npc_razael_and_lyana") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
if (player->GetQuestStatus(QUEST_REPORTS_FROM_THE_FIELD) == QUEST_STATUS_INCOMPLETE)
switch (creature->GetEntry())
{
case NPC_RAZAEL:
if (!player->GetReqKillOrCastCurrentCount(QUEST_REPORTS_FROM_THE_FIELD, NPC_RAZAEL))
{
AddGossipItemFor(player, 8870, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, GOSSIP_TEXTID_RAZAEL1, creature->GetGUID());
return true;
}
break;
case NPC_LYANA:
if (!player->GetReqKillOrCastCurrentCount(QUEST_REPORTS_FROM_THE_FIELD, NPC_LYANA))
{
AddGossipItemFor(player, 8879, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, GOSSIP_TEXTID_LYANA1, creature->GetGUID());
return true;
}
break;
}
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_INFO_DEF + 1:
SendGossipMenuFor(player, GOSSIP_TEXTID_RAZAEL2, creature->GetGUID());
player->TalkedToCreature(NPC_RAZAEL, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF + 2:
SendGossipMenuFor(player, GOSSIP_TEXTID_LYANA2, creature->GetGUID());
player->TalkedToCreature(NPC_LYANA, creature->GetGUID());
break;
}
return true;
}
};
enum RodinLightningSpells
{
SPELL_RODIN_LIGHTNING_START = 44787,
@@ -490,7 +422,6 @@ void AddSC_howling_fjord()
new npc_attracted_reef_bull();
new npc_apothecary_hanes();
new npc_plaguehound_tracker();
new npc_razael_and_lyana();
RegisterCreatureAI(npc_rodin_lightning_enabler);
RegisterSpellScript(spell_hawk_hunting);
RegisterSpellScript(spell_the_cleansing_shrine_cast);
@@ -387,64 +387,6 @@ public:
}
};
/*######
## avatar_of_freya
######*/
enum Freya
{
QUEST_FREYA_PACT = 12621,
SPELL_FREYA_CONVERSATION = 52045,
GOSSIP_AVATAR_MENU_1 = 9720,
GOSSIP_AVATAR_MENU_2 = 9721,
GOSSIP_AVATAR_MENU_3 = 9722,
GOSSIP_TEXTID_AVATAR_1 = 13303,
GOSSIP_TEXTID_AVATAR_2 = 13304,
GOSSIP_TEXTID_AVATAR_3 = 13305,
};
class npc_avatar_of_freya : public CreatureScript
{
public:
npc_avatar_of_freya() : CreatureScript("npc_avatar_of_freya") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
if (player->GetQuestStatus(QUEST_FREYA_PACT) == QUEST_STATUS_INCOMPLETE)
AddGossipItemFor(player, GOSSIP_AVATAR_MENU_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, GOSSIP_TEXTID_AVATAR_1, creature);
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_INFO_DEF+1:
AddGossipItemFor(player, GOSSIP_AVATAR_MENU_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, GOSSIP_TEXTID_AVATAR_2, creature);
break;
case GOSSIP_ACTION_INFO_DEF+2:
AddGossipItemFor(player, GOSSIP_AVATAR_MENU_3, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
SendGossipMenuFor(player, GOSSIP_TEXTID_AVATAR_3, creature);
break;
case GOSSIP_ACTION_INFO_DEF+3:
player->CastSpell(player, SPELL_FREYA_CONVERSATION, true);
CloseGossipMenuFor(player);
break;
}
return true;
}
};
/*######
## npc_bushwhacker
######*/
@@ -1187,7 +1129,6 @@ void AddSC_sholazar_basin()
new go_pressure_valve();
new go_brazier();
new npc_vekjik();
new npc_avatar_of_freya();
new npc_bushwhacker();
new npc_engineer_helice();
new npc_adventurous_dwarf();
@@ -22,7 +22,6 @@
#include "ScriptedCreature.h"
#include "SpellMgr.h"
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
@@ -339,56 +338,6 @@ class spell_q13007_iron_colossus : public SpellScript
}
};
/*######
## npc_roxi_ramrocket
######*/
enum RoxiRamrocket
{
SPELL_MECHANO_HOG = 60866,
SPELL_MEKGINEERS_CHOPPER = 60867
};
class npc_roxi_ramrocket : public CreatureScript
{
public:
npc_roxi_ramrocket() : CreatureScript("npc_roxi_ramrocket") { }
bool OnGossipHello(Player* player, Creature* creature) override
{
//Quest Menu
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
//Trainer Menu
if (creature->IsTrainer())
AddGossipItemFor(player, GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN);
//Vendor Menu
if (creature->IsVendor())
if (player->HasSpell(SPELL_MECHANO_HOG) || player->HasSpell(SPELL_MEKGINEERS_CHOPPER))
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_TRAIN:
player->GetSession()->SendTrainerList(creature);
break;
case GOSSIP_ACTION_TRADE:
player->GetSession()->SendListInventory(creature->GetGUID());
break;
}
return true;
}
};
/*######
## npc_brunnhildar_prisoner
######*/
@@ -1386,7 +1335,6 @@ void AddSC_storm_peaks()
new npc_iron_watcher();
new npc_time_lost_proto_drake();
RegisterSpellScript(spell_q13007_iron_colossus);
new npc_roxi_ramrocket();
new npc_brunnhildar_prisoner();
new npc_freed_protodrake();
new npc_icefang();
@@ -83,6 +83,9 @@ public:
void Reset() override
{
if (_defeated)
return;
faction_Timer = 8000;
envelopingWinds_Timer = 9000;
shock_Timer = 5000;
@@ -93,6 +96,15 @@ public:
Talk(SAY_SUMMON);
}
void JustReachedHome() override
{
if (_defeated)
{
Talk(SAY_FREE);
me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
}
}
void UpdateAI(uint32 diff) override
{
if (faction_Timer)
@@ -110,12 +122,11 @@ public:
if (HealthBelowPct(30))
{
me->SetFaction(FACTION_FRIENDLY);
me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
_defeated = true;
me->RemoveAllAuras();
me->GetThreatMgr().ClearAllThreat();
me->SetFaction(FACTION_FRIENDLY);
me->CombatStop(true);
Talk(SAY_FREE);
me->GetThreatMgr().ClearAllThreat();
return;
}
@@ -140,6 +151,7 @@ public:
uint32 faction_Timer;
uint32 envelopingWinds_Timer;
uint32 shock_Timer;
bool _defeated = false;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -20,7 +20,6 @@
#include "Group.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
@@ -657,98 +656,6 @@ public:
};
};
/*######
## npc_drake_dealer_hurlunk
######*/
class npc_drake_dealer_hurlunk : public CreatureScript
{
public:
npc_drake_dealer_hurlunk() : CreatureScript("npc_drake_dealer_hurlunk") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_TRADE)
player->GetSession()->SendListInventory(creature->GetGUID());
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsVendor() && player->GetReputationRank(1015) == REP_EXALTED)
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
};
/*######
## npc_flanis_swiftwing_and_kagrosh
######*/
enum Flanis : uint32
{
QUEST_THE_FATE_OF_FLANIS = 10583,
ITEM_FLAUNISS_PACK = 30658,
GOSSIP_MENU_FLANIS = 8356,
};
enum Kagrosh : uint32
{
QUEST_THE_FATE_OF_KAGROSH = 10601,
ITEM_KAGROSHS_PACK = 30659,
GOSSIP_MENU_KAGROSH = 8371,
};
class npcs_flanis_swiftwing_and_kagrosh : public CreatureScript
{
public:
npcs_flanis_swiftwing_and_kagrosh() : CreatureScript("npcs_flanis_swiftwing_and_kagrosh") { }
bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
ItemPosCountVec dest;
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_FLAUNISS_PACK, 1, nullptr);
if (msg == EQUIP_ERR_OK)
{
player->StoreNewItem(dest, ITEM_FLAUNISS_PACK, true);
}
}
if (action == GOSSIP_ACTION_INFO_DEF + 2)
{
ItemPosCountVec dest;
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_KAGROSHS_PACK, 1, nullptr);
if (msg == EQUIP_ERR_OK)
{
player->StoreNewItem(dest, ITEM_KAGROSHS_PACK, true);
}
}
CloseGossipMenuFor(player);
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetQuestStatus(QUEST_THE_FATE_OF_FLANIS) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_FLAUNISS_PACK, 1, true))
AddGossipItemFor(player, GOSSIP_MENU_FLANIS, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->GetQuestStatus(QUEST_THE_FATE_OF_KAGROSH) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_KAGROSHS_PACK, 1, true))
AddGossipItemFor(player, GOSSIP_MENU_KAGROSH, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
};
/*####
# npc_karynaku
####*/
@@ -2219,8 +2126,6 @@ void AddSC_shadowmoon_valley()
new npc_mature_netherwing_drake();
RegisterCreatureAI(npc_enslaved_netherwing_drake);
new npc_dragonmaw_peon();
new npc_drake_dealer_hurlunk();
new npcs_flanis_swiftwing_and_kagrosh();
new npc_karynaku();
new npc_lord_illidan_stormrage();
new go_crystal_prison();
@@ -20,101 +20,6 @@
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
/*
##################################################
Shattrath City Flask Vendors provides flasks to people exalted with 3 fActions:
Haldor the Compulsive
Arcanist Xorith
Both sell special flasks for use in Outlands 25man raids only,
purchasable for one Mark of Illidari each
Purchase requires exalted reputation with Scryers/Aldor, Cenarion Expedition and The Sha'tar
##################################################
*/
class npc_shattrathflaskvendors : public CreatureScript
{
public:
npc_shattrathflaskvendors() : CreatureScript("npc_shattrathflaskvendors") { }
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_TRADE)
player->GetSession()->SendListInventory(creature->GetGUID());
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->GetEntry() == 23484)
{
// Aldor vendor
if (creature->IsVendor() && (player->GetReputationRank(932) == REP_EXALTED) && (player->GetReputationRank(935) == REP_EXALTED) && (player->GetReputationRank(942) == REP_EXALTED))
{
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
SendGossipMenuFor(player, 11085, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 11083, creature->GetGUID());
}
}
if (creature->GetEntry() == 23483)
{
// Scryers vendor
if (creature->IsVendor() && (player->GetReputationRank(934) == REP_EXALTED) && (player->GetReputationRank(935) == REP_EXALTED) && (player->GetReputationRank(942) == REP_EXALTED))
{
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE);
SendGossipMenuFor(player, 11085, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, 11084, creature->GetGUID());
}
}
return true;
}
};
/*######
# npc_zephyr
######*/
enum Zephyr : int32
{
GOSSIP_MENU_ZEPHYR = 9205,
SPELL_TELEPORT_CAVERNS_OF_TIME = 37778,
};
class npc_zephyr : public CreatureScript
{
public:
npc_zephyr() : CreatureScript("npc_zephyr") { }
bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
player->CastSpell(player, SPELL_TELEPORT_CAVERNS_OF_TIME, false);
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetReputationRank(989) >= REP_REVERED)
AddGossipItemFor(player, GOSSIP_MENU_ZEPHYR, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;
}
};
/*######
# npc_kservant
@@ -415,8 +320,6 @@ struct npc_shattrath_daily_quest : public NullCreatureAI
void AddSC_shattrath_city()
{
new npc_shattrathflaskvendors();
new npc_zephyr();
new npc_kservant();
RegisterCreatureAI(npc_shattrath_daily_quest);
}
+1 -7
View File
@@ -314,11 +314,7 @@ public:
struct npc_training_dummy : NullCreatureAI
{
npc_training_dummy(Creature* creature) : NullCreatureAI(creature)
{
// TODO: Remove once WorldObject casting is ported
me->SetIsCombatDisallowed(false);
}
npc_training_dummy(Creature* creature) : NullCreatureAI(creature) { }
void JustEnteredCombat(Unit* who) override
{
@@ -363,8 +359,6 @@ struct npc_target_dummy : NullCreatureAI
{
npc_target_dummy(Creature* creature) : NullCreatureAI(creature)
{
// TODO: Remove once WorldObject casting is ported
me->SetIsCombatDisallowed(false);
_deathTimer = 15s;
}
-2
View File
@@ -1360,8 +1360,6 @@ inline constexpr uint64 IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK =
(UI64LIT(1) << MECHANIC_SNARE) |
(UI64LIT(1) << MECHANIC_STUN) |
(UI64LIT(1) << MECHANIC_FREEZE) |
(UI64LIT(1) << MECHANIC_SILENCE) |
(UI64LIT(1) << MECHANIC_DISARM) |
(UI64LIT(1) << MECHANIC_KNOCKOUT) |
(UI64LIT(1) << MECHANIC_POLYMORPH) |
(UI64LIT(1) << MECHANIC_BANISH) |