Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c57abd69f | |||
| e649402163 | |||
| a1c9172beb | |||
| b408c8a95d | |||
| f88a303327 | |||
| 8ad6a2aca3 | |||
| 36ac3dbd1d | |||
| 24d1ae71d9 | |||
| 9cef99f0ff | |||
| f409ffad12 | |||
| c1f7eaa153 | |||
| b455db0db8 | |||
| 1fb284cb5c | |||
| ebd8d81924 | |||
| 362084b829 | |||
| 656cf2d07d | |||
| bfe51f6ad4 | |||
| 2a3107a78d | |||
| 48826e21d6 | |||
| 15c476c12d | |||
| 6c4d7244c3 | |||
| 9fb80102c8 | |||
| 7028258084 | |||
| 5966eb0ffc | |||
| 90c8db0b04 | |||
| 9240bf1243 | |||
| 88f8dcb0e7 | |||
| 9cb3c79dbe | |||
| 75e3b59442 | |||
| 030c2307c2 | |||
| 27d54f15a2 | |||
| 5e18c2b766 | |||
| 1c85341b1f | |||
| ef02839ea0 | |||
| 377927b878 | |||
| a251e56c59 | |||
| 7de018f7eb | |||
| abb25f56d1 | |||
| 7a92231614 | |||
| f2952c905a | |||
| 8abd40f217 | |||
| 34cc87a5f9 | |||
| f986fdcddd | |||
| a212717c37 | |||
| 49cb354133 | |||
| 7298d89c9a | |||
| 3a2ae82593 | |||
| 16717acdd3 | |||
| d96123e661 | |||
| 8a0da95ed2 | |||
| 8363b1b6c8 | |||
| 2874119c6d | |||
| 56fa2fc7f7 | |||
| 5deb9e3255 | |||
| ecd8eacb1f | |||
| 1811c0ec35 | |||
| fae3ff5028 | |||
| 20a24b7935 | |||
| 526022e2bc | |||
| 4a1f4d02f0 | |||
| 4d2a80ddb8 | |||
| 81df32963f | |||
| 2b98ddeadd | |||
| 4c999bee3f | |||
| ba1cca9521 | |||
| b797877558 | |||
| 326644bbac | |||
| 36fdf9af82 | |||
| 579574acb3 | |||
| 63ab74b4fb | |||
| df7e943a74 | |||
| 203356aca8 | |||
| e2bed00b5c | |||
| fdc5849a69 | |||
| 2f8c374569 |
@@ -0,0 +1,161 @@
|
||||
# When a release is published on this repo (or manual dispatch):
|
||||
# 1. Builds the Electron launcher from that tag (npm run pack:win).
|
||||
# 2. Downloads any assets attached to the same release on this repo (patches, Wow exe, …).
|
||||
# 3. Merges them (launcher files win on name collision) and creates/updates the matching
|
||||
# release on Fractured-Distro.
|
||||
#
|
||||
# Setup (GitHub → Settings → Secrets and variables → Actions):
|
||||
# DISTRO_SYNC_TOKEN — PAT with releases write on Fractured-Distro (see repo README).
|
||||
#
|
||||
# Change DISTRO_REPO or the job `if:` if your GitHub slugs differ.
|
||||
|
||||
name: Sync release to Fractured-Distro
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag on this repo (must exist; e.g. v1.0.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
DISTRO_REPO: Dawnforger/Fractured-Distro
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
outputs:
|
||||
tag: ${{ steps.t.outputs.tag }}
|
||||
steps:
|
||||
- name: Resolve tag
|
||||
id: t
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "tag=${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
build-electron:
|
||||
needs: meta
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.tag }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: npm
|
||||
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
||||
|
||||
- name: Install and pack (NSIS + portable)
|
||||
working-directory: tools/fractured-launcher-electron
|
||||
run: |
|
||||
npm ci
|
||||
npm run pack:win
|
||||
|
||||
- name: Stage launcher files for upload
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path launcher-publish | Out-Null
|
||||
Copy-Item tools/fractured-launcher-electron/dist/*.exe launcher-publish/
|
||||
if (Test-Path tools/fractured-launcher-electron/dist/latest.yml) {
|
||||
Copy-Item tools/fractured-launcher-electron/dist/latest.yml launcher-publish/
|
||||
}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: electron-dist
|
||||
path: launcher-publish/
|
||||
|
||||
sync-distro:
|
||||
needs: [meta, build-electron]
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.repository.default_branch }}
|
||||
sparse-checkout: |
|
||||
tools/fractured-launcher-electron/scripts
|
||||
sparse-checkout-cone-mode: true
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: electron-dist
|
||||
path: /tmp/electron
|
||||
|
||||
- name: Merge main release assets + Electron build
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. tools/fractured-launcher-electron/scripts/release-sync-filters.sh
|
||||
TAG="${{ needs.meta.outputs.tag }}"
|
||||
mkdir -p combined
|
||||
mkdir -p /tmp/from-main
|
||||
if gh release download "$TAG" -R "${{ github.repository }}" -D /tmp/from-main 2>/tmp/dl.err; then
|
||||
shopt -s nullglob
|
||||
for f in /tmp/from-main/*; do
|
||||
if [ -f "$f" ]; then
|
||||
bn=$(basename "$f")
|
||||
if should_skip_merge_from_github "$bn"; then
|
||||
echo "Skipping GitHub release asset (CI launcher or excluded): $bn"
|
||||
continue
|
||||
fi
|
||||
cp -f "$f" combined/
|
||||
fi
|
||||
done
|
||||
echo "Merged assets from ${{ github.repository }} release $TAG"
|
||||
else
|
||||
echo "Main release download note (continuing with launcher only):"
|
||||
cat /tmp/dl.err || true
|
||||
fi
|
||||
shopt -s nullglob
|
||||
for f in /tmp/electron/*; do
|
||||
if [ -f "$f" ]; then
|
||||
cp -f "$f" combined/
|
||||
fi
|
||||
done
|
||||
echo "Combined directory:"
|
||||
ls -la combined/
|
||||
|
||||
- name: Upload to Fractured-Distro
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.DISTRO_SYNC_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -z "${GH_TOKEN:-}" ]; then
|
||||
echo "Missing secret DISTRO_SYNC_TOKEN (PAT with access to $DISTRO_REPO)."
|
||||
exit 1
|
||||
fi
|
||||
TAG="${{ needs.meta.outputs.tag }}"
|
||||
shopt -s nullglob
|
||||
files=(combined/*)
|
||||
if [ "${#files[@]}" -eq 0 ]; then
|
||||
echo "Nothing to upload (Electron pack produced no files?)."
|
||||
exit 1
|
||||
fi
|
||||
SRC_URL="https://github.com/${{ github.repository }}/releases/tag/${TAG}"
|
||||
if gh release view "$TAG" -R "$DISTRO_REPO" &>/dev/null; then
|
||||
gh release upload "$TAG" -R "$DISTRO_REPO" "${files[@]}" --clobber
|
||||
echo "Uploaded (clobber) to $DISTRO_REPO release $TAG"
|
||||
else
|
||||
gh release create "$TAG" -R "$DISTRO_REPO" \
|
||||
--title "Fractured $TAG" \
|
||||
--notes "Synced from [$TAG]($SRC_URL) on ${{ github.repository }}. Includes CI-built Electron launcher + release assets." \
|
||||
"${files[@]}"
|
||||
echo "Created $DISTRO_REPO release $TAG with ${#files[@]} asset(s)."
|
||||
fi
|
||||
@@ -0,0 +1,80 @@
|
||||
# Verifies Electron launcher Windows pack and uploads installers for testing.
|
||||
|
||||
name: Fractured launcher CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [master, main]
|
||||
paths:
|
||||
- 'tools/fractured-launcher-electron/**'
|
||||
- '.github/workflows/fractured-launcher-ci.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'tools/fractured-launcher-electron/**'
|
||||
- '.github/workflows/fractured-launcher-ci.yml'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: fractured-launcher-ci-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
electron-launcher-windows:
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 45
|
||||
defaults:
|
||||
run:
|
||||
working-directory: tools/fractured-launcher-electron
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: npm
|
||||
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
||||
|
||||
- name: Install and pack (NSIS + portable)
|
||||
run: |
|
||||
npm ci
|
||||
npm run pack:win
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fractured-launcher-electron-windows-${{ github.run_id }}
|
||||
if-no-files-found: warn
|
||||
path: |
|
||||
tools/fractured-launcher-electron/dist/*.exe
|
||||
tools/fractured-launcher-electron/dist/latest.yml
|
||||
|
||||
electron-launcher-linux:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
defaults:
|
||||
run:
|
||||
working-directory: tools/fractured-launcher-electron
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: npm
|
||||
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
||||
|
||||
- name: Install and pack (AppImage)
|
||||
run: |
|
||||
npm ci
|
||||
npm run pack:linux
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fractured-launcher-electron-linux-${{ github.run_id }}
|
||||
if-no-files-found: warn
|
||||
path: |
|
||||
tools/fractured-launcher-electron/dist/*.AppImage
|
||||
tools/fractured-launcher-electron/dist/latest.yml
|
||||
tools/fractured-launcher-electron/dist/latest-linux.yml
|
||||
@@ -0,0 +1,248 @@
|
||||
# Primary path for player-facing binaries: every *published* GitHub Release on this repo
|
||||
# is mirrored to your self-hosted Gitea (same tag). No public GitHub distro repo.
|
||||
#
|
||||
# Triggers:
|
||||
# - release: published / released → GitHub “Release” (not a raw git tag alone).
|
||||
# - workflow_dispatch → Actions → this workflow → “Run workflow” (enter tag).
|
||||
#
|
||||
# Troubleshooting: “Re-run failed jobs” on an OLD run replays the *original* workflow
|
||||
# YAML (e.g. still runs `npm run pack:win` without --publish never). After changing this
|
||||
# file on default branch, start a *new* run via “Run workflow”, not Re-run on a pre-fix run.
|
||||
#
|
||||
# Important: pushing only a git tag does NOT run this — you must create/publish a
|
||||
# Release on github.com (Releases → Draft/new release → Publish). The workflow
|
||||
# definition must exist on the repo DEFAULT branch (GitHub runs it from there).
|
||||
#
|
||||
# Steps: Windows (NSIS+portable) + Linux (AppImage) in parallel, launcher from DEFAULT BRANCH
|
||||
# overlay on tag checkout → merge with GitHub release assets → upload all to Gitea.
|
||||
#
|
||||
# Secrets: GITEA_BASE_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO
|
||||
# Optional variable: GITEA_TARGET_REF (see tools/fractured-launcher-electron/README.md)
|
||||
#
|
||||
# Job guard: edit `if:` if github.repository is not Dawnforger/Fractured.
|
||||
|
||||
name: Sync release to Gitea
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published, released]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Git tag only (e.g. v0.7.11-paragon-foo). NOT the release title — open the release and copy the tag next to the title.'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: gitea-release-sync-${{ github.repository }}-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.event.release.tag_name }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
outputs:
|
||||
tag: ${{ steps.t.outputs.tag }}
|
||||
steps:
|
||||
- name: Resolve tag
|
||||
id: t
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
RAW="${{ github.event.inputs.tag }}"
|
||||
else
|
||||
RAW="${{ github.event.release.tag_name }}"
|
||||
fi
|
||||
TAG="$(printf '%s' "$RAW" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
if [ -z "$TAG" ]; then
|
||||
echo '::error::Tag input is empty. Paste the git tag (e.g. v0.7.11-…).'
|
||||
exit 1
|
||||
fi
|
||||
if printf '%s' "$TAG" | grep -q '[[:space:]]'; then
|
||||
echo '::error::Tag contains whitespace — that is usually the **release title**, not the tag. On GitHub → Releases → open the release → copy the **tag** (short ref like v0.7.11-…), not the long title line.'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
{
|
||||
echo "tag<<__TAG_EOF__"
|
||||
echo "$TAG"
|
||||
echo "__TAG_EOF__"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
build-electron:
|
||||
needs: meta
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.tag }}
|
||||
|
||||
# Release tags often point at server/game commits that predate launcher lib fixes.
|
||||
# Always pack the launcher from default branch so app.asar includes the full tree.
|
||||
- name: Overlay launcher from default branch
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
DB="${{ github.event.repository.default_branch }}"
|
||||
git fetch --no-tags --depth=1 origin "+refs/heads/${DB}:refs/remotes/origin/${DB}"
|
||||
git checkout "origin/${DB}" -- tools/fractured-launcher-electron
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: npm
|
||||
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
||||
|
||||
- name: Install and pack (NSIS + portable)
|
||||
working-directory: tools/fractured-launcher-electron
|
||||
run: |
|
||||
npm ci
|
||||
node -p "'Launcher package.json version: ' + require('./package.json').version"
|
||||
npm run pack:win
|
||||
|
||||
- name: Stage launcher files for upload
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path launcher-publish | Out-Null
|
||||
Copy-Item tools/fractured-launcher-electron/dist/*.exe launcher-publish/
|
||||
if (Test-Path tools/fractured-launcher-electron/dist/latest.yml) {
|
||||
Copy-Item tools/fractured-launcher-electron/dist/latest.yml launcher-publish/
|
||||
}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: electron-dist-windows
|
||||
path: launcher-publish/
|
||||
|
||||
build-electron-linux:
|
||||
needs: meta
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.tag }}
|
||||
|
||||
- name: Overlay launcher from default branch
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
DB="${{ github.event.repository.default_branch }}"
|
||||
git fetch --no-tags --depth=1 origin "+refs/heads/${DB}:refs/remotes/origin/${DB}"
|
||||
git checkout "origin/${DB}" -- tools/fractured-launcher-electron
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: npm
|
||||
cache-dependency-path: tools/fractured-launcher-electron/package-lock.json
|
||||
|
||||
- name: Install and pack (AppImage)
|
||||
working-directory: tools/fractured-launcher-electron
|
||||
run: |
|
||||
npm ci
|
||||
node -p "'Launcher package.json version: ' + require('./package.json').version"
|
||||
npm run pack:linux
|
||||
|
||||
- name: Stage Linux launcher for upload
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p launcher-linux-publish
|
||||
shopt -s nullglob
|
||||
cp -f tools/fractured-launcher-electron/dist/*.AppImage launcher-linux-publish/ 2>/dev/null || true
|
||||
for f in tools/fractured-launcher-electron/dist/latest.yml tools/fractured-launcher-electron/dist/latest-linux.yml; do
|
||||
if [ -f "$f" ]; then cp -f "$f" launcher-linux-publish/; fi
|
||||
done
|
||||
ls -la launcher-linux-publish/
|
||||
if ! compgen -G "launcher-linux-publish/*.AppImage" > /dev/null; then
|
||||
echo "No AppImage under dist/ — electron-builder linux target failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: electron-dist-linux
|
||||
path: launcher-linux-publish/
|
||||
|
||||
sync-gitea:
|
||||
needs: [meta, build-electron, build-electron-linux]
|
||||
if: github.repository == 'Dawnforger/Fractured'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITEA_BASE_URL: ${{ secrets.GITEA_BASE_URL }}
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
GITEA_OWNER: ${{ secrets.GITEA_OWNER }}
|
||||
GITEA_REPO: ${{ secrets.GITEA_REPO }}
|
||||
GITEA_TARGET_REF: ${{ vars.GITEA_TARGET_REF }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Script may not exist on older release tags; always use default branch.
|
||||
ref: ${{ github.event.repository.default_branch }}
|
||||
sparse-checkout: |
|
||||
tools/fractured-launcher-electron/scripts
|
||||
sparse-checkout-cone-mode: true
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: electron-dist-windows
|
||||
path: /tmp/electron-win
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: electron-dist-linux
|
||||
path: /tmp/electron-linux
|
||||
|
||||
- name: Merge GitHub release assets + Electron build
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. tools/fractured-launcher-electron/scripts/release-sync-filters.sh
|
||||
TAG="${{ needs.meta.outputs.tag }}"
|
||||
mkdir -p combined
|
||||
mkdir -p /tmp/from-main
|
||||
if gh release download "$TAG" -R "${{ github.repository }}" -D /tmp/from-main 2>/tmp/dl.err; then
|
||||
shopt -s nullglob
|
||||
for f in /tmp/from-main/*; do
|
||||
if [ -f "$f" ]; then
|
||||
bn=$(basename "$f")
|
||||
if should_skip_merge_from_github "$bn"; then
|
||||
echo "Skipping GitHub release asset (CI launcher or excluded): $bn"
|
||||
continue
|
||||
fi
|
||||
cp -f "$f" combined/
|
||||
fi
|
||||
done
|
||||
echo "Merged assets from ${{ github.repository }} release $TAG"
|
||||
else
|
||||
echo "GitHub release download note (continuing with launcher only):"
|
||||
cat /tmp/dl.err || true
|
||||
fi
|
||||
shopt -s nullglob
|
||||
for f in /tmp/electron-win/* /tmp/electron-linux/*; do
|
||||
if [ -f "$f" ]; then
|
||||
cp -f "$f" combined/
|
||||
fi
|
||||
done
|
||||
ls -la combined/
|
||||
|
||||
- name: Upload to Gitea
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for v in GITEA_BASE_URL GITEA_TOKEN GITEA_OWNER GITEA_REPO; do
|
||||
if [ -z "${!v:-}" ]; then
|
||||
echo "Missing secret $v — add it under repo Settings → Secrets and variables → Actions." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
bash tools/fractured-launcher-electron/scripts/upload-release-to-gitea.sh combined "${{ needs.meta.outputs.tag }}"
|
||||
@@ -23,6 +23,7 @@
|
||||
/data/sql/custom/*
|
||||
/src/server/scripts/Custom/*
|
||||
!/src/server/scripts/Custom/README.md
|
||||
!/src/server/scripts/Custom/custom_script_loader.cpp
|
||||
|
||||
/*.override.yml
|
||||
/*.override.yaml
|
||||
@@ -119,3 +120,9 @@ local.properties
|
||||
!/modules/mod-ale/**
|
||||
# Team Docker: ALE needs Lua at configure time (see mod-ale docs)
|
||||
!docker-compose.override.yml
|
||||
|
||||
# Local build artifacts (do not commit)
|
||||
build-worldserver.log
|
||||
|
||||
# Local logs parked under contrib/fractured-dev-extras (see README there)
|
||||
contrib/fractured-dev-extras/*.log
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ include(ConfigInstall)
|
||||
CU_RUN_HOOK("AFTER_LOAD_CMAKE_MODULES")
|
||||
|
||||
find_package(PCHSupport)
|
||||
find_package(MySQL REQUIRED)
|
||||
find_package(MySQL REQUIRED COMPONENTS lib)
|
||||
|
||||
if(UNIX AND WITH_PERFTOOLS)
|
||||
find_package(Gperftools)
|
||||
|
||||
@@ -15,6 +15,58 @@ prerequisites; everything here is just the deltas you need on top of it.
|
||||
|
||||
---
|
||||
|
||||
## Fractured client + network defaults
|
||||
|
||||
Stock-friendly defaults for fresh local installs. A `git clone` ->
|
||||
`docker compose up` (or native install) lets a single developer log in
|
||||
from the same machine without any post-install config tweaks.
|
||||
|
||||
- **`authserver.conf` -> `RealmServerPort`** = **3724** (stock WoW). A
|
||||
patched `Wow.exe` with `set realmlist 127.0.0.1` (no port) reaches
|
||||
the auth handshake.
|
||||
- **`realmlist` table -> `port`** is the **world** port (default
|
||||
**8085**, matches `WorldServerPort` in `worldserver.conf.dist`).
|
||||
Auth tells the client to handshake to this port for the world hand-off.
|
||||
- **`realmlist` table -> `address`** defaults to **`127.0.0.1`** in the
|
||||
base SQL. The auth server hands this address to clients after login,
|
||||
so 127.0.0.1 means "talk to the world server on the same machine
|
||||
auth is running on" -- correct for solo dev. **Override on production
|
||||
deploys**, see *Production deployment overrides* below.
|
||||
|
||||
### Production deployment overrides
|
||||
|
||||
Production Fractured runs on a remote VPS at `hsrwow.net` with auth
|
||||
bound to a non-stock port (47497 -- 3724 was unavailable on that host).
|
||||
Apply the overrides **once per fresh dbimport** on the production box.
|
||||
|
||||
```sql
|
||||
-- Run against acore_auth on the production database after first dbimport:
|
||||
UPDATE realmlist
|
||||
SET address = 'hsrwow.net',
|
||||
port = 8085 -- world port; leave at 8085 unless changed
|
||||
WHERE id = 1;
|
||||
```
|
||||
|
||||
Edit the production `authserver.conf` (NOT `authserver.conf.dist`)
|
||||
to bind the auth listener to the production port:
|
||||
|
||||
```ini
|
||||
RealmServerPort = 47497
|
||||
```
|
||||
|
||||
Restart the auth server. Production clients connect with:
|
||||
|
||||
```text
|
||||
set realmlist hsrwow.net:47497
|
||||
```
|
||||
|
||||
The Fractured-patched 3.3.5 client supports the `host:port` syntax;
|
||||
stock 3.3.5 clients do not, so any contributor distributing the
|
||||
client bundle for production must include the patched `Wow.exe` from
|
||||
the GitHub release.
|
||||
|
||||
---
|
||||
|
||||
## What you get when you build this fork
|
||||
|
||||
- Worldserver with `CLASS_PARAGON` and Paragon-aware DK rune / sticky
|
||||
@@ -172,22 +224,19 @@ The standard AzerothCore three-database layout (`acore_auth`,
|
||||
|
||||
Easiest path: run the worldserver once with empty databases and let
|
||||
`AC_FORCE_CREATE_DB=1` populate them, **or** use `dbimport` from the
|
||||
install dir. Then layer the Fractured-specific SQL on top:
|
||||
install dir.
|
||||
|
||||
```bash
|
||||
cd <repo>/modules/mod-paragon/sql
|
||||
The Fractured-specific SQL (mod-paragon) lives under
|
||||
`modules/mod-paragon/data/sql/db-{world,characters}/base/` — that's the
|
||||
**AzerothCore-standard module layout**, which means AC's built-in
|
||||
DBUpdater picks it up automatically on every `worldserver` /
|
||||
`dbimport` start. New SQL files are applied; previously-applied ones
|
||||
are skipped via the hash recorded in `acore_world.updates` /
|
||||
`acore_characters.updates`. No manual `mysql < ...` steps required for
|
||||
deploys.
|
||||
|
||||
# world DB
|
||||
mysql -u acore -p acore_world < world/base/paragon_gametables.sql
|
||||
mysql -u acore -p acore_world < world/base/paragon_spell_ae_cost.sql
|
||||
mysql -u acore -p acore_world < world/base/player_class_stats_paragon_basemana.sql
|
||||
|
||||
# characters DB
|
||||
mysql -u acore -p acore_characters < characters/base/character_paragon_currency.sql
|
||||
```
|
||||
|
||||
Re-run any module-specific SQL whenever you pull updates that touch
|
||||
`modules/*/sql/`.
|
||||
Modify-and-redeploy works the same way: change the file, push, pull on
|
||||
the VPS, and the next `dbimport` run sees the new hash and re-applies.
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
# Fractured Client Patches
|
||||
|
||||
Binary client artifacts that pair with this server. They live on the
|
||||
[Releases page](https://github.com/Dawnforger/Fractured/releases),
|
||||
**not** in the tree, so the repo stays lean and binaries can be
|
||||
re-downloaded without bloating `git clone`.
|
||||
|
||||
This file is the table of contents and install guide.
|
||||
|
||||
**Launcher (Windows):** The maintained client launcher lives in
|
||||
[`tools/fractured-launcher-electron/`](../../tools/fractured-launcher-electron/)
|
||||
(see its README for build and config). **Public downloads** for the launcher
|
||||
and mirrored patch assets are pushed to
|
||||
[Fractured-Distro releases](https://github.com/Dawnforger/Fractured-Distro/releases)
|
||||
when a release is published here (workflow **Sync release to Fractured-Distro**).
|
||||
|
||||
---
|
||||
|
||||
## What ships in a release
|
||||
|
||||
| Artifact | Size | Purpose |
|
||||
|---|---|---|
|
||||
| `patch-enUS-4.MPQ` | ~5 MB | DBC + GlueXML bake. Adds `CLASS_PARAGON` (id 12), the character-create slot, glue strings, game-table DBCs, and a patched `Spell.dbc`: **(1)** `RuneCostID` zeroed on every rune-cost spell so non–Death Knight clients still send DK casts (rune costs are shown via `RuneFrame.lua`); **(2)** `Reagent[]` / `ReagentCount[]` zeroed on every spell whose `SpellFamilyName` is non-zero (all class abilities), while profession crafts (`SpellFamilyName == 0`) keep their materials. Both edits mirror server load-time corrections so client preflight and server validation stay aligned. Required for character creation as Paragon to even show up. |
|
||||
| `patch-enUS-5.MPQ` | ~64 KB | FrameXML overrides. Replaces stock `PlayerFrame.lua` / `RuneFrame.lua` / `ComboFrame.lua` / `UnitFrame.lua` / `SpellBookFrame.lua` + `SpellBookFrame.xml` with Paragon-aware versions: rune simulator, combo-point simulator, server-authoritative resource sync over the `PARAA` addon channel, action-button usability + click guards, an expanded spellbook (higher `MAX_SPELLS`, 24 skill-line tabs instead of stock 8) so all-class spells render, Paragon stat tooltips on the character sheet (including filtering duplicate “attack power from strength” lines so the paper doll matches server AP), a tooltip post-processor that appends ", Paragon" to the "Classes:" line on class-restricted gear / glyphs (the server bypasses `AllowableClass` for class 12, but the engine paints the line red and omits Paragon — the Lua hook recolors it green and adds the name so the player can tell it's wearable), a **spell-tooltip post-processor** that (1) recolors and appends "(Paragon: bypassed)" to "Requires *Stance*" lines on Warrior abilities (server-side `SpellInfo::CheckShapeshift` skips stance enforcement for Paragons on `SPELLFAMILY_WARRIOR` spells, but the client still renders the requirement from the stock `Stances` DBC field which we deliberately leave unzeroed so stock Warriors keep enforcement), (2) appends a Paragon line to **Maelstrom Weapon** (53817) noting that Fireball / Frostbolt / Arcane Blast also benefit, and (3) appends a Paragon line to **Mirror Image** (55342) noting that the images cast random damage spells with a cast time from the caster's spellbook instead of Frostbolt — all three patches gate on `UnitClass("player") == "PARAGON"` so stock-class tooltips are byte-identical to vanilla, and **PetFrame** re-anchored so the **pet unit frame sits below the rune row** for Paragon (stock layout had runes overlapping the pet portrait). A **Warrior stance click bypass** wraps `UseAction` so that for Paragon characters, clicking an action slot bound to a stance-gated Warrior ability (Whirlwind, Charge, Pummel, Shield Slam, Hamstring, Overpower, Shield Bash, Shield Block, Disarm, Revenge, Spell Reflection, Recklessness, Bladestorm, Shockwave, Concussion Blow, Last Stand, Sweeping Strikes, Mocking Blow, Heroic Fury, Slam, Devastate, Intercept) routes through `CastSpellByName(name)` instead of the engine's stance-gated `UseAction` path; the engine's stance pre-check inside `UseAction` would otherwise drop the cast packet client-side and our server-side `CheckShapeshift` bypass would never get to run. Stock classes never enter the bypass branch. The paper-doll **ammo slot** follows stock visibility rules (shown for hunters / ranged weapons; hidden when `UnitHasRelicSlot` applies). |
|
||||
| `patch-enUS-6.MPQ` | ~134 KB | The `ParagonAdvancement` addon. Replaces the talent pane (`N` key) for Paragon characters with the Character Advancement panel: per-class spell tabs, talent grid, Overview/Search tabs, AE/TE currency, commit / reset / preview, login-time toast suppression, a **PETS** tab with live hunter pet talent trees (preview learn, no TE/AE cost), a dedicated **Reset Pet Talents** control (server `PARAA` `C RESET PET TALENTS` — instant, no gold, no confirmation; requires matching worldserver), bottom-row **Reset all Abilities / Reset Build / Reset all Talents** disabled while on the PETS tab so those paths cannot dismiss the pet or unlearn Tame Beast, and a **Builds** page (full-pane overlay opened from the bottom-row Builds button) for saving named, icon-tagged loadouts: New Build (+) icon picker reuses `MACRO_ICON_FILENAMES`, right-click for edit/delete, shift-left-click to favorite (favorites bubble to the top), left-click pops a Load Build confirm. Build swaps reset + refund AE/TE, re-spend on the saved recipe, and **park hunter pets** to `PET_SAVE_NOT_IN_SLOT` so their name/talents/exp are preserved across swaps. |
|
||||
| `Wow.exe` | ~7.5 MB | 3.3.5a (build 12340) client byte-patched to skip the MPQ signature check so custom `patch-enUS-N.MPQ` files load. Diff against stock is a few bytes; everything else is unchanged. |
|
||||
|
||||
Server and client work as a pair: the addon talks to `mod-paragon` on the
|
||||
worldserver via `WHISPER` addon-channel messages with the `PARAA` prefix
|
||||
(currency push, spell/talent snapshot, commit, combo points, rune
|
||||
cooldowns, learn-toast silence window, **`C RESET PET TALENTS`**
|
||||
for hunter pet talent resets from the Character Advancement PETS tab,
|
||||
and the **build catalog** verbs `Q BUILDS` / `C BUILD NEW` / `C BUILD
|
||||
EDIT` / `C BUILD DELETE` / `C BUILD FAVORITE` / `C BUILD LOAD` for the
|
||||
saved-loadout system on the Builds page). Build swaps require the
|
||||
matching worldserver image because the swap path is server-driven
|
||||
(snapshot → reset → re-spend → pet park/unpark). Mismatched versions
|
||||
usually manifest as the panel rendering blank or AE/TE reading 0/0.
|
||||
|
||||
---
|
||||
|
||||
## Install
|
||||
|
||||
You need a 3.3.5a (build 12340) WoW client. ChromieCraft's free 3.3.5a
|
||||
download is the canonical clean source if you don't already have one.
|
||||
|
||||
1. Download every artifact from the latest release matching this server
|
||||
build:
|
||||
`https://github.com/Dawnforger/Fractured/releases/latest`
|
||||
2. Replace `Wow.exe` at the root of your client install with the patched
|
||||
one from the release. Keep a backup of the original if you want.
|
||||
3. Drop `patch-enUS-4.MPQ`, `patch-enUS-5.MPQ`, `patch-enUS-6.MPQ` into
|
||||
`Data/enUS/`. (For other locales, rename the suffix accordingly —
|
||||
contents are locale-independent, only the filename ordering matters
|
||||
to the loader.)
|
||||
4. Edit `Data/enUS/realmlist.wtf` to point at your server, e.g.
|
||||
`set realmlist your.host.tld`.
|
||||
5. Launch `Wow.exe`. The login screen should reach the realm list. Make
|
||||
a Paragon character (the new class entry on the create screen) and
|
||||
press `N` in-world to open the Character Advancement panel.
|
||||
|
||||
If the panel opens empty / AE+TE read 0/0 / `N` opens the stock talent
|
||||
pane: your client is loading an older `patch-enUS-6.MPQ`, or the
|
||||
worldserver image is older than commit `4d2a80d` (the
|
||||
`character_paragon_panel_spell_revoked` migration). Pull both ends to
|
||||
the same release tag and rebuild the worldserver image.
|
||||
|
||||
If the **client** shows the Paragon class on the create screen but the
|
||||
server replies **Character Creation Failed** (sometimes shown as
|
||||
"Error creating character") when you pick it -- **or** the character
|
||||
is created but spawns with no weapon / armor proficiencies (auto-attack
|
||||
greys out, can't equip anything beyond a fist), or with the proficiency
|
||||
**skills** but no **passive spells** like Block, Parry, Dual Wield --
|
||||
the worldserver is missing one of four pieces of class-12 data. All
|
||||
ship as SQL migrations under
|
||||
`modules/mod-paragon/data/sql/db-world/updates/` and are auto-applied
|
||||
by AzerothCore's DBUpdater on every `ac-db-import` run, but the SQL
|
||||
files are baked into the dbimport Docker image at build time -- so a
|
||||
stale image won't pick up new migrations. Fix:
|
||||
|
||||
```bash
|
||||
git pull origin main
|
||||
docker compose build ac-db-import ac-worldserver
|
||||
docker compose up -d ac-db-import
|
||||
docker compose restart ac-worldserver
|
||||
```
|
||||
|
||||
Existing class-12 characters created before these migrations will
|
||||
keep their broken state -- the cascade only fires inside
|
||||
`Player::Create` and `Player::LearnDefaultSkill` at character spawn.
|
||||
Delete the old Paragon and re-roll after the rebuild.
|
||||
|
||||
The four migrations:
|
||||
|
||||
- `2026_05_09_00.sql` -- DBC overlay rows for `chrclasses_dbc` and
|
||||
`skillraceclassinfo_dbc`. Without this the server can't even
|
||||
resolve class 12 in `sChrClassesStore`. See **Server-side Paragon
|
||||
DBC overlay** below.
|
||||
- `2026_05_10_00.sql` -- `playercreateinfo`, `playercreateinfo_action`,
|
||||
and `player_class_stats` rows for class 12. Without this
|
||||
`Player::Create` rejects every (race, class=12) pair as an
|
||||
"invalid race/class pair" and the worldserver prints
|
||||
`class-N Level-L does not have stats data!` integrity warnings on
|
||||
load.
|
||||
- `2026_05_10_01.sql` -- 20 `playercreateinfo_skills` rows
|
||||
(`classMask = 2048` = class 12) granting every weapon /
|
||||
armor proficiency at level 1. Without this a Paragon spawns with
|
||||
only the universal `classMask = 0` skills (Defense, Unarmed,
|
||||
Cloth, languages, Mounts) -- no Swords, no Mail, no Shield, etc.
|
||||
- `2026_05_10_02.sql` -- 3,314 `skilllineability_dbc` rows opening
|
||||
the class-12 bit on every SkillLineAbility row our patched
|
||||
`SkillLineAbility.dbc` modified. AC reads these rows in
|
||||
`Player::LearnDefaultSkill` to drive the `skill -> passive spell`
|
||||
cascade. Without it the proficiency *skills* from `_01.sql` exist
|
||||
but the *passive spells* (Block, Parry, Dual Wield, Defense,
|
||||
weapon Shoot, racial Mace/Sword Specialization, etc.) never auto-
|
||||
learn, so the spellbook past the racials looks empty.
|
||||
|
||||
After the rebuild + restart, `ac-worldserver` should log
|
||||
`>> Loaded 72 Player Create Definitions` (was 62 pre-Paragon),
|
||||
`>> Loaded 1391 Player Create Skills` (was 1371),
|
||||
`>> Loaded 10219 SkillLineAbility MultiMap Data` (unchanged total --
|
||||
the SQL overlay replaces existing rows by ID, doesn't add new ones),
|
||||
and character creation succeeds for any DK-eligible race with a full
|
||||
weapon / armor kit and the matching passive spells.
|
||||
|
||||
If the client **logs in** successfully but **disconnects immediately**
|
||||
when entering the realm: the auth server is handing your client the
|
||||
wrong world-server address. On a fresh local install the seed defaults
|
||||
to `127.0.0.1` (commit landing this paragraph). If your DB was
|
||||
imported from an older Fractured checkout, the seed may still point at
|
||||
`hsrwow.net`, which sends the client to our production world server
|
||||
instead of yours. Fix:
|
||||
|
||||
```bash
|
||||
# Docker:
|
||||
docker exec ac-database mysql -uroot -ppassword \
|
||||
-e "UPDATE acore_auth.realmlist SET address='127.0.0.1' WHERE id=1;"
|
||||
docker compose restart ac-authserver
|
||||
```
|
||||
|
||||
Substitute your public hostname/IP for `127.0.0.1` if remote players
|
||||
will be connecting. See `BUILD-NATIVE.md` -> *Production deployment
|
||||
overrides* for the full list of values to set on a production box.
|
||||
|
||||
---
|
||||
|
||||
## Server-side Paragon DBC overlay (automatic)
|
||||
|
||||
The Fractured **client** learns about Paragon from `patch-enUS-4.MPQ`
|
||||
(DBC + GlueXML). The **worldserver** never reads your MPQs — it reads
|
||||
plain `.dbc` files under its `DataDir` (`.../data/dbc/` by default).
|
||||
|
||||
Stock Docker installs populate `data/dbc/` from a vanilla 3.3.5a
|
||||
extract (`ac-client-data-init` in `docker-compose.yml`). That tree has
|
||||
no `ChrClasses` row for id **12** and no class-12 bit on
|
||||
`SkillRaceClassInfo` rows, which would normally trigger:
|
||||
|
||||
`Class (12) not found in DBC while creating new char ... wrong DBC files or cheater?`
|
||||
|
||||
…and reject the create with `CHAR_CREATE_FAILED`.
|
||||
|
||||
To remove that gap, the repo ships
|
||||
`modules/mod-paragon/data/sql/db-world/updates/2026_05_09_00.sql`,
|
||||
which `INSERT`s the Paragon class-12 deltas into:
|
||||
|
||||
- `chrclasses_dbc` — 1 row defining class 12 ("Paragon", power=Mana,
|
||||
family=Warrior, expansion=2).
|
||||
- `skillraceclassinfo_dbc` — 235 rows replacing stock entries with the
|
||||
patched ClassMask (class-12 bit OR'd in) so every baseline skill is
|
||||
available to Paragon characters.
|
||||
|
||||
`AzerothCore`'s DBC loader (`DBCStores.cpp::LoadDBC` -> `LoadFromDB`)
|
||||
merges these rows on top of whatever `data/dbc/` contains at every
|
||||
worldserver boot. The DBUpdater in `ac-db-import` (Docker) or the
|
||||
worldserver itself (native) applies the migration automatically — so
|
||||
the **only** steps a fresh contributor needs are `git clone` and
|
||||
`docker compose up -d`.
|
||||
|
||||
### Regenerating the migration
|
||||
|
||||
The SQL is auto-generated from the patched DBCs that already live
|
||||
inside `patch-enUS-4.MPQ`. The bake script lives outside this repo
|
||||
(per the repo-tidy policy) at:
|
||||
|
||||
`fractured-tooling/from-workspace-root/_gen_paragon_dbc_overlay_sql.py`
|
||||
|
||||
Re-run it whenever you change the Paragon DBC bake — for example,
|
||||
adding a new race to the Paragon class mask. It diffs the patched
|
||||
DBCs against a stock 3.3.5a DBC extract and emits a fresh
|
||||
`2026_05_09_00.sql` (or successor migration with a new timestamp if
|
||||
deltas change). Workflow:
|
||||
|
||||
```powershell
|
||||
# Extract the patched DBCs once:
|
||||
.\tools\mpq\mpqcli.exe extract `
|
||||
"ChromieCraft_3.3.5a\Data\enUS\patch-enUS-4.MPQ" `
|
||||
-o "$env:TEMP\paragon-dbc-extract"
|
||||
|
||||
# Regenerate the SQL migration:
|
||||
python fractured-tooling\from-workspace-root\_gen_paragon_dbc_overlay_sql.py
|
||||
```
|
||||
|
||||
If the regenerated SQL has new content, commit it as a **new** dated
|
||||
migration filename (e.g. `2026_06_01_00.sql`) — never edit a file that
|
||||
has already been applied to live databases, AC's DBUpdater will detect
|
||||
the hash change and re-run the SQL, which can be fine but is best
|
||||
reserved for emergencies.
|
||||
|
||||
### Manual DBC overlay (rare, fallback)
|
||||
|
||||
If you ever need the patched DBCs *on disk* — e.g. for a tool that
|
||||
reads `data/dbc/` directly outside the worldserver, or to verify a
|
||||
client-vs-server DBC mismatch — extract `patch-enUS-4.MPQ` and copy
|
||||
its `DBFilesClient/*.dbc` into `data/dbc/`:
|
||||
|
||||
**Docker:**
|
||||
|
||||
```powershell
|
||||
docker run --rm `
|
||||
-v ac-client-data:/data `
|
||||
-v ${PWD}\paragon-dbc-extract:/patch:ro `
|
||||
alpine sh -c "cp -f /patch/*.dbc /data/dbc/"
|
||||
docker compose restart ac-worldserver
|
||||
```
|
||||
|
||||
**Native:** copy into `<CMAKE_INSTALL_PREFIX>/data/dbc/` and restart.
|
||||
|
||||
This is **not required** for normal operation — the SQL migration
|
||||
covers everything `mod-paragon` needs at runtime. Use the manual
|
||||
overlay only when you're consciously bypassing the SQL merge layer.
|
||||
|
||||
---
|
||||
|
||||
## Building the patches yourself
|
||||
|
||||
The MPQs are reproducible from the dev tree (not in this repo —
|
||||
`Classless Dev/Paragon Patch UI/` and
|
||||
`Classless Dev/Paragon Advancement/` on the maintainer's workstation)
|
||||
via two PowerShell scripts in `tools/`:
|
||||
|
||||
```
|
||||
tools\build_paragon_ui_patch.ps1 -Deploy # -> patch-enUS-5.MPQ
|
||||
tools\build_paragon_advancement_patch.ps1 -Deploy # -> patch-enUS-6.MPQ
|
||||
```
|
||||
|
||||
`patch-enUS-4.MPQ` is the DBC + GlueXML bake; the bake scripts live with
|
||||
the rest of the dev tooling and are not part of this repo by design
|
||||
(see the repo-tidy policy in `README.txt` next to this file). Typical
|
||||
order on a maintainer machine:
|
||||
|
||||
1. `fractured-tooling/from-workspace-root/_patch_spell_dbc_runes.py` — stage `Spell.dbc` with `RuneCostID` cleared.
|
||||
2. `fractured-tooling/from-workspace-root/_patch_spell_dbc_reagents.py` — same staged `Spell.dbc`, clear class-spell reagents for client preflight.
|
||||
3. `fractured-tooling/from-workspace-root/_patch_spell_dbc_stances.py` — same staged `Spell.dbc`, zero the `Stances` field on every `SpellFamilyName == 4` (Warrior) row so the client engine's "Must be in Battle/Defensive/Berserker Stance" pre-cast check stops eating `CMSG_CAST_SPELL` packets for Paragon casters who never picked the stance form. The server's `SpellInfo::CheckShapeshift` Paragon bypass takes over from there. Stock Warriors still see the server-side stance error mid-cast if they actually click while out of stance.
|
||||
4. `fractured-tooling/from-workspace-root/_make_paragon_dbc_patch.py` — rebuild `ChrClasses` / `CharBaseInfo` / game tables, then pack `patch-enUS-4.MPQ`.
|
||||
|
||||
The patched `Wow.exe` is a one-time hex-edit of the stock 3.3.5a
|
||||
client. The diff is publicly documented in the WoW emulation community
|
||||
under names like "MPQ signature patch" / "no-CD-signature patch".
|
||||
|
||||
---
|
||||
|
||||
## Versioning
|
||||
|
||||
Releases are tagged to match the state of `main` they were built from.
|
||||
The release notes call out which server commit shipped alongside each
|
||||
artifact set, so a contributor running `git checkout <tag>` on this
|
||||
repo can pull the matching client bundle and have a guaranteed-aligned
|
||||
end-to-end build.
|
||||
@@ -0,0 +1,16 @@
|
||||
Fractured / Paragon — non-runtime repo extras
|
||||
==============================================
|
||||
|
||||
This folder holds material that is not required to configure, build, or run
|
||||
AzerothCore. Upstream AzerothCore does not ship these paths.
|
||||
|
||||
Contents:
|
||||
- BUILD-NATIVE.md — fork-specific native build notes (moved from repo root).
|
||||
- CLAUDE.md — optional AI assistant context (moved from repo root).
|
||||
- CLIENT-PATCHES.md — what ships in a Fractured client release (MPQs +
|
||||
patched Wow.exe), where to download them (Releases page), and how
|
||||
to install them. Binaries themselves are NOT in the tree.
|
||||
- *.log — local build logs (moved from repo root when present).
|
||||
|
||||
Operational files (docker-compose.override.yml, env/dist, modules/mod-paragon,
|
||||
etc.) stay at their normal locations.
|
||||
@@ -58,16 +58,16 @@ INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`,
|
||||
(90991, 90993, 4, 270, 515);
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (91247,91248,91249,90985,90986,90987,90988,90989,90990);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(91247, 91247, 3),
|
||||
(91247, 91248, 3),
|
||||
(91247, 91249, 3),
|
||||
(90985, 90985, 3),
|
||||
(90985, 90986, 3),
|
||||
(90985, 90987, 3),
|
||||
(90988, 90988, 3),
|
||||
(90988, 90989, 3),
|
||||
(90988, 90990, 3);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(91247, 91247, 0, 0, 3),
|
||||
(91247, 91248, 0, 0, 3),
|
||||
(91247, 91249, 0, 0, 3),
|
||||
(90985, 90985, 0, 0, 3),
|
||||
(90985, 90986, 0, 0, 3),
|
||||
(90985, 90987, 0, 0, 3),
|
||||
(90988, 90988, 0, 0, 3),
|
||||
(90988, 90989, 0, 0, 3),
|
||||
(90988, 90990, 0, 0, 3);
|
||||
|
||||
UPDATE `creature` SET `id1` = 15384 WHERE `guid` = 91250 AND `id1` = 19871;
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@ INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_
|
||||
(17653, 0, 3, 0, 4, 0, 100, 512, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 9, 17653, 0, 100, 1, 0, 0, 0, 0, 'Shadowmoon Channeler - On Aggro - Set In Combat With Zone');
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (@CGUID+0,@CGUID+1,@CGUID+2,@CGUID+3,@CGUID+4,@CGUID+5);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(@CGUID+0, @CGUID+5, 24),
|
||||
(@CGUID+1, @CGUID+5, 24),
|
||||
(@CGUID+2, @CGUID+5, 24),
|
||||
(@CGUID+3, @CGUID+5, 24),
|
||||
(@CGUID+4, @CGUID+5, 24),
|
||||
(@CGUID+5, @CGUID+5, 24);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@CGUID+0, @CGUID+5, 0, 0, 24),
|
||||
(@CGUID+1, @CGUID+5, 0, 0, 24),
|
||||
(@CGUID+2, @CGUID+5, 0, 0, 24),
|
||||
(@CGUID+3, @CGUID+5, 0, 0, 24),
|
||||
(@CGUID+4, @CGUID+5, 0, 0, 24),
|
||||
(@CGUID+5, @CGUID+5, 0, 0, 24);
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (-138519,-138519,-138520,-138521,-138522,-138523));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
|
||||
@@ -18,7 +18,7 @@ INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry
|
||||
(13, 1, 30952, 0, 0, 31, 0, 3, 17687, 0, 0, 0, 0, '', 'Shoot Flame Arrow (30952) only hit Flame Arrow (17687)');
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (151094,151095,151096,151097);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(151095,151095,3),
|
||||
(151096,151095,3),
|
||||
(151097,151095,3);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(151095, 151095, 0, 0, 3),
|
||||
(151096, 151095, 0, 0, 3),
|
||||
(151097, 151095, 0, 0, 3);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
-- DB update 2023_07_10_00 -> 2023_07_10_01
|
||||
--
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (90978, 90979, 90980, 90981, 90982);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(90978, 90978, 3),
|
||||
(90979, 90978, 3),
|
||||
(90980, 90978, 3),
|
||||
(90981, 90978, 3),
|
||||
(90982, 90978, 3);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(90978, 90978, 0, 0, 3),
|
||||
(90979, 90978, 0, 0, 3),
|
||||
(90980, 90978, 0, 0, 3),
|
||||
(90981, 90978, 0, 0, 3),
|
||||
(90982, 90978, 0, 0, 3);
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
-- DB update 2023_07_17_00 -> 2023_07_17_01
|
||||
--
|
||||
SET @attrmask_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'spell_enchant_proc_data'
|
||||
AND COLUMN_NAME = 'attributeMask'
|
||||
);
|
||||
SET @sql := IF(
|
||||
@attrmask_exists > 0,
|
||||
'SELECT 1',
|
||||
'ALTER TABLE `spell_enchant_proc_data` ADD COLUMN `attributeMask` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `procEx`'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
UPDATE `spell_enchant_proc_data` SET `attributeMask` = 0x2 WHERE `entry` = 2675;
|
||||
|
||||
@@ -3,7 +3,7 @@ UPDATE `creature_template` SET `scriptname` = '' WHERE `entry` = 27326;
|
||||
|
||||
DELETE FROM `spell_target_position` WHERE `ID` = 48324 AND `EffectIndex` = 0;
|
||||
INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `VerifiedBuild`) VALUES
|
||||
(48324, 0, 571, 3454.11, -2802.37, 202.14, 0, 34149345);
|
||||
(48324, 0, 571, 3454.11, -2802.37, 202.14, 0, 0);
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` IN (48382, 47533);
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
-- DB update 2023_08_12_02 -> 2023_08_13_00
|
||||
--
|
||||
SET @csg_comment_exists := (
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'creature_summon_groups'
|
||||
AND COLUMN_NAME = 'Comment'
|
||||
);
|
||||
SET @sql := IF(
|
||||
@csg_comment_exists > 0,
|
||||
'SELECT 1',
|
||||
'ALTER TABLE `creature_summon_groups` ADD COLUMN `Comment` varchar(255) NOT NULL DEFAULT '''' AFTER `summonTime`'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
DELETE FROM `event_scripts` WHERE `id` = 14376;
|
||||
|
||||
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 185220;
|
||||
|
||||
@@ -1362,132 +1362,132 @@ UPDATE `creature_template_addon` SET `bytes2` = 1 WHERE (`entry` IN (21224, 2122
|
||||
UPDATE `creature_template` SET `speed_walk` = 1.6, `speed_run` = 1.71428 WHERE (`entry` IN (21218, 21301));
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (@CGUID+1 ,@CGUID+2 ,@CGUID+3 ,@CGUID+4 ,@CGUID+5 ,@CGUID+6 ,@CGUID+7 ,@CGUID+8 ,@CGUID+9 ,@CGUID+10 ,@CGUID+11 ,@CGUID+12 ,@CGUID+13 ,@CGUID+14 ,@CGUID+15 ,@CGUID+22 ,@CGUID+23 ,@CGUID+24 ,@CGUID+25 ,@CGUID+26 ,@CGUID+27 ,@CGUID+28 ,@CGUID+29 ,@CGUID+30 ,@CGUID+31 ,@CGUID+32 ,@CGUID+33 ,@CGUID+34 ,@CGUID+35 ,@CGUID+36 ,@CGUID+37 ,@CGUID+38 ,@CGUID+39 ,@CGUID+40 ,@CGUID+41 ,@CGUID+42 ,@CGUID+43 ,@CGUID+44 ,@CGUID+45 ,@CGUID+46 ,@CGUID+47 ,@CGUID+48 ,@CGUID+49 ,@CGUID+50 ,@CGUID+51 ,@CGUID+52 ,@CGUID+53 ,@CGUID+54 ,@CGUID+55 ,@CGUID+56 ,@CGUID+57 ,@CGUID+58 ,@CGUID+59 ,@CGUID+60 ,@CGUID+61 ,@CGUID+62 ,@CGUID+63 ,@CGUID+64 ,@CGUID+65 ,@CGUID+66 ,@CGUID+67 ,@CGUID+68 ,@CGUID+69 ,@CGUID+70 ,@CGUID+71 ,@CGUID+72 ,@CGUID+73 ,@CGUID+74 ,@CGUID+75 ,@CGUID+76 ,@CGUID+77 ,@CGUID+78 ,@CGUID+79 ,@CGUID+80 ,@CGUID+81 ,@CGUID+82 ,@CGUID+83 ,@CGUID+84 ,@CGUID+85 ,@CGUID+86 ,@CGUID+87 ,@CGUID+88 ,@CGUID+89 ,@CGUID+90 ,@CGUID+91 ,@CGUID+92 ,@CGUID+93 ,@CGUID+94 ,@CGUID+95 ,@CGUID+96 ,@CGUID+97 ,@CGUID+98 ,@CGUID+99 ,@CGUID+102,@CGUID+103,@CGUID+104,@CGUID+105,@CGUID+106,@CGUID+107,@CGUID+108,@CGUID+109,@CGUID+115,@CGUID+116,@CGUID+117,@CGUID+118,@CGUID+119,@CGUID+120,@CGUID+121,@CGUID+122,@CGUID+123,@CGUID+124,@CGUID+125,@CGUID+126,@CGUID+127,@CGUID+128,@CGUID+129,@CGUID+130,@CGUID+131,@CGUID+132,@CGUID+133,@CGUID+134,@CGUID+135,@CGUID+136,@CGUID+137,@CGUID+138);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(@CGUID+1 , @CGUID+1 , 3),
|
||||
(@CGUID+2 , @CGUID+1 , 3),
|
||||
(@CGUID+3 , @CGUID+1 , 3),
|
||||
(@CGUID+4 , @CGUID+1 , 3),
|
||||
(@CGUID+5 , @CGUID+1 , 3),
|
||||
(@CGUID+6 , @CGUID+6 , 3),
|
||||
(@CGUID+7 , @CGUID+6 , 3),
|
||||
(@CGUID+8 , @CGUID+6 , 3),
|
||||
(@CGUID+9 , @CGUID+6 , 3),
|
||||
(@CGUID+10 , @CGUID+6 , 3),
|
||||
(@CGUID+11 , @CGUID+11 , 3),
|
||||
(@CGUID+12 , @CGUID+11 , 3),
|
||||
(@CGUID+13 , @CGUID+11 , 3),
|
||||
(@CGUID+14 , @CGUID+11 , 3),
|
||||
(@CGUID+15 , @CGUID+11 , 3),
|
||||
(@CGUID+22 , @CGUID+22 , 3),
|
||||
(@CGUID+23 , @CGUID+22 , 3),
|
||||
(@CGUID+24 , @CGUID+22 , 3),
|
||||
(@CGUID+25 , @CGUID+22 , 3),
|
||||
(@CGUID+26 , @CGUID+22 , 3),
|
||||
(@CGUID+27 , @CGUID+22 , 3),
|
||||
(@CGUID+28 , @CGUID+22 , 3),
|
||||
(@CGUID+29 , @CGUID+22 , 3),
|
||||
(@CGUID+30 , @CGUID+22 , 3),
|
||||
(@CGUID+31 , @CGUID+31 , 3),
|
||||
(@CGUID+32 , @CGUID+31 , 3),
|
||||
(@CGUID+33 , @CGUID+31 , 3),
|
||||
(@CGUID+34 , @CGUID+31 , 3),
|
||||
(@CGUID+35 , @CGUID+31 , 3),
|
||||
(@CGUID+36 , @CGUID+31 , 3),
|
||||
(@CGUID+37 , @CGUID+31 , 3),
|
||||
(@CGUID+38 , @CGUID+31 , 3),
|
||||
(@CGUID+39 , @CGUID+31 , 3),
|
||||
(@CGUID+40 , @CGUID+40 , 3),
|
||||
(@CGUID+41 , @CGUID+40 , 3),
|
||||
(@CGUID+42 , @CGUID+40 , 3),
|
||||
(@CGUID+43 , @CGUID+40 , 3),
|
||||
(@CGUID+44 , @CGUID+40 , 3),
|
||||
(@CGUID+45 , @CGUID+40 , 3),
|
||||
(@CGUID+46 , @CGUID+40 , 3),
|
||||
(@CGUID+47 , @CGUID+40 , 3),
|
||||
(@CGUID+48 , @CGUID+40 , 3),
|
||||
(@CGUID+49 , @CGUID+49 , 3),
|
||||
(@CGUID+50 , @CGUID+49 , 3),
|
||||
(@CGUID+51 , @CGUID+49 , 3),
|
||||
(@CGUID+52 , @CGUID+49 , 3),
|
||||
(@CGUID+53 , @CGUID+49 , 3),
|
||||
(@CGUID+54 , @CGUID+49 , 3),
|
||||
(@CGUID+55 , @CGUID+49 , 3),
|
||||
(@CGUID+56 , @CGUID+49 , 3),
|
||||
(@CGUID+57 , @CGUID+49 , 3),
|
||||
(@CGUID+58 , @CGUID+58 , 3),
|
||||
(@CGUID+59 , @CGUID+58 , 3),
|
||||
(@CGUID+60 , @CGUID+58 , 3),
|
||||
(@CGUID+61 , @CGUID+58 , 3),
|
||||
(@CGUID+62 , @CGUID+58 , 3),
|
||||
(@CGUID+63 , @CGUID+58 , 3),
|
||||
(@CGUID+64 , @CGUID+58 , 3),
|
||||
(@CGUID+65 , @CGUID+58 , 3),
|
||||
(@CGUID+66 , @CGUID+58 , 3),
|
||||
(@CGUID+67 , @CGUID+67 , 3),
|
||||
(@CGUID+68 , @CGUID+67 , 3),
|
||||
(@CGUID+69 , @CGUID+67 , 3),
|
||||
(@CGUID+70 , @CGUID+67 , 3),
|
||||
(@CGUID+71 , @CGUID+67 , 3),
|
||||
(@CGUID+72 , @CGUID+67 , 3),
|
||||
(@CGUID+73 , @CGUID+67 , 3),
|
||||
(@CGUID+74 , @CGUID+67 , 3),
|
||||
(@CGUID+75 , @CGUID+67 , 3),
|
||||
(@CGUID+76 , @CGUID+76 , 3),
|
||||
(@CGUID+77 , @CGUID+76 , 3),
|
||||
(@CGUID+78 , @CGUID+76 , 3),
|
||||
(@CGUID+79 , @CGUID+76 , 3),
|
||||
(@CGUID+80 , @CGUID+76 , 3),
|
||||
(@CGUID+81 , @CGUID+76 , 3),
|
||||
(@CGUID+82 , @CGUID+82 , 3),
|
||||
(@CGUID+83 , @CGUID+82 , 3),
|
||||
(@CGUID+84 , @CGUID+82 , 3),
|
||||
(@CGUID+85 , @CGUID+82 , 3),
|
||||
(@CGUID+86 , @CGUID+82 , 3),
|
||||
(@CGUID+87 , @CGUID+82 , 3),
|
||||
(@CGUID+88 , @CGUID+88 , 3),
|
||||
(@CGUID+89 , @CGUID+88 , 3),
|
||||
(@CGUID+90 , @CGUID+88 , 3),
|
||||
(@CGUID+91 , @CGUID+88 , 3),
|
||||
(@CGUID+92 , @CGUID+88 , 3),
|
||||
(@CGUID+93 , @CGUID+88 , 3),
|
||||
(@CGUID+94 , @CGUID+94 , 3),
|
||||
(@CGUID+95 , @CGUID+94 , 3),
|
||||
(@CGUID+96 , @CGUID+94 , 3),
|
||||
(@CGUID+97 , @CGUID+94 , 3),
|
||||
(@CGUID+98 , @CGUID+94 , 3),
|
||||
(@CGUID+99 , @CGUID+94 , 3),
|
||||
(@CGUID+102, @CGUID+102, 3),
|
||||
(@CGUID+103, @CGUID+102, 3),
|
||||
(@CGUID+104, @CGUID+102, 3),
|
||||
(@CGUID+105, @CGUID+102, 3),
|
||||
(@CGUID+106, @CGUID+106, 3),
|
||||
(@CGUID+107, @CGUID+106, 3),
|
||||
(@CGUID+108, @CGUID+106, 3),
|
||||
(@CGUID+109, @CGUID+106, 3),
|
||||
(@CGUID+115, @CGUID+115, 3),
|
||||
(@CGUID+116, @CGUID+115, 3),
|
||||
(@CGUID+117, @CGUID+115, 3),
|
||||
(@CGUID+118, @CGUID+118, 3),
|
||||
(@CGUID+119, @CGUID+118, 3),
|
||||
(@CGUID+120, @CGUID+118, 3),
|
||||
(@CGUID+121, @CGUID+118, 3),
|
||||
(@CGUID+122, @CGUID+122, 3),
|
||||
(@CGUID+123, @CGUID+122, 3),
|
||||
(@CGUID+124, @CGUID+122, 3),
|
||||
(@CGUID+125, @CGUID+122, 3),
|
||||
(@CGUID+126, @CGUID+122, 3),
|
||||
(@CGUID+127, @CGUID+127, 3),
|
||||
(@CGUID+128, @CGUID+127, 3),
|
||||
(@CGUID+129, @CGUID+127, 3),
|
||||
(@CGUID+130, @CGUID+127, 3),
|
||||
(@CGUID+131, @CGUID+127, 3),
|
||||
(@CGUID+132, @CGUID+127, 3),
|
||||
(@CGUID+133, @CGUID+133, 3),
|
||||
(@CGUID+134, @CGUID+133, 3),
|
||||
(@CGUID+135, @CGUID+133, 3),
|
||||
(@CGUID+136, @CGUID+133, 3),
|
||||
(@CGUID+137, @CGUID+133, 3),
|
||||
(@CGUID+138, @CGUID+133, 3);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@CGUID+1, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+2, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+3, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+4, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+5, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+6, @CGUID+6, 0, 0, 3),
|
||||
(@CGUID+7, @CGUID+6, 0, 0, 3),
|
||||
(@CGUID+8, @CGUID+6, 0, 0, 3),
|
||||
(@CGUID+9, @CGUID+6, 0, 0, 3),
|
||||
(@CGUID+10, @CGUID+6, 0, 0, 3),
|
||||
(@CGUID+11, @CGUID+11, 0, 0, 3),
|
||||
(@CGUID+12, @CGUID+11, 0, 0, 3),
|
||||
(@CGUID+13, @CGUID+11, 0, 0, 3),
|
||||
(@CGUID+14, @CGUID+11, 0, 0, 3),
|
||||
(@CGUID+15, @CGUID+11, 0, 0, 3),
|
||||
(@CGUID+22, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+23, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+24, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+25, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+27, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+29, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+30, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+31, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+32, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+33, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+35, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+37, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+38, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+39, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+40, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+41, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+42, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+45, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+46, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+47, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+48, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+49, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+50, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+51, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+52, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+53, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+54, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+55, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+56, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+57, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+58, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+59, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+60, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+61, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+62, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+63, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+64, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+65, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+66, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+67, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+68, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+69, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+70, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+71, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+72, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+73, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+74, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+75, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+76, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+77, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+78, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+79, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+82, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+83, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+84, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+85, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+87, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+88, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+90, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+92, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+93, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+94, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+95, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+96, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+97, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+98, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+99, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+102, @CGUID+102, 0, 0, 3),
|
||||
(@CGUID+103, @CGUID+102, 0, 0, 3),
|
||||
(@CGUID+104, @CGUID+102, 0, 0, 3),
|
||||
(@CGUID+105, @CGUID+102, 0, 0, 3),
|
||||
(@CGUID+106, @CGUID+106, 0, 0, 3),
|
||||
(@CGUID+107, @CGUID+106, 0, 0, 3),
|
||||
(@CGUID+108, @CGUID+106, 0, 0, 3),
|
||||
(@CGUID+109, @CGUID+106, 0, 0, 3),
|
||||
(@CGUID+115, @CGUID+115, 0, 0, 3),
|
||||
(@CGUID+116, @CGUID+115, 0, 0, 3),
|
||||
(@CGUID+117, @CGUID+115, 0, 0, 3),
|
||||
(@CGUID+118, @CGUID+118, 0, 0, 3),
|
||||
(@CGUID+119, @CGUID+118, 0, 0, 3),
|
||||
(@CGUID+120, @CGUID+118, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+118, 0, 0, 3),
|
||||
(@CGUID+122, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+123, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+124, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+125, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+126, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+127, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+128, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+129, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+130, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+131, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+132, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+133, @CGUID+133, 0, 0, 3),
|
||||
(@CGUID+134, @CGUID+133, 0, 0, 3),
|
||||
(@CGUID+135, @CGUID+133, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+133, 0, 0, 3),
|
||||
(@CGUID+137, @CGUID+133, 0, 0, 3),
|
||||
(@CGUID+138, @CGUID+133, 0, 0, 3);
|
||||
|
||||
UPDATE `smart_scripts` SET `action_param2`=0 WHERE `entryorguid`=21230 AND `source_type`=0 AND `id`=1 AND `link`=0;
|
||||
UPDATE `smart_scripts` SET `action_param2`=0 WHERE `entryorguid`=21230 AND `source_type`=0 AND `id`=5 AND `link`=0;
|
||||
|
||||
@@ -183,11 +183,11 @@ INSERT INTO `linked_respawn`(`guid`, `linkedGuid`, `linkType`) VALUES
|
||||
|
||||
-- Leotheras formation
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` = @LEOTHERAS;
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(@LEOTHERAS, @LEOTHERAS, 24),
|
||||
(@LEOTHERAS, @LEOTHERAS+1, 24),
|
||||
(@LEOTHERAS, @LEOTHERAS+2, 24),
|
||||
(@LEOTHERAS, @LEOTHERAS+3, 24);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@LEOTHERAS, @LEOTHERAS, 0, 0, 24),
|
||||
(@LEOTHERAS, @LEOTHERAS+1, 0, 0, 24),
|
||||
(@LEOTHERAS, @LEOTHERAS+2, 0, 0, 24),
|
||||
(@LEOTHERAS, @LEOTHERAS+3, 0, 0, 24);
|
||||
|
||||
SET @KARATHRESS := 153154;
|
||||
DELETE FROM `linked_respawn` WHERE `linkedGuid` = @KARATHRESS;
|
||||
|
||||
@@ -869,176 +869,176 @@ INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_
|
||||
|
||||
-- Static Formations
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (@CGUID+03,@CGUID+04,@CGUID+05,@CGUID+06,@CGUID+07,@CGUID+08,@CGUID+09,@CGUID+10,@CGUID+11,@CGUID+12,@CGUID+13,@CGUID+14,@CGUID+15,@CGUID+16,@CGUID+17,@CGUID+18,@CGUID+19,@CGUID+20,@CGUID+52,@CGUID+53,@CGUID+54,@CGUID+55,@CGUID+59,@CGUID+60,@CGUID+61,@CGUID+62,@CGUID+63,@CGUID+64,@CGUID+65,@CGUID+66,@CGUID+67,@CGUID+68,@CGUID+69,@CGUID+70,@CGUID+74,@CGUID+75,@CGUID+76,@CGUID+77,@CGUID+78,@CGUID+79,@CGUID+80,@CGUID+81,@CGUID+82,@CGUID+83,@CGUID+84,@CGUID+85,@CGUID+86,@CGUID+87,@CGUID+88,@CGUID+89,@CGUID+90,@CGUID+91,@CGUID+93,@CGUID+94,@CGUID+98,@CGUID+99,@CGUID+100,@CGUID+101,@CGUID+102,@CGUID+103,@CGUID+104,@CGUID+105,@CGUID+106,@CGUID+107,@CGUID+108,@CGUID+109,@CGUID+110,@CGUID+111,@CGUID+112,@CGUID+113,@CGUID+114,@CGUID+115,@CGUID+116,@CGUID+117,@CGUID+118,@CGUID+119,@CGUID+120,@CGUID+121,@CGUID+125,@CGUID+126,@CGUID+127,@CGUID+128,@CGUID+129,@CGUID+130,@CGUID+131,@CGUID+132,@CGUID+133,@CGUID+134,@CGUID+135,@CGUID+136,@CGUID+143,@CGUID+144,@CGUID+145,@CGUID+146,@CGUID+147,@CGUID+148,@CGUID+149,@CGUID+150,@CGUID+151,@CGUID+152,@CGUID+153,@CGUID+154,@CGUID+155,@CGUID+156,@CGUID+157,@CGUID+158,@CGUID+159,@CGUID+160,@CGUID+161,@CGUID+162,@CGUID+163,@CGUID+164,@CGUID+165,@CGUID+166,@CGUID+167,@CGUID+168,@CGUID+169,@CGUID+170,@CGUID+171,@CGUID+172,@CGUID+173,@CGUID+174,@CGUID+175,@CGUID+176,@CGUID+177,@CGUID+178,@CGUID+180,@CGUID+181,@CGUID+182,@CGUID+183,@CGUID+184,@CGUID+185,@CGUID+186,@CGUID+187,@CGUID+188,@CGUID+189,@CGUID+190,@CGUID+191,@CGUID+218,@CGUID+219,@CGUID+220,@CGUID+221,@CGUID+222) AND `groupAI` IN (3, 24);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
-- Entrance Group 1
|
||||
(@CGUID+3, @CGUID+3, 3),
|
||||
(@CGUID+4, @CGUID+3, 3),
|
||||
(@CGUID+5, @CGUID+3, 3),
|
||||
(@CGUID+6, @CGUID+3, 3),
|
||||
(@CGUID+7, @CGUID+3, 3),
|
||||
(@CGUID+8, @CGUID+3, 3),
|
||||
(@CGUID+3, @CGUID+3, 0, 0, 3),
|
||||
(@CGUID+4, @CGUID+3, 0, 0, 3),
|
||||
(@CGUID+5, @CGUID+3, 0, 0, 3),
|
||||
(@CGUID+6, @CGUID+3, 0, 0, 3),
|
||||
(@CGUID+7, @CGUID+3, 0, 0, 3),
|
||||
(@CGUID+8, @CGUID+3, 0, 0, 3),
|
||||
-- Entrance Group 2
|
||||
(@CGUID+9 , @CGUID+9, 3),
|
||||
(@CGUID+10, @CGUID+9, 3),
|
||||
(@CGUID+11, @CGUID+9, 3),
|
||||
(@CGUID+12, @CGUID+9, 3),
|
||||
(@CGUID+13, @CGUID+9, 3),
|
||||
(@CGUID+14, @CGUID+9, 3),
|
||||
(@CGUID+9, @CGUID+9, 0, 0, 3),
|
||||
(@CGUID+10, @CGUID+9, 0, 0, 3),
|
||||
(@CGUID+11, @CGUID+9, 0, 0, 3),
|
||||
(@CGUID+12, @CGUID+9, 0, 0, 3),
|
||||
(@CGUID+13, @CGUID+9, 0, 0, 3),
|
||||
(@CGUID+14, @CGUID+9, 0, 0, 3),
|
||||
-- Entrance Group 3
|
||||
(@CGUID+15, @CGUID+15, 3),
|
||||
(@CGUID+16, @CGUID+15, 3),
|
||||
(@CGUID+17, @CGUID+15, 3),
|
||||
(@CGUID+18, @CGUID+15, 3),
|
||||
(@CGUID+19, @CGUID+15, 3),
|
||||
(@CGUID+20, @CGUID+15, 3),
|
||||
(@CGUID+15, @CGUID+15, 0, 0, 3),
|
||||
(@CGUID+16, @CGUID+15, 0, 0, 3),
|
||||
(@CGUID+17, @CGUID+15, 0, 0, 3),
|
||||
(@CGUID+18, @CGUID+15, 0, 0, 3),
|
||||
(@CGUID+19, @CGUID+15, 0, 0, 3),
|
||||
(@CGUID+20, @CGUID+15, 0, 0, 3),
|
||||
-- Sentinel Group 1
|
||||
(@CGUID+52, @CGUID+52, 3),
|
||||
(@CGUID+53, @CGUID+52, 3),
|
||||
(@CGUID+52, @CGUID+52, 0, 0, 3),
|
||||
(@CGUID+53, @CGUID+52, 0, 0, 3),
|
||||
-- Sentinel Group 2
|
||||
(@CGUID+54, @CGUID+54, 3),
|
||||
(@CGUID+55, @CGUID+54, 3),
|
||||
(@CGUID+54, @CGUID+54, 0, 0, 3),
|
||||
(@CGUID+55, @CGUID+54, 0, 0, 3),
|
||||
-- Inquisitor Adds 1
|
||||
(@CGUID+59, @CGUID+59, 3),
|
||||
(@CGUID+60, @CGUID+59, 3),
|
||||
(@CGUID+61, @CGUID+59, 3),
|
||||
(@CGUID+62, @CGUID+59, 3),
|
||||
(@CGUID+63, @CGUID+59, 3),
|
||||
(@CGUID+64, @CGUID+59, 3),
|
||||
(@CGUID+59, @CGUID+59, 0, 0, 3),
|
||||
(@CGUID+60, @CGUID+59, 0, 0, 3),
|
||||
(@CGUID+61, @CGUID+59, 0, 0, 3),
|
||||
(@CGUID+62, @CGUID+59, 0, 0, 3),
|
||||
(@CGUID+63, @CGUID+59, 0, 0, 3),
|
||||
(@CGUID+64, @CGUID+59, 0, 0, 3),
|
||||
-- Inquisitor Adds 2
|
||||
(@CGUID+65, @CGUID+65, 3),
|
||||
(@CGUID+66, @CGUID+65, 3),
|
||||
(@CGUID+67, @CGUID+65, 3),
|
||||
(@CGUID+68, @CGUID+65, 3),
|
||||
(@CGUID+69, @CGUID+65, 3),
|
||||
(@CGUID+70, @CGUID+65, 3),
|
||||
(@CGUID+65, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+66, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+67, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+68, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+69, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+70, @CGUID+65, 0, 0, 3),
|
||||
-- Void Reaver Trash Group 1
|
||||
(@CGUID+74, @CGUID+74, 3),
|
||||
(@CGUID+75, @CGUID+74, 3),
|
||||
(@CGUID+76, @CGUID+74, 3),
|
||||
(@CGUID+77, @CGUID+74, 3),
|
||||
(@CGUID+78, @CGUID+74, 3),
|
||||
(@CGUID+74, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+75, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+76, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+77, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+78, @CGUID+74, 0, 0, 3),
|
||||
-- Void Reaver Trash Group 2
|
||||
(@CGUID+79, @CGUID+79, 3),
|
||||
(@CGUID+80, @CGUID+79, 3),
|
||||
(@CGUID+81, @CGUID+79, 3),
|
||||
(@CGUID+82, @CGUID+79, 3),
|
||||
(@CGUID+83, @CGUID+79, 3),
|
||||
(@CGUID+79, @CGUID+79, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+79, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+79, 0, 0, 3),
|
||||
(@CGUID+82, @CGUID+79, 0, 0, 3),
|
||||
(@CGUID+83, @CGUID+79, 0, 0, 3),
|
||||
-- Void Reaver Trash Group 3
|
||||
(@CGUID+84, @CGUID+84, 3),
|
||||
(@CGUID+85, @CGUID+84, 3),
|
||||
(@CGUID+86, @CGUID+84, 3),
|
||||
(@CGUID+87, @CGUID+84, 3),
|
||||
(@CGUID+84, @CGUID+84, 0, 0, 3),
|
||||
(@CGUID+85, @CGUID+84, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+84, 0, 0, 3),
|
||||
(@CGUID+87, @CGUID+84, 0, 0, 3),
|
||||
-- Void Reaver Trash Group 4
|
||||
(@CGUID+88, @CGUID+88, 3),
|
||||
(@CGUID+89, @CGUID+88, 3),
|
||||
(@CGUID+90, @CGUID+88, 3),
|
||||
(@CGUID+91, @CGUID+88, 3),
|
||||
(@CGUID+88, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+90, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+88, 0, 0, 3),
|
||||
-- Solarium Sentinel Group 1
|
||||
(@CGUID+93, @CGUID+93, 3),
|
||||
(@CGUID+94, @CGUID+93, 3),
|
||||
(@CGUID+93, @CGUID+93, 0, 0, 3),
|
||||
(@CGUID+94, @CGUID+93, 0, 0, 3),
|
||||
-- Solarium Large Group 1
|
||||
(@CGUID+98 , @CGUID+98, 3),
|
||||
(@CGUID+99 , @CGUID+98, 3),
|
||||
(@CGUID+100, @CGUID+98, 3),
|
||||
(@CGUID+101, @CGUID+98, 3),
|
||||
(@CGUID+102, @CGUID+98, 3),
|
||||
(@CGUID+103, @CGUID+98, 3),
|
||||
(@CGUID+104, @CGUID+98, 3),
|
||||
(@CGUID+105, @CGUID+98, 3),
|
||||
(@CGUID+106, @CGUID+98, 3),
|
||||
(@CGUID+107, @CGUID+98, 3),
|
||||
(@CGUID+108, @CGUID+98, 3),
|
||||
(@CGUID+109, @CGUID+98, 3),
|
||||
(@CGUID+98, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+99, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+100, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+101, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+102, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+103, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+104, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+105, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+106, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+107, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+108, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+109, @CGUID+98, 0, 0, 3),
|
||||
-- Solarium Large Group 2
|
||||
(@CGUID+110, @CGUID+110, 3),
|
||||
(@CGUID+111, @CGUID+110, 3),
|
||||
(@CGUID+112, @CGUID+110, 3),
|
||||
(@CGUID+113, @CGUID+110, 3),
|
||||
(@CGUID+114, @CGUID+110, 3),
|
||||
(@CGUID+115, @CGUID+110, 3),
|
||||
(@CGUID+116, @CGUID+110, 3),
|
||||
(@CGUID+117, @CGUID+110, 3),
|
||||
(@CGUID+118, @CGUID+110, 3),
|
||||
(@CGUID+119, @CGUID+110, 3),
|
||||
(@CGUID+120, @CGUID+110, 3),
|
||||
(@CGUID+121, @CGUID+110, 3),
|
||||
(@CGUID+110, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+111, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+112, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+113, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+114, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+115, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+116, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+117, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+118, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+119, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+120, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+110, 0, 0, 3),
|
||||
-- Inquisitor Adds 3
|
||||
(@CGUID+125, @CGUID+125, 3),
|
||||
(@CGUID+126, @CGUID+125, 3),
|
||||
(@CGUID+127, @CGUID+125, 3),
|
||||
(@CGUID+128, @CGUID+125, 3),
|
||||
(@CGUID+129, @CGUID+125, 3),
|
||||
(@CGUID+130, @CGUID+125, 3),
|
||||
(@CGUID+125, @CGUID+125, 0, 0, 3),
|
||||
(@CGUID+126, @CGUID+125, 0, 0, 3),
|
||||
(@CGUID+127, @CGUID+125, 0, 0, 3),
|
||||
(@CGUID+128, @CGUID+125, 0, 0, 3),
|
||||
(@CGUID+129, @CGUID+125, 0, 0, 3),
|
||||
(@CGUID+130, @CGUID+125, 0, 0, 3),
|
||||
-- Inquisitor Adds 4
|
||||
(@CGUID+131, @CGUID+131, 3),
|
||||
(@CGUID+132, @CGUID+131, 3),
|
||||
(@CGUID+133, @CGUID+131, 3),
|
||||
(@CGUID+134, @CGUID+131, 3),
|
||||
(@CGUID+135, @CGUID+131, 3),
|
||||
(@CGUID+136, @CGUID+131, 3),
|
||||
(@CGUID+131, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+132, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+133, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+134, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+135, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+131, 0, 0, 3),
|
||||
-- Solarian Adds 1
|
||||
(@CGUID+143, @CGUID+143, 3),
|
||||
(@CGUID+144, @CGUID+143, 3),
|
||||
(@CGUID+145, @CGUID+143, 3),
|
||||
(@CGUID+146, @CGUID+143, 3),
|
||||
(@CGUID+147, @CGUID+143, 3),
|
||||
(@CGUID+148, @CGUID+143, 3),
|
||||
(@CGUID+143, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+144, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+145, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+146, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+147, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+148, @CGUID+143, 0, 0, 3),
|
||||
-- Solarian Adds 2
|
||||
(@CGUID+149, @CGUID+149, 3),
|
||||
(@CGUID+150, @CGUID+149, 3),
|
||||
(@CGUID+151, @CGUID+149, 3),
|
||||
(@CGUID+152, @CGUID+149, 3),
|
||||
(@CGUID+153, @CGUID+149, 3),
|
||||
(@CGUID+154, @CGUID+149, 3),
|
||||
(@CGUID+149, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+150, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+151, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+152, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+153, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+154, @CGUID+149, 0, 0, 3),
|
||||
-- Solarian Adds 3
|
||||
(@CGUID+155, @CGUID+155, 3),
|
||||
(@CGUID+156, @CGUID+155, 3),
|
||||
(@CGUID+157, @CGUID+155, 3),
|
||||
(@CGUID+158, @CGUID+155, 3),
|
||||
(@CGUID+159, @CGUID+155, 3),
|
||||
(@CGUID+160, @CGUID+155, 3),
|
||||
(@CGUID+155, @CGUID+155, 0, 0, 3),
|
||||
(@CGUID+156, @CGUID+155, 0, 0, 3),
|
||||
(@CGUID+157, @CGUID+155, 0, 0, 3),
|
||||
(@CGUID+158, @CGUID+155, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+155, 0, 0, 3),
|
||||
(@CGUID+160, @CGUID+155, 0, 0, 3),
|
||||
-- Solarian Adds 4
|
||||
(@CGUID+161, @CGUID+161, 3),
|
||||
(@CGUID+162, @CGUID+161, 3),
|
||||
(@CGUID+163, @CGUID+161, 3),
|
||||
(@CGUID+164, @CGUID+161, 3),
|
||||
(@CGUID+165, @CGUID+161, 3),
|
||||
(@CGUID+166, @CGUID+161, 3),
|
||||
(@CGUID+161, @CGUID+161, 0, 0, 3),
|
||||
(@CGUID+162, @CGUID+161, 0, 0, 3),
|
||||
(@CGUID+163, @CGUID+161, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+161, 0, 0, 3),
|
||||
(@CGUID+165, @CGUID+161, 0, 0, 3),
|
||||
(@CGUID+166, @CGUID+161, 0, 0, 3),
|
||||
-- Solarian Adds 5
|
||||
(@CGUID+167, @CGUID+167, 3),
|
||||
(@CGUID+168, @CGUID+167, 3),
|
||||
(@CGUID+169, @CGUID+167, 3),
|
||||
(@CGUID+170, @CGUID+167, 3),
|
||||
(@CGUID+171, @CGUID+167, 3),
|
||||
(@CGUID+172, @CGUID+167, 3),
|
||||
(@CGUID+167, @CGUID+167, 0, 0, 3),
|
||||
(@CGUID+168, @CGUID+167, 0, 0, 3),
|
||||
(@CGUID+169, @CGUID+167, 0, 0, 3),
|
||||
(@CGUID+170, @CGUID+167, 0, 0, 3),
|
||||
(@CGUID+171, @CGUID+167, 0, 0, 3),
|
||||
(@CGUID+172, @CGUID+167, 0, 0, 3),
|
||||
-- Solarian Adds 6
|
||||
(@CGUID+173, @CGUID+173, 3),
|
||||
(@CGUID+174, @CGUID+173, 3),
|
||||
(@CGUID+175, @CGUID+173, 3),
|
||||
(@CGUID+176, @CGUID+173, 3),
|
||||
(@CGUID+177, @CGUID+173, 3),
|
||||
(@CGUID+178, @CGUID+173, 3),
|
||||
(@CGUID+173, @CGUID+173, 0, 0, 3),
|
||||
(@CGUID+174, @CGUID+173, 0, 0, 3),
|
||||
(@CGUID+175, @CGUID+173, 0, 0, 3),
|
||||
(@CGUID+176, @CGUID+173, 0, 0, 3),
|
||||
(@CGUID+177, @CGUID+173, 0, 0, 3),
|
||||
(@CGUID+178, @CGUID+173, 0, 0, 3),
|
||||
-- Kael Trash 1
|
||||
(@CGUID+180, @CGUID+180, 3),
|
||||
(@CGUID+181, @CGUID+180, 3),
|
||||
(@CGUID+182, @CGUID+180, 3),
|
||||
(@CGUID+183, @CGUID+180, 3),
|
||||
(@CGUID+180, @CGUID+180, 0, 0, 3),
|
||||
(@CGUID+181, @CGUID+180, 0, 0, 3),
|
||||
(@CGUID+182, @CGUID+180, 0, 0, 3),
|
||||
(@CGUID+183, @CGUID+180, 0, 0, 3),
|
||||
-- Kael Trash 2
|
||||
(@CGUID+184, @CGUID+184, 3),
|
||||
(@CGUID+185, @CGUID+184, 3),
|
||||
(@CGUID+186, @CGUID+184, 3),
|
||||
(@CGUID+187, @CGUID+184, 3),
|
||||
(@CGUID+184, @CGUID+184, 0, 0, 3),
|
||||
(@CGUID+185, @CGUID+184, 0, 0, 3),
|
||||
(@CGUID+186, @CGUID+184, 0, 0, 3),
|
||||
(@CGUID+187, @CGUID+184, 0, 0, 3),
|
||||
-- Kael Trash 3
|
||||
(@CGUID+188, @CGUID+188, 3),
|
||||
(@CGUID+189, @CGUID+188, 3),
|
||||
(@CGUID+190, @CGUID+188, 3),
|
||||
(@CGUID+191, @CGUID+188, 3),
|
||||
(@CGUID+188, @CGUID+188, 0, 0, 3),
|
||||
(@CGUID+189, @CGUID+188, 0, 0, 3),
|
||||
(@CGUID+190, @CGUID+188, 0, 0, 3),
|
||||
(@CGUID+191, @CGUID+188, 0, 0, 3),
|
||||
-- Kael & Advisors
|
||||
(@CGUID+218, @CGUID+218, 24),
|
||||
(@CGUID+219, @CGUID+218, 24),
|
||||
(@CGUID+220, @CGUID+218, 24),
|
||||
(@CGUID+221, @CGUID+218, 24),
|
||||
(@CGUID+222, @CGUID+218, 24);
|
||||
(@CGUID+218, @CGUID+218, 0, 0, 24),
|
||||
(@CGUID+219, @CGUID+218, 0, 0, 24),
|
||||
(@CGUID+220, @CGUID+218, 0, 0, 24),
|
||||
(@CGUID+221, @CGUID+218, 0, 0, 24),
|
||||
(@CGUID+222, @CGUID+218, 0, 0, 24);
|
||||
|
||||
-- Update SheatheState en masse
|
||||
UPDATE `creature_template_addon` SET `bytes2` = 1 WHERE `entry` IN (18805,19514,19516,19622,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,20041,20042,20043,20044,20045,20046,20047,20048,20049,20050,20052,20060,20062,20063,20064,22515,22517);
|
||||
|
||||
@@ -3770,411 +3770,411 @@ INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`
|
||||
-- 0x203CA44680168B80007C2000008127DD .go xyz 409.20535 785.9281 14.643406
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (@CGUID+1,@CGUID+2,@CGUID+3,@CGUID+4,@CGUID+5,@CGUID+6,@CGUID+7,@CGUID+8,@CGUID+9,@CGUID+10,@CGUID+11,@CGUID+12,@CGUID+23,@CGUID+24,@CGUID+25,@CGUID+26,@CGUID+27,@CGUID+28,@CGUID+29,@CGUID+30,@CGUID+31,@CGUID+32,@CGUID+33,@CGUID+34,@CGUID+35,@CGUID+36,@CGUID+37,@CGUID+38,@CGUID+39,@CGUID+40,@CGUID+41,@CGUID+42,@CGUID+43,@CGUID+44,@CGUID+45,@CGUID+46,@CGUID+47,@CGUID+48,@CGUID+49,@CGUID+50,@CGUID+51,@CGUID+52,@CGUID+53,@CGUID+54,@CGUID+62,@CGUID+63,@CGUID+64,@CGUID+65,@CGUID+66,@CGUID+67,@CGUID+68,@CGUID+69,@CGUID+70,@CGUID+71,@CGUID+74,@CGUID+75,@CGUID+76,@CGUID+77,@CGUID+78,@CGUID+79,@CGUID+82,@CGUID+83,@CGUID+84,@CGUID+85,@CGUID+86,@CGUID+87,@CGUID+88,@CGUID+89,@CGUID+90,@CGUID+91,@CGUID+92,@CGUID+93,@CGUID+94,@CGUID+95,@CGUID+96,@CGUID+97,@CGUID+98,@CGUID+99,@CGUID+146,@CGUID+147,@CGUID+148,@CGUID+149,@CGUID+150,@CGUID+151,@CGUID+152,@CGUID+153,@CGUID+154,@CGUID+155,@CGUID+156,@CGUID+157,@CGUID+158,@CGUID+159,@CGUID+160,@CGUID+161,@CGUID+162,@CGUID+163,@CGUID+164,@CGUID+165,@CGUID+166,@CGUID+167,@CGUID+168,@CGUID+169,@CGUID+170,@CGUID+171,@CGUID+172,@CGUID+173,@CGUID+174,@CGUID+175,@CGUID+188,@CGUID+189,@CGUID+190,@CGUID+191,@CGUID+192,@CGUID+193,@CGUID+194,@CGUID+195,@CGUID+196,@CGUID+197,@CGUID+198,@CGUID+199,@CGUID+200,@CGUID+201,@CGUID+202,@CGUID+203,@CGUID+204,@CGUID+205,@CGUID+206,@CGUID+207,@CGUID+208,@CGUID+209,@CGUID+210,@CGUID+211,@CGUID+212,@CGUID+213,@CGUID+222,@CGUID+223,@CGUID+224,@CGUID+225,@CGUID+226,@CGUID+227,@CGUID+228,@CGUID+229,@CGUID+253,@CGUID+254,@CGUID+255,@CGUID+256,@CGUID+266,@CGUID+267,@CGUID+268,@CGUID+269,@CGUID+270,@CGUID+271,@CGUID+272,@CGUID+273,@CGUID+274,@CGUID+275,@CGUID+276,@CGUID+277,@CGUID+278,@CGUID+279,@CGUID+280,@CGUID+281,@CGUID+282,@CGUID+283,@CGUID+284,@CGUID+287,@CGUID+289,@CGUID+290,@CGUID+291,@CGUID+292,@CGUID+293,@CGUID+294,@CGUID+295,@CGUID+296,@CGUID+297,@CGUID+298,@CGUID+299,@CGUID+300,@CGUID+301,@CGUID+302,@CGUID+303,@CGUID+304,@CGUID+305,@CGUID+318,@CGUID+319,@CGUID+320,@CGUID+321,@CGUID+322,@CGUID+323,@CGUID+324,@CGUID+325,@CGUID+326,@CGUID+327,@CGUID+328,@CGUID+329,@CGUID+330,@CGUID+331,@CGUID+365,@CGUID+366,@CGUID+367,@CGUID+368,@CGUID+369,@CGUID+370,@CGUID+371,@CGUID+372,@CGUID+373,@CGUID+374,@CGUID+375,@CGUID+376,@CGUID+377,@CGUID+378,@CGUID+379,@CGUID+380,@CGUID+383,@CGUID+384,@CGUID+385,@CGUID+386,@CGUID+387,@CGUID+388,@CGUID+389,@CGUID+390,@CGUID+391,@CGUID+392,@CGUID+393,@CGUID+396,@CGUID+397,@CGUID+398,@CGUID+399,@CGUID+400,@CGUID+401,@CGUID+402,@CGUID+403,@CGUID+404,@CGUID+405,@CGUID+406,@CGUID+418,@CGUID+419,@CGUID+420,@CGUID+421,@CGUID+422,@CGUID+423,@CGUID+540,@CGUID+541,@CGUID+542,@CGUID+543,@CGUID+544,@CGUID+545,@CGUID+546,@CGUID+547,@CGUID+548,@CGUID+549,@CGUID+550,@CGUID+551,@CGUID+552,@CGUID+553,@CGUID+554,@CGUID+555,@CGUID+556,@CGUID+557,@CGUID+558,@CGUID+559,@CGUID+560,@CGUID+561,@CGUID+562,@CGUID+563,@CGUID+564,@CGUID+565,@CGUID+566,@CGUID+567,@CGUID+568,@CGUID+569,@CGUID+570,@CGUID+571,@CGUID+572,@CGUID+573,@CGUID+574,@CGUID+575,@CGUID+576,@CGUID+577,@CGUID+578,@CGUID+579,@CGUID+580,@CGUID+581,@CGUID+582,@CGUID+583,@CGUID+584,@CGUID+585,@CGUID+586,@CGUID+587,@CGUID+588,@CGUID+589,@CGUID+592,@CGUID+593,@CGUID+594,@CGUID+595,@CGUID+596,@CGUID+597,@CGUID+598,@CGUID+599,@CGUID+600,@CGUID+601,@CGUID+602,@CGUID+603,@CGUID+605,@CGUID+606,@CGUID+607,@CGUID+608,@CGUID+609,@CGUID+610,@CGUID+611,@CGUID+612,@CGUID+613,@CGUID+614,@CGUID+615,@CGUID+616,@CGUID+617,@CGUID+618,@CGUID+619,@CGUID+620,@CGUID+621,@CGUID+622,@CGUID+623,@CGUID+624,@CGUID+625,@CGUID+626,@CGUID+627,@CGUID+628,@CGUID+629,@CGUID+630,@CGUID+631,@CGUID+632,@CGUID+633,@CGUID+634,@CGUID+635,@CGUID+636,@CGUID+637,@CGUID+638,@CGUID+639,@CGUID+640,@CGUID+641,@CGUID+642,@CGUID+643,@CGUID+644,@CGUID+645,@CGUID+646,@CGUID+647,@CGUID+648,@CGUID+649,@CGUID+650,@CGUID+651,@CGUID+652,@CGUID+653,@CGUID+654,@CGUID+655,@CGUID+656,@CGUID+657,@CGUID+658,@CGUID+659,@CGUID+660,@CGUID+661,@CGUID+662,@CGUID+663,@CGUID+664,@CGUID+665,@CGUID+666,@CGUID+667,@CGUID+668,@CGUID+669,@CGUID+670,@CGUID+671,@CGUID+672,@CGUID+673,@CGUID+674,@CGUID+675,@CGUID+676,@CGUID+677,@CGUID+691,@CGUID+692,@CGUID+693,@CGUID+694,@CGUID+695,@CGUID+696,@CGUID+697,@CGUID+698,@CGUID+699,@CGUID+700,@CGUID+701,@CGUID+702,@CGUID+703,@CGUID+704,@CGUID+705,@CGUID+706,@CGUID+707,@CGUID+708,@CGUID+709,@CGUID+710,@CGUID+711,@CGUID+712,@CGUID+713,@CGUID+714,@CGUID+716,@CGUID+717,@CGUID+718,@CGUID+719) AND `groupAI` IN (3, 27);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(@CGUID+1 , @CGUID+1 , 3),
|
||||
(@CGUID+2 , @CGUID+1 , 3),
|
||||
(@CGUID+3 , @CGUID+1 , 3),
|
||||
(@CGUID+4 , @CGUID+4 , 3),
|
||||
(@CGUID+5 , @CGUID+4 , 3),
|
||||
(@CGUID+6 , @CGUID+4 , 3),
|
||||
(@CGUID+7 , @CGUID+7 , 3),
|
||||
(@CGUID+8 , @CGUID+7 , 3),
|
||||
(@CGUID+9 , @CGUID+7 , 3),
|
||||
(@CGUID+10 , @CGUID+10 , 3),
|
||||
(@CGUID+11 , @CGUID+10 , 3),
|
||||
(@CGUID+12 , @CGUID+10 , 3),
|
||||
(@CGUID+23 , @CGUID+23 , 3),
|
||||
(@CGUID+24 , @CGUID+23 , 3),
|
||||
(@CGUID+25 , @CGUID+23 , 3),
|
||||
(@CGUID+26 , @CGUID+23 , 3),
|
||||
(@CGUID+27 , @CGUID+23 , 3),
|
||||
(@CGUID+28 , @CGUID+23 , 3),
|
||||
(@CGUID+29 , @CGUID+23 , 3),
|
||||
(@CGUID+30 , @CGUID+23 , 3),
|
||||
(@CGUID+31 , @CGUID+23 , 3),
|
||||
(@CGUID+32 , @CGUID+23 , 3),
|
||||
(@CGUID+33 , @CGUID+33 , 3),
|
||||
(@CGUID+34 , @CGUID+33 , 3),
|
||||
(@CGUID+35 , @CGUID+33 , 3),
|
||||
(@CGUID+36 , @CGUID+33 , 3),
|
||||
(@CGUID+37 , @CGUID+33 , 3),
|
||||
(@CGUID+38 , @CGUID+33 , 3),
|
||||
(@CGUID+39 , @CGUID+33 , 3),
|
||||
(@CGUID+40 , @CGUID+33 , 3),
|
||||
(@CGUID+41 , @CGUID+33 , 3),
|
||||
(@CGUID+42 , @CGUID+33 , 3),
|
||||
(@CGUID+43 , @CGUID+43 , 3),
|
||||
(@CGUID+44 , @CGUID+43 , 3),
|
||||
(@CGUID+45 , @CGUID+43 , 3),
|
||||
(@CGUID+46 , @CGUID+43 , 3),
|
||||
(@CGUID+47 , @CGUID+43 , 3),
|
||||
(@CGUID+48 , @CGUID+43 , 3),
|
||||
(@CGUID+49 , @CGUID+49 , 3),
|
||||
(@CGUID+50 , @CGUID+49 , 3),
|
||||
(@CGUID+51 , @CGUID+49 , 3),
|
||||
(@CGUID+52 , @CGUID+49 , 3),
|
||||
(@CGUID+53 , @CGUID+49 , 3),
|
||||
(@CGUID+54 , @CGUID+49 , 3),
|
||||
(@CGUID+62 , @CGUID+62 , 27),
|
||||
(@CGUID+63 , @CGUID+62 , 27),
|
||||
(@CGUID+64 , @CGUID+62 , 27),
|
||||
(@CGUID+65 , @CGUID+65 , 3),
|
||||
(@CGUID+66 , @CGUID+65 , 3),
|
||||
(@CGUID+67 , @CGUID+65 , 3),
|
||||
(@CGUID+68 , @CGUID+65 , 3),
|
||||
(@CGUID+69 , @CGUID+65 , 3),
|
||||
(@CGUID+70 , @CGUID+65 , 3),
|
||||
(@CGUID+71 , @CGUID+65 , 3),
|
||||
(@CGUID+74 , @CGUID+74 , 3),
|
||||
(@CGUID+75 , @CGUID+74 , 3),
|
||||
(@CGUID+76 , @CGUID+74 , 3),
|
||||
(@CGUID+77 , @CGUID+74 , 3),
|
||||
(@CGUID+78 , @CGUID+74 , 3),
|
||||
(@CGUID+79 , @CGUID+74 , 3),
|
||||
(@CGUID+82 , @CGUID+82 , 3),
|
||||
(@CGUID+83 , @CGUID+82 , 3),
|
||||
(@CGUID+84 , @CGUID+82 , 3),
|
||||
(@CGUID+85 , @CGUID+82 , 3),
|
||||
(@CGUID+86 , @CGUID+82 , 3),
|
||||
(@CGUID+87 , @CGUID+87 , 3),
|
||||
(@CGUID+88 , @CGUID+87 , 3),
|
||||
(@CGUID+89 , @CGUID+87 , 3),
|
||||
(@CGUID+90 , @CGUID+87 , 3),
|
||||
(@CGUID+91 , @CGUID+87 , 3),
|
||||
(@CGUID+92 , @CGUID+87 , 3),
|
||||
(@CGUID+93 , @CGUID+87 , 3),
|
||||
(@CGUID+94 , @CGUID+94 , 3),
|
||||
(@CGUID+95 , @CGUID+94 , 3),
|
||||
(@CGUID+96 , @CGUID+94 , 3),
|
||||
(@CGUID+97 , @CGUID+94 , 3),
|
||||
(@CGUID+98 , @CGUID+94 , 3),
|
||||
(@CGUID+99 , @CGUID+94 , 3),
|
||||
(@CGUID+146, @CGUID+146, 3),
|
||||
(@CGUID+147, @CGUID+146, 3),
|
||||
(@CGUID+148, @CGUID+146, 3),
|
||||
(@CGUID+149, @CGUID+146, 3),
|
||||
(@CGUID+150, @CGUID+146, 3),
|
||||
(@CGUID+151, @CGUID+146, 3),
|
||||
(@CGUID+152, @CGUID+152, 3),
|
||||
(@CGUID+153, @CGUID+152, 3),
|
||||
(@CGUID+154, @CGUID+152, 3),
|
||||
(@CGUID+155, @CGUID+152, 3),
|
||||
(@CGUID+156, @CGUID+152, 3),
|
||||
(@CGUID+157, @CGUID+152, 3),
|
||||
(@CGUID+158, @CGUID+158, 3),
|
||||
(@CGUID+159, @CGUID+158, 3),
|
||||
(@CGUID+160, @CGUID+158, 3),
|
||||
(@CGUID+161, @CGUID+158, 3),
|
||||
(@CGUID+162, @CGUID+158, 3),
|
||||
(@CGUID+163, @CGUID+158, 3),
|
||||
(@CGUID+164, @CGUID+164, 3),
|
||||
(@CGUID+165, @CGUID+164, 3),
|
||||
(@CGUID+166, @CGUID+164, 3),
|
||||
(@CGUID+167, @CGUID+164, 3),
|
||||
(@CGUID+168, @CGUID+164, 3),
|
||||
(@CGUID+169, @CGUID+164, 3),
|
||||
(@CGUID+170, @CGUID+170, 3),
|
||||
(@CGUID+171, @CGUID+170, 3),
|
||||
(@CGUID+172, @CGUID+170, 3),
|
||||
(@CGUID+173, @CGUID+170, 3),
|
||||
(@CGUID+174, @CGUID+170, 3),
|
||||
(@CGUID+175, @CGUID+170, 3),
|
||||
(@CGUID+188, @CGUID+188, 3),
|
||||
(@CGUID+189, @CGUID+188, 3),
|
||||
(@CGUID+190, @CGUID+190, 3),
|
||||
(@CGUID+191, @CGUID+190, 3),
|
||||
(@CGUID+192, @CGUID+192, 3),
|
||||
(@CGUID+193, @CGUID+192, 3),
|
||||
(@CGUID+194, @CGUID+194, 3),
|
||||
(@CGUID+195, @CGUID+194, 3),
|
||||
(@CGUID+196, @CGUID+196, 3),
|
||||
(@CGUID+197, @CGUID+196, 3),
|
||||
(@CGUID+198, @CGUID+198, 3),
|
||||
(@CGUID+199, @CGUID+198, 3),
|
||||
(@CGUID+200, @CGUID+198, 3),
|
||||
(@CGUID+201, @CGUID+198, 3),
|
||||
(@CGUID+202, @CGUID+198, 3),
|
||||
(@CGUID+203, @CGUID+198, 3),
|
||||
(@CGUID+204, @CGUID+198, 3),
|
||||
(@CGUID+205, @CGUID+198, 3),
|
||||
(@CGUID+206, @CGUID+206, 3),
|
||||
(@CGUID+207, @CGUID+206, 3),
|
||||
(@CGUID+208, @CGUID+206, 3),
|
||||
(@CGUID+209, @CGUID+206, 3),
|
||||
(@CGUID+210, @CGUID+206, 3),
|
||||
(@CGUID+211, @CGUID+206, 3),
|
||||
(@CGUID+212, @CGUID+206, 3),
|
||||
(@CGUID+213, @CGUID+206, 3),
|
||||
(@CGUID+222, @CGUID+222, 3),
|
||||
(@CGUID+223, @CGUID+222, 3),
|
||||
(@CGUID+224, @CGUID+222, 3),
|
||||
(@CGUID+225, @CGUID+222, 3),
|
||||
(@CGUID+226, @CGUID+226, 3),
|
||||
(@CGUID+227, @CGUID+226, 3),
|
||||
(@CGUID+228, @CGUID+226, 3),
|
||||
(@CGUID+229, @CGUID+226, 3),
|
||||
(@CGUID+253, @CGUID+253, 3),
|
||||
(@CGUID+254, @CGUID+253, 3),
|
||||
(@CGUID+255, @CGUID+253, 3),
|
||||
(@CGUID+256, @CGUID+253, 3),
|
||||
(@CGUID+266, @CGUID+266, 3),
|
||||
(@CGUID+267, @CGUID+266, 3),
|
||||
(@CGUID+268, @CGUID+266, 3),
|
||||
(@CGUID+269, @CGUID+266, 3),
|
||||
(@CGUID+270, @CGUID+266, 3),
|
||||
(@CGUID+271, @CGUID+266, 3),
|
||||
(@CGUID+272, @CGUID+266, 3),
|
||||
(@CGUID+273, @CGUID+273, 3),
|
||||
(@CGUID+274, @CGUID+273, 3),
|
||||
(@CGUID+275, @CGUID+273, 3),
|
||||
(@CGUID+276, @CGUID+273, 3),
|
||||
(@CGUID+277, @CGUID+273, 3),
|
||||
(@CGUID+278, @CGUID+273, 3),
|
||||
(@CGUID+279, @CGUID+273, 3),
|
||||
(@CGUID+280, @CGUID+280, 3),
|
||||
(@CGUID+281, @CGUID+280, 3),
|
||||
(@CGUID+282, @CGUID+280, 3),
|
||||
(@CGUID+283, @CGUID+280, 3),
|
||||
(@CGUID+284, @CGUID+280, 3),
|
||||
(@CGUID+287, @CGUID+287, 3),
|
||||
(@CGUID+289, @CGUID+287, 3),
|
||||
(@CGUID+290, @CGUID+287, 3),
|
||||
(@CGUID+291, @CGUID+287, 3),
|
||||
(@CGUID+292, @CGUID+287, 3),
|
||||
(@CGUID+293, @CGUID+287, 3),
|
||||
(@CGUID+294, @CGUID+287, 3),
|
||||
(@CGUID+295, @CGUID+287, 3),
|
||||
(@CGUID+296, @CGUID+287, 3),
|
||||
(@CGUID+297, @CGUID+297, 3),
|
||||
(@CGUID+298, @CGUID+297, 3),
|
||||
(@CGUID+299, @CGUID+297, 3),
|
||||
(@CGUID+300, @CGUID+297, 3),
|
||||
(@CGUID+301, @CGUID+297, 3),
|
||||
(@CGUID+302, @CGUID+302, 3),
|
||||
(@CGUID+303, @CGUID+302, 3),
|
||||
(@CGUID+304, @CGUID+302, 3),
|
||||
(@CGUID+305, @CGUID+302, 3),
|
||||
(@CGUID+318, @CGUID+318, 3),
|
||||
(@CGUID+319, @CGUID+318, 3),
|
||||
(@CGUID+320, @CGUID+318, 3),
|
||||
(@CGUID+321, @CGUID+318, 3),
|
||||
(@CGUID+322, @CGUID+318, 3),
|
||||
(@CGUID+323, @CGUID+323, 3),
|
||||
(@CGUID+324, @CGUID+323, 3),
|
||||
(@CGUID+325, @CGUID+323, 3),
|
||||
(@CGUID+326, @CGUID+323, 3),
|
||||
(@CGUID+327, @CGUID+323, 3),
|
||||
(@CGUID+328, @CGUID+328, 3),
|
||||
(@CGUID+329, @CGUID+328, 3),
|
||||
(@CGUID+330, @CGUID+330, 3),
|
||||
(@CGUID+331, @CGUID+330, 3),
|
||||
(@CGUID+365, @CGUID+365, 3),
|
||||
(@CGUID+366, @CGUID+365, 3),
|
||||
(@CGUID+367, @CGUID+365, 3),
|
||||
(@CGUID+368, @CGUID+365, 3),
|
||||
(@CGUID+369, @CGUID+365, 3),
|
||||
(@CGUID+370, @CGUID+365, 3),
|
||||
(@CGUID+371, @CGUID+365, 3),
|
||||
(@CGUID+372, @CGUID+365, 3),
|
||||
(@CGUID+373, @CGUID+373, 3),
|
||||
(@CGUID+374, @CGUID+373, 3),
|
||||
(@CGUID+375, @CGUID+373, 3),
|
||||
(@CGUID+376, @CGUID+373, 3),
|
||||
(@CGUID+377, @CGUID+373, 3),
|
||||
(@CGUID+378, @CGUID+373, 3),
|
||||
(@CGUID+379, @CGUID+373, 3),
|
||||
(@CGUID+380, @CGUID+373, 3),
|
||||
(@CGUID+383, @CGUID+383, 3),
|
||||
(@CGUID+384, @CGUID+383, 3),
|
||||
(@CGUID+385, @CGUID+383, 3),
|
||||
(@CGUID+386, @CGUID+383, 3),
|
||||
(@CGUID+387, @CGUID+383, 3),
|
||||
(@CGUID+388, @CGUID+383, 3),
|
||||
(@CGUID+389, @CGUID+383, 3),
|
||||
(@CGUID+390, @CGUID+383, 3),
|
||||
(@CGUID+391, @CGUID+383, 3),
|
||||
(@CGUID+392, @CGUID+383, 3),
|
||||
(@CGUID+393, @CGUID+383, 3),
|
||||
(@CGUID+396, @CGUID+396, 3),
|
||||
(@CGUID+397, @CGUID+396, 3),
|
||||
(@CGUID+398, @CGUID+396, 3),
|
||||
(@CGUID+399, @CGUID+396, 3),
|
||||
(@CGUID+400, @CGUID+396, 3),
|
||||
(@CGUID+401, @CGUID+396, 3),
|
||||
(@CGUID+402, @CGUID+396, 3),
|
||||
(@CGUID+403, @CGUID+396, 3),
|
||||
(@CGUID+404, @CGUID+396, 3),
|
||||
(@CGUID+405, @CGUID+396, 3),
|
||||
(@CGUID+406, @CGUID+396, 3),
|
||||
(@CGUID+418, @CGUID+418, 3),
|
||||
(@CGUID+419, @CGUID+418, 3),
|
||||
(@CGUID+420, @CGUID+418, 3),
|
||||
(@CGUID+421, @CGUID+418, 3),
|
||||
(@CGUID+422, @CGUID+418, 3),
|
||||
(@CGUID+423, @CGUID+418, 3),
|
||||
(@CGUID+540, @CGUID+540, 3),
|
||||
(@CGUID+541, @CGUID+540, 3),
|
||||
(@CGUID+542, @CGUID+540, 3),
|
||||
(@CGUID+543, @CGUID+540, 3),
|
||||
(@CGUID+544, @CGUID+540, 3),
|
||||
(@CGUID+545, @CGUID+540, 3),
|
||||
(@CGUID+546, @CGUID+540, 3),
|
||||
(@CGUID+547, @CGUID+540, 3),
|
||||
(@CGUID+548, @CGUID+540, 3),
|
||||
(@CGUID+549, @CGUID+540, 3),
|
||||
(@CGUID+550, @CGUID+550, 3),
|
||||
(@CGUID+551, @CGUID+550, 3),
|
||||
(@CGUID+552, @CGUID+550, 3),
|
||||
(@CGUID+553, @CGUID+550, 3),
|
||||
(@CGUID+554, @CGUID+550, 3),
|
||||
(@CGUID+555, @CGUID+550, 3),
|
||||
(@CGUID+556, @CGUID+550, 3),
|
||||
(@CGUID+557, @CGUID+550, 3),
|
||||
(@CGUID+558, @CGUID+550, 3),
|
||||
(@CGUID+559, @CGUID+550, 3),
|
||||
(@CGUID+560, @CGUID+560, 3),
|
||||
(@CGUID+561, @CGUID+560, 3),
|
||||
(@CGUID+562, @CGUID+560, 3),
|
||||
(@CGUID+563, @CGUID+560, 3),
|
||||
(@CGUID+564, @CGUID+560, 3),
|
||||
(@CGUID+565, @CGUID+560, 3),
|
||||
(@CGUID+566, @CGUID+560, 3),
|
||||
(@CGUID+567, @CGUID+560, 3),
|
||||
(@CGUID+568, @CGUID+560, 3),
|
||||
(@CGUID+569, @CGUID+560, 3),
|
||||
(@CGUID+570, @CGUID+570, 3),
|
||||
(@CGUID+571, @CGUID+570, 3),
|
||||
(@CGUID+572, @CGUID+570, 3),
|
||||
(@CGUID+573, @CGUID+570, 3),
|
||||
(@CGUID+574, @CGUID+570, 3),
|
||||
(@CGUID+575, @CGUID+570, 3),
|
||||
(@CGUID+576, @CGUID+570, 3),
|
||||
(@CGUID+577, @CGUID+570, 3),
|
||||
(@CGUID+578, @CGUID+570, 3),
|
||||
(@CGUID+579, @CGUID+570, 3),
|
||||
(@CGUID+580, @CGUID+580, 3),
|
||||
(@CGUID+581, @CGUID+580, 3),
|
||||
(@CGUID+582, @CGUID+580, 3),
|
||||
(@CGUID+583, @CGUID+580, 3),
|
||||
(@CGUID+584, @CGUID+580, 3),
|
||||
(@CGUID+585, @CGUID+580, 3),
|
||||
(@CGUID+586, @CGUID+580, 3),
|
||||
(@CGUID+587, @CGUID+580, 3),
|
||||
(@CGUID+588, @CGUID+580, 3),
|
||||
(@CGUID+589, @CGUID+580, 3),
|
||||
(@CGUID+592, @CGUID+592, 3),
|
||||
(@CGUID+593, @CGUID+592, 3),
|
||||
(@CGUID+594, @CGUID+592, 3),
|
||||
(@CGUID+595, @CGUID+592, 3),
|
||||
(@CGUID+596, @CGUID+592, 3),
|
||||
(@CGUID+597, @CGUID+592, 3),
|
||||
(@CGUID+598, @CGUID+592, 3),
|
||||
(@CGUID+599, @CGUID+592, 3),
|
||||
(@CGUID+600, @CGUID+592, 3),
|
||||
(@CGUID+601, @CGUID+592, 3),
|
||||
(@CGUID+602, @CGUID+602, 3),
|
||||
(@CGUID+603, @CGUID+602, 3),
|
||||
(@CGUID+605, @CGUID+605, 3),
|
||||
(@CGUID+606, @CGUID+605, 3),
|
||||
(@CGUID+607, @CGUID+605, 3),
|
||||
(@CGUID+608, @CGUID+605, 3),
|
||||
(@CGUID+609, @CGUID+605, 3),
|
||||
(@CGUID+610, @CGUID+605, 3),
|
||||
(@CGUID+611, @CGUID+605, 3),
|
||||
(@CGUID+612, @CGUID+605, 3),
|
||||
(@CGUID+613, @CGUID+605, 3),
|
||||
(@CGUID+614, @CGUID+605, 3),
|
||||
(@CGUID+615, @CGUID+615, 3),
|
||||
(@CGUID+616, @CGUID+615, 3),
|
||||
(@CGUID+617, @CGUID+615, 3),
|
||||
(@CGUID+618, @CGUID+615, 3),
|
||||
(@CGUID+619, @CGUID+615, 3),
|
||||
(@CGUID+620, @CGUID+615, 3),
|
||||
(@CGUID+621, @CGUID+615, 3),
|
||||
(@CGUID+622, @CGUID+615, 3),
|
||||
(@CGUID+623, @CGUID+615, 3),
|
||||
(@CGUID+624, @CGUID+615, 3),
|
||||
(@CGUID+625, @CGUID+625, 3),
|
||||
(@CGUID+626, @CGUID+625, 3),
|
||||
(@CGUID+627, @CGUID+625, 3),
|
||||
(@CGUID+628, @CGUID+628, 3),
|
||||
(@CGUID+629, @CGUID+628, 3),
|
||||
(@CGUID+630, @CGUID+628, 3),
|
||||
(@CGUID+631, @CGUID+631, 3),
|
||||
(@CGUID+632, @CGUID+631, 3),
|
||||
(@CGUID+633, @CGUID+631, 3),
|
||||
(@CGUID+634, @CGUID+631, 3),
|
||||
(@CGUID+635, @CGUID+635, 3),
|
||||
(@CGUID+636, @CGUID+635, 3),
|
||||
(@CGUID+637, @CGUID+635, 3),
|
||||
(@CGUID+638, @CGUID+638, 3),
|
||||
(@CGUID+639, @CGUID+638, 3),
|
||||
(@CGUID+640, @CGUID+638, 3),
|
||||
(@CGUID+641, @CGUID+638, 3),
|
||||
(@CGUID+642, @CGUID+638, 3),
|
||||
(@CGUID+643, @CGUID+638, 3),
|
||||
(@CGUID+644, @CGUID+644, 3),
|
||||
(@CGUID+645, @CGUID+644, 3),
|
||||
(@CGUID+646, @CGUID+644, 3),
|
||||
(@CGUID+647, @CGUID+644, 3),
|
||||
(@CGUID+648, @CGUID+648, 3),
|
||||
(@CGUID+649, @CGUID+648, 3),
|
||||
(@CGUID+650, @CGUID+648, 3),
|
||||
(@CGUID+651, @CGUID+648, 3),
|
||||
(@CGUID+652, @CGUID+648, 3),
|
||||
(@CGUID+653, @CGUID+648, 3),
|
||||
(@CGUID+654, @CGUID+654, 3),
|
||||
(@CGUID+655, @CGUID+654, 3),
|
||||
(@CGUID+656, @CGUID+654, 3),
|
||||
(@CGUID+657, @CGUID+654, 3),
|
||||
(@CGUID+658, @CGUID+658, 3),
|
||||
(@CGUID+659, @CGUID+658, 3),
|
||||
(@CGUID+660, @CGUID+658, 3),
|
||||
(@CGUID+661, @CGUID+658, 3),
|
||||
(@CGUID+662, @CGUID+658, 3),
|
||||
(@CGUID+663, @CGUID+658, 3),
|
||||
(@CGUID+664, @CGUID+658, 3),
|
||||
(@CGUID+665, @CGUID+658, 3),
|
||||
(@CGUID+666, @CGUID+658, 3),
|
||||
(@CGUID+667, @CGUID+658, 3),
|
||||
(@CGUID+668, @CGUID+668, 3),
|
||||
(@CGUID+669, @CGUID+668, 3),
|
||||
(@CGUID+670, @CGUID+668, 3),
|
||||
(@CGUID+671, @CGUID+668, 3),
|
||||
(@CGUID+672, @CGUID+668, 3),
|
||||
(@CGUID+673, @CGUID+673, 3),
|
||||
(@CGUID+674, @CGUID+673, 3),
|
||||
(@CGUID+675, @CGUID+673, 3),
|
||||
(@CGUID+676, @CGUID+673, 3),
|
||||
(@CGUID+677, @CGUID+673, 3),
|
||||
(@CGUID+691, @CGUID+691, 3),
|
||||
(@CGUID+692, @CGUID+691, 3),
|
||||
(@CGUID+693, @CGUID+691, 3),
|
||||
(@CGUID+694, @CGUID+691, 3),
|
||||
(@CGUID+695, @CGUID+691, 3),
|
||||
(@CGUID+696, @CGUID+691, 3),
|
||||
(@CGUID+697, @CGUID+697, 3),
|
||||
(@CGUID+698, @CGUID+697, 3),
|
||||
(@CGUID+699, @CGUID+697, 3),
|
||||
(@CGUID+700, @CGUID+697, 3),
|
||||
(@CGUID+701, @CGUID+697, 3),
|
||||
(@CGUID+702, @CGUID+697, 3),
|
||||
(@CGUID+703, @CGUID+703, 3),
|
||||
(@CGUID+704, @CGUID+703, 3),
|
||||
(@CGUID+705, @CGUID+703, 3),
|
||||
(@CGUID+706, @CGUID+703, 3),
|
||||
(@CGUID+707, @CGUID+703, 3),
|
||||
(@CGUID+708, @CGUID+703, 3),
|
||||
(@CGUID+709, @CGUID+709, 3),
|
||||
(@CGUID+710, @CGUID+709, 3),
|
||||
(@CGUID+711, @CGUID+709, 3),
|
||||
(@CGUID+712, @CGUID+709, 3),
|
||||
(@CGUID+713, @CGUID+709, 3),
|
||||
(@CGUID+714, @CGUID+709, 3),
|
||||
(@CGUID+716, @CGUID+716, 3),
|
||||
(@CGUID+717, @CGUID+716, 3),
|
||||
(@CGUID+718, @CGUID+716, 3),
|
||||
(@CGUID+719, @CGUID+716, 3);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@CGUID+1, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+2, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+3, @CGUID+1, 0, 0, 3),
|
||||
(@CGUID+4, @CGUID+4, 0, 0, 3),
|
||||
(@CGUID+5, @CGUID+4, 0, 0, 3),
|
||||
(@CGUID+6, @CGUID+4, 0, 0, 3),
|
||||
(@CGUID+7, @CGUID+7, 0, 0, 3),
|
||||
(@CGUID+8, @CGUID+7, 0, 0, 3),
|
||||
(@CGUID+9, @CGUID+7, 0, 0, 3),
|
||||
(@CGUID+10, @CGUID+10, 0, 0, 3),
|
||||
(@CGUID+11, @CGUID+10, 0, 0, 3),
|
||||
(@CGUID+12, @CGUID+10, 0, 0, 3),
|
||||
(@CGUID+23, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+24, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+25, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+27, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+29, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+30, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+31, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+32, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+33, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+35, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+37, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+38, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+39, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+40, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+41, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+42, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+45, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+46, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+47, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+48, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+49, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+50, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+51, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+52, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+53, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+54, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+62, @CGUID+62, 0, 0, 27),
|
||||
(@CGUID+63, @CGUID+62, 0, 0, 27),
|
||||
(@CGUID+64, @CGUID+62, 0, 0, 27),
|
||||
(@CGUID+65, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+66, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+67, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+68, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+69, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+70, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+71, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+74, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+75, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+76, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+77, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+78, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+79, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+82, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+83, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+84, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+85, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+87, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+88, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+90, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+92, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+93, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+94, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+95, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+96, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+97, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+98, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+99, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+146, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+147, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+148, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+149, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+150, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+151, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+152, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+153, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+154, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+155, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+156, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+157, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+158, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+160, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+161, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+162, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+163, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+165, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+166, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+167, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+168, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+169, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+170, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+171, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+172, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+173, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+174, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+175, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+188, @CGUID+188, 0, 0, 3),
|
||||
(@CGUID+189, @CGUID+188, 0, 0, 3),
|
||||
(@CGUID+190, @CGUID+190, 0, 0, 3),
|
||||
(@CGUID+191, @CGUID+190, 0, 0, 3),
|
||||
(@CGUID+192, @CGUID+192, 0, 0, 3),
|
||||
(@CGUID+193, @CGUID+192, 0, 0, 3),
|
||||
(@CGUID+194, @CGUID+194, 0, 0, 3),
|
||||
(@CGUID+195, @CGUID+194, 0, 0, 3),
|
||||
(@CGUID+196, @CGUID+196, 0, 0, 3),
|
||||
(@CGUID+197, @CGUID+196, 0, 0, 3),
|
||||
(@CGUID+198, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+199, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+200, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+201, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+202, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+203, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+204, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+205, @CGUID+198, 0, 0, 3),
|
||||
(@CGUID+206, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+207, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+208, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+209, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+210, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+211, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+212, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+213, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+222, @CGUID+222, 0, 0, 3),
|
||||
(@CGUID+223, @CGUID+222, 0, 0, 3),
|
||||
(@CGUID+224, @CGUID+222, 0, 0, 3),
|
||||
(@CGUID+225, @CGUID+222, 0, 0, 3),
|
||||
(@CGUID+226, @CGUID+226, 0, 0, 3),
|
||||
(@CGUID+227, @CGUID+226, 0, 0, 3),
|
||||
(@CGUID+228, @CGUID+226, 0, 0, 3),
|
||||
(@CGUID+229, @CGUID+226, 0, 0, 3),
|
||||
(@CGUID+253, @CGUID+253, 0, 0, 3),
|
||||
(@CGUID+254, @CGUID+253, 0, 0, 3),
|
||||
(@CGUID+255, @CGUID+253, 0, 0, 3),
|
||||
(@CGUID+256, @CGUID+253, 0, 0, 3),
|
||||
(@CGUID+266, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+267, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+268, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+269, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+270, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+271, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+272, @CGUID+266, 0, 0, 3),
|
||||
(@CGUID+273, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+274, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+275, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+276, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+277, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+278, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+279, @CGUID+273, 0, 0, 3),
|
||||
(@CGUID+280, @CGUID+280, 0, 0, 3),
|
||||
(@CGUID+281, @CGUID+280, 0, 0, 3),
|
||||
(@CGUID+282, @CGUID+280, 0, 0, 3),
|
||||
(@CGUID+283, @CGUID+280, 0, 0, 3),
|
||||
(@CGUID+284, @CGUID+280, 0, 0, 3),
|
||||
(@CGUID+287, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+289, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+290, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+291, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+292, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+293, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+294, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+295, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+296, @CGUID+287, 0, 0, 3),
|
||||
(@CGUID+297, @CGUID+297, 0, 0, 3),
|
||||
(@CGUID+298, @CGUID+297, 0, 0, 3),
|
||||
(@CGUID+299, @CGUID+297, 0, 0, 3),
|
||||
(@CGUID+300, @CGUID+297, 0, 0, 3),
|
||||
(@CGUID+301, @CGUID+297, 0, 0, 3),
|
||||
(@CGUID+302, @CGUID+302, 0, 0, 3),
|
||||
(@CGUID+303, @CGUID+302, 0, 0, 3),
|
||||
(@CGUID+304, @CGUID+302, 0, 0, 3),
|
||||
(@CGUID+305, @CGUID+302, 0, 0, 3),
|
||||
(@CGUID+318, @CGUID+318, 0, 0, 3),
|
||||
(@CGUID+319, @CGUID+318, 0, 0, 3),
|
||||
(@CGUID+320, @CGUID+318, 0, 0, 3),
|
||||
(@CGUID+321, @CGUID+318, 0, 0, 3),
|
||||
(@CGUID+322, @CGUID+318, 0, 0, 3),
|
||||
(@CGUID+323, @CGUID+323, 0, 0, 3),
|
||||
(@CGUID+324, @CGUID+323, 0, 0, 3),
|
||||
(@CGUID+325, @CGUID+323, 0, 0, 3),
|
||||
(@CGUID+326, @CGUID+323, 0, 0, 3),
|
||||
(@CGUID+327, @CGUID+323, 0, 0, 3),
|
||||
(@CGUID+328, @CGUID+328, 0, 0, 3),
|
||||
(@CGUID+329, @CGUID+328, 0, 0, 3),
|
||||
(@CGUID+330, @CGUID+330, 0, 0, 3),
|
||||
(@CGUID+331, @CGUID+330, 0, 0, 3),
|
||||
(@CGUID+365, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+366, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+367, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+368, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+369, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+370, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+371, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+372, @CGUID+365, 0, 0, 3),
|
||||
(@CGUID+373, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+374, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+375, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+376, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+377, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+378, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+379, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+380, @CGUID+373, 0, 0, 3),
|
||||
(@CGUID+383, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+384, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+385, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+386, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+387, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+388, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+389, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+390, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+391, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+392, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+393, @CGUID+383, 0, 0, 3),
|
||||
(@CGUID+396, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+397, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+398, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+399, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+400, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+401, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+402, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+403, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+404, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+405, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+406, @CGUID+396, 0, 0, 3),
|
||||
(@CGUID+418, @CGUID+418, 0, 0, 3),
|
||||
(@CGUID+419, @CGUID+418, 0, 0, 3),
|
||||
(@CGUID+420, @CGUID+418, 0, 0, 3),
|
||||
(@CGUID+421, @CGUID+418, 0, 0, 3),
|
||||
(@CGUID+422, @CGUID+418, 0, 0, 3),
|
||||
(@CGUID+423, @CGUID+418, 0, 0, 3),
|
||||
(@CGUID+540, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+541, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+542, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+543, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+544, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+545, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+546, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+547, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+548, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+549, @CGUID+540, 0, 0, 3),
|
||||
(@CGUID+550, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+551, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+552, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+553, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+554, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+555, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+556, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+557, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+558, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+559, @CGUID+550, 0, 0, 3),
|
||||
(@CGUID+560, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+561, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+562, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+563, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+564, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+565, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+566, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+567, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+568, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+569, @CGUID+560, 0, 0, 3),
|
||||
(@CGUID+570, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+571, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+572, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+573, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+574, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+575, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+576, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+577, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+578, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+579, @CGUID+570, 0, 0, 3),
|
||||
(@CGUID+580, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+581, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+582, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+583, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+584, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+585, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+586, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+587, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+588, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+589, @CGUID+580, 0, 0, 3),
|
||||
(@CGUID+592, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+593, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+594, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+595, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+596, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+597, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+598, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+599, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+600, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+601, @CGUID+592, 0, 0, 3),
|
||||
(@CGUID+602, @CGUID+602, 0, 0, 3),
|
||||
(@CGUID+603, @CGUID+602, 0, 0, 3),
|
||||
(@CGUID+605, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+606, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+607, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+608, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+609, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+610, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+611, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+612, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+613, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+614, @CGUID+605, 0, 0, 3),
|
||||
(@CGUID+615, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+616, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+617, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+618, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+619, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+620, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+621, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+622, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+623, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+624, @CGUID+615, 0, 0, 3),
|
||||
(@CGUID+625, @CGUID+625, 0, 0, 3),
|
||||
(@CGUID+626, @CGUID+625, 0, 0, 3),
|
||||
(@CGUID+627, @CGUID+625, 0, 0, 3),
|
||||
(@CGUID+628, @CGUID+628, 0, 0, 3),
|
||||
(@CGUID+629, @CGUID+628, 0, 0, 3),
|
||||
(@CGUID+630, @CGUID+628, 0, 0, 3),
|
||||
(@CGUID+631, @CGUID+631, 0, 0, 3),
|
||||
(@CGUID+632, @CGUID+631, 0, 0, 3),
|
||||
(@CGUID+633, @CGUID+631, 0, 0, 3),
|
||||
(@CGUID+634, @CGUID+631, 0, 0, 3),
|
||||
(@CGUID+635, @CGUID+635, 0, 0, 3),
|
||||
(@CGUID+636, @CGUID+635, 0, 0, 3),
|
||||
(@CGUID+637, @CGUID+635, 0, 0, 3),
|
||||
(@CGUID+638, @CGUID+638, 0, 0, 3),
|
||||
(@CGUID+639, @CGUID+638, 0, 0, 3),
|
||||
(@CGUID+640, @CGUID+638, 0, 0, 3),
|
||||
(@CGUID+641, @CGUID+638, 0, 0, 3),
|
||||
(@CGUID+642, @CGUID+638, 0, 0, 3),
|
||||
(@CGUID+643, @CGUID+638, 0, 0, 3),
|
||||
(@CGUID+644, @CGUID+644, 0, 0, 3),
|
||||
(@CGUID+645, @CGUID+644, 0, 0, 3),
|
||||
(@CGUID+646, @CGUID+644, 0, 0, 3),
|
||||
(@CGUID+647, @CGUID+644, 0, 0, 3),
|
||||
(@CGUID+648, @CGUID+648, 0, 0, 3),
|
||||
(@CGUID+649, @CGUID+648, 0, 0, 3),
|
||||
(@CGUID+650, @CGUID+648, 0, 0, 3),
|
||||
(@CGUID+651, @CGUID+648, 0, 0, 3),
|
||||
(@CGUID+652, @CGUID+648, 0, 0, 3),
|
||||
(@CGUID+653, @CGUID+648, 0, 0, 3),
|
||||
(@CGUID+654, @CGUID+654, 0, 0, 3),
|
||||
(@CGUID+655, @CGUID+654, 0, 0, 3),
|
||||
(@CGUID+656, @CGUID+654, 0, 0, 3),
|
||||
(@CGUID+657, @CGUID+654, 0, 0, 3),
|
||||
(@CGUID+658, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+659, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+660, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+661, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+662, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+663, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+664, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+665, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+666, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+667, @CGUID+658, 0, 0, 3),
|
||||
(@CGUID+668, @CGUID+668, 0, 0, 3),
|
||||
(@CGUID+669, @CGUID+668, 0, 0, 3),
|
||||
(@CGUID+670, @CGUID+668, 0, 0, 3),
|
||||
(@CGUID+671, @CGUID+668, 0, 0, 3),
|
||||
(@CGUID+672, @CGUID+668, 0, 0, 3),
|
||||
(@CGUID+673, @CGUID+673, 0, 0, 3),
|
||||
(@CGUID+674, @CGUID+673, 0, 0, 3),
|
||||
(@CGUID+675, @CGUID+673, 0, 0, 3),
|
||||
(@CGUID+676, @CGUID+673, 0, 0, 3),
|
||||
(@CGUID+677, @CGUID+673, 0, 0, 3),
|
||||
(@CGUID+691, @CGUID+691, 0, 0, 3),
|
||||
(@CGUID+692, @CGUID+691, 0, 0, 3),
|
||||
(@CGUID+693, @CGUID+691, 0, 0, 3),
|
||||
(@CGUID+694, @CGUID+691, 0, 0, 3),
|
||||
(@CGUID+695, @CGUID+691, 0, 0, 3),
|
||||
(@CGUID+696, @CGUID+691, 0, 0, 3),
|
||||
(@CGUID+697, @CGUID+697, 0, 0, 3),
|
||||
(@CGUID+698, @CGUID+697, 0, 0, 3),
|
||||
(@CGUID+699, @CGUID+697, 0, 0, 3),
|
||||
(@CGUID+700, @CGUID+697, 0, 0, 3),
|
||||
(@CGUID+701, @CGUID+697, 0, 0, 3),
|
||||
(@CGUID+702, @CGUID+697, 0, 0, 3),
|
||||
(@CGUID+703, @CGUID+703, 0, 0, 3),
|
||||
(@CGUID+704, @CGUID+703, 0, 0, 3),
|
||||
(@CGUID+705, @CGUID+703, 0, 0, 3),
|
||||
(@CGUID+706, @CGUID+703, 0, 0, 3),
|
||||
(@CGUID+707, @CGUID+703, 0, 0, 3),
|
||||
(@CGUID+708, @CGUID+703, 0, 0, 3),
|
||||
(@CGUID+709, @CGUID+709, 0, 0, 3),
|
||||
(@CGUID+710, @CGUID+709, 0, 0, 3),
|
||||
(@CGUID+711, @CGUID+709, 0, 0, 3),
|
||||
(@CGUID+712, @CGUID+709, 0, 0, 3),
|
||||
(@CGUID+713, @CGUID+709, 0, 0, 3),
|
||||
(@CGUID+714, @CGUID+709, 0, 0, 3),
|
||||
(@CGUID+716, @CGUID+716, 0, 0, 3),
|
||||
(@CGUID+717, @CGUID+716, 0, 0, 3),
|
||||
(@CGUID+718, @CGUID+716, 0, 0, 3),
|
||||
(@CGUID+719, @CGUID+716, 0, 0, 3);
|
||||
|
||||
DELETE FROM `creature_addon` WHERE `guid` IN (12726,12727,12728,12729,12730,12731,12732,12733,12734,12735,12736,12760,12776,12778,12779,12780,12781,12782,12784,12785,12786,12787,12788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12843,12866,12869,12870,12871,12872,12873,12874,12875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12886,12888,12889,12892,12894,13230,13235,40446,40526,40527,42920,46817,52411,52418,52420,52423,52424,52427,52428,52429,52430,52431,52432,52433,52440,52441,52442,52443,52444,52445,52446,52447,52448,52449,52450,52451,52452,52453,52454,52455,52456,52457,52458,52459,52460,52461,52462,52463,52464,52465,52739,52740,52743,52768,52769,52772,52773,52846,52847,52848,52850,52854,52855,52857,53054,53055,53056,53057,53058,53059,53210,53229,53586,53710,53711,53816,84716);
|
||||
DELETE FROM `waypoint_data` WHERE `id` IN (128660,128690,128840,128860,128880,128890,404460,405260,429200,468170,524110,524180,524200,524230,524240,524270,527390,527400,527430,527680,527690,527720,527730,528460,528470,528480,528500,528540,528550,528570,530540,530550,530560,530570,530580,530590,538160);
|
||||
|
||||
@@ -18,14 +18,14 @@ INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Lan
|
||||
UPDATE `creature` SET `spawntimesecs` = 300 WHERE `id1` = 23191 AND `map` = 564;
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` = 148236;
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(148236, 148236, 24),
|
||||
(148237, 148236, 24),
|
||||
(148238, 148236, 24),
|
||||
(148239, 148236, 24),
|
||||
(148240, 148236, 24),
|
||||
(148241, 148236, 24),
|
||||
(148242, 148236, 24);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(148236, 148236, 0, 0, 24),
|
||||
(148237, 148236, 0, 0, 24),
|
||||
(148238, 148236, 0, 0, 24),
|
||||
(148239, 148236, 0, 0, 24),
|
||||
(148240, 148236, 0, 0, 24),
|
||||
(148241, 148236, 0, 0, 24),
|
||||
(148242, 148236, 0, 0, 24);
|
||||
|
||||
-- Delete leftover gobs
|
||||
DELETE FROM `gameobject` WHERE `guid` IN (20523,20558,20559,20561,20563,20567) AND `map` = 564;
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
-- DB update 2024_07_09_06 -> 2024_07_09_07
|
||||
--
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (158167,158168,158169,158170,158171,158172,158173,158174,158175,158176,158177,158178,158155,158156,158157,158158,158159,158160,158161,158162,158163,158164,158165,158166,158143,158144,158145,158146,158147,158148,158149,158150,158151,158152,158153,158154);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(158167, 158167, 3),
|
||||
(158167, 158168, 3),
|
||||
(158167, 158169, 3),
|
||||
(158167, 158170, 3),
|
||||
(158167, 158171, 3),
|
||||
(158167, 158172, 3),
|
||||
(158167, 158173, 3),
|
||||
(158167, 158174, 3),
|
||||
(158167, 158175, 3),
|
||||
(158167, 158176, 3),
|
||||
(158167, 158177, 3),
|
||||
(158167, 158178, 3),
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(158167, 158167, 0, 0, 3),
|
||||
(158167, 158168, 0, 0, 3),
|
||||
(158167, 158169, 0, 0, 3),
|
||||
(158167, 158170, 0, 0, 3),
|
||||
(158167, 158171, 0, 0, 3),
|
||||
(158167, 158172, 0, 0, 3),
|
||||
(158167, 158173, 0, 0, 3),
|
||||
(158167, 158174, 0, 0, 3),
|
||||
(158167, 158175, 0, 0, 3),
|
||||
(158167, 158176, 0, 0, 3),
|
||||
(158167, 158177, 0, 0, 3),
|
||||
(158167, 158178, 0, 0, 3),
|
||||
|
||||
(158155, 158155, 3),
|
||||
(158155, 158156, 3),
|
||||
(158155, 158157, 3),
|
||||
(158155, 158158, 3),
|
||||
(158155, 158159, 3),
|
||||
(158155, 158160, 3),
|
||||
(158155, 158161, 3),
|
||||
(158155, 158162, 3),
|
||||
(158155, 158163, 3),
|
||||
(158155, 158164, 3),
|
||||
(158155, 158165, 3),
|
||||
(158155, 158166, 3),
|
||||
(158155, 158155, 0, 0, 3),
|
||||
(158155, 158156, 0, 0, 3),
|
||||
(158155, 158157, 0, 0, 3),
|
||||
(158155, 158158, 0, 0, 3),
|
||||
(158155, 158159, 0, 0, 3),
|
||||
(158155, 158160, 0, 0, 3),
|
||||
(158155, 158161, 0, 0, 3),
|
||||
(158155, 158162, 0, 0, 3),
|
||||
(158155, 158163, 0, 0, 3),
|
||||
(158155, 158164, 0, 0, 3),
|
||||
(158155, 158165, 0, 0, 3),
|
||||
(158155, 158166, 0, 0, 3),
|
||||
|
||||
(158143, 158143, 3),
|
||||
(158143, 158144, 3),
|
||||
(158143, 158145, 3),
|
||||
(158143, 158146, 3),
|
||||
(158143, 158147, 3),
|
||||
(158143, 158148, 3),
|
||||
(158143, 158149, 3),
|
||||
(158143, 158150, 3),
|
||||
(158143, 158151, 3),
|
||||
(158143, 158152, 3),
|
||||
(158143, 158153, 3),
|
||||
(158143, 158154, 3);
|
||||
(158143, 158143, 0, 0, 3),
|
||||
(158143, 158144, 0, 0, 3),
|
||||
(158143, 158145, 0, 0, 3),
|
||||
(158143, 158146, 0, 0, 3),
|
||||
(158143, 158147, 0, 0, 3),
|
||||
(158143, 158148, 0, 0, 3),
|
||||
(158143, 158149, 0, 0, 3),
|
||||
(158143, 158150, 0, 0, 3),
|
||||
(158143, 158151, 0, 0, 3),
|
||||
(158143, 158152, 0, 0, 3),
|
||||
(158143, 158153, 0, 0, 3),
|
||||
(158143, 158154, 0, 0, 3);
|
||||
|
||||
@@ -42,11 +42,26 @@ CREATE TABLE `realmlist` (
|
||||
--
|
||||
-- Dumping data for table `realmlist`
|
||||
--
|
||||
-- Defaults are tuned for fresh local installs: `address` is what the auth
|
||||
-- server hands clients after login as the WORLD server endpoint. Stock
|
||||
-- 127.0.0.1 means "the same box auth is running on", so a fresh
|
||||
-- `git clone` -> `docker compose up` works without any post-install
|
||||
-- tweaks for a developer hosting on their own machine.
|
||||
--
|
||||
-- Production deployments must override `address` after first dbimport,
|
||||
-- e.g.:
|
||||
-- UPDATE realmlist SET address = 'your.public.host', port = 8085 WHERE id = 1;
|
||||
-- See contrib/fractured-dev-extras/BUILD-NATIVE.md for the full deploy
|
||||
-- checklist (auth/world ports, firewall, public hostnames).
|
||||
--
|
||||
-- `port` is the WORLD server port (must match WorldServerPort in
|
||||
-- worldserver.conf). The auth-server LISTEN port is separately configured
|
||||
-- via RealmServerPort in authserver.conf (stock default 3724).
|
||||
|
||||
LOCK TABLES `realmlist` WRITE;
|
||||
/*!40000 ALTER TABLE `realmlist` DISABLE KEYS */;
|
||||
INSERT INTO `realmlist` VALUES
|
||||
(1,'AzerothCore','127.0.0.1','127.0.0.1','255.255.255.0',8085,0,0,1,0,0,12340);
|
||||
(1,'Fractured WoW','127.0.0.1','127.0.0.1','255.255.255.0',8085,0,0,1,0,0,12340);
|
||||
/*!40000 ALTER TABLE `realmlist` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ CREATE TABLE `world_state` (
|
||||
`Id` int unsigned NOT NULL COMMENT 'Internal save ID',
|
||||
`Data` longtext,
|
||||
PRIMARY KEY (`Id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='WorldState save system';
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WorldState save system';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
||||
@@ -27,7 +27,7 @@ CREATE TABLE `player_shapeshift_model` (
|
||||
`GenderID` tinyint unsigned NOT NULL,
|
||||
`ModelID` int unsigned NOT NULL,
|
||||
PRIMARY KEY (`ShapeshiftID`,`RaceID`,`CustomizationID`,`GenderID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci PACK_KEYS=0;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci PACK_KEYS=0;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
||||
@@ -25,7 +25,7 @@ CREATE TABLE `player_totem_model` (
|
||||
`RaceID` tinyint unsigned NOT NULL,
|
||||
`ModelID` int unsigned NOT NULL,
|
||||
PRIMARY KEY (`TotemID`,`RaceID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci PACK_KEYS=0;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci PACK_KEYS=0;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
||||
@@ -546,7 +546,7 @@ INSERT INTO `spell_target_position` VALUES
|
||||
(48274,0,575,302.36,-352.01,90.54,2.2,0),
|
||||
(48275,0,575,291.39,-352.01,90.54,0.91,0),
|
||||
(48276,0,575,296.651,-346.293,108.547,1.58,0),
|
||||
(48324,0,571,3454.11,-2802.37,202.14,0,34149345),
|
||||
(48324,0,571,3454.11,-2802.37,202.14,0,0),
|
||||
(48622,0,571,4274.53,-3055.55,319.463,2.535,0),
|
||||
(48760,0,571,3876.16,6984.44,106.32,6.279,0),
|
||||
(48960,0,571,4313.37,-2958.17,318.463,1.98,0),
|
||||
|
||||
@@ -665,97 +665,97 @@ INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`,
|
||||
|
||||
-- Static Linking
|
||||
DELETE FROM `creature_formations` WHERE `groupAI` IN (3, 27) AND `leaderGUID` IN (@CGUID+22,@CGUID+23,@CGUID+26,@CGUID+28,@CGUID+30,@CGUID+31,@CGUID+36,@CGUID+37,@CGUID+41,@CGUID+42,@CGUID+43,@CGUID+44,@CGUID+61,@CGUID+63,@CGUID+72,@CGUID+80,@CGUID+86,@CGUID+102,@CGUID+103,@CGUID+110,@CGUID+117,@CGUID+120,@CGUID+139,@CGUID+140) AND `memberGUID` IN (@CGUID+21,@CGUID+22,@CGUID+23,@CGUID+24,@CGUID+25,@CGUID+26,@CGUID+27,@CGUID+28,@CGUID+29,@CGUID+30,@CGUID+31,@CGUID+32,@CGUID+33,@CGUID+34,@CGUID+36,@CGUID+37,@CGUID+38,@CGUID+40,@CGUID+41,@CGUID+42,@CGUID+43,@CGUID+44,@CGUID+61,@CGUID+62,@CGUID+63,@CGUID+64,@CGUID+65,@CGUID+66,@CGUID+67,@CGUID+70,@CGUID+71,@CGUID+72,@CGUID+73,@CGUID+74,@CGUID+75,@CGUID+76,@CGUID+77,@CGUID+78,@CGUID+79,@CGUID+80,@CGUID+82,@CGUID+83,@CGUID+84,@CGUID+86,@CGUID+87,@CGUID+89,@CGUID+90,@CGUID+91,@CGUID+92,@CGUID+93,@CGUID+94,@CGUID+95,@CGUID+96,@CGUID+98,@CGUID+99,@CGUID+100,@CGUID+101,@CGUID+102,@CGUID+103,@CGUID+106,@CGUID+110,@CGUID+111,@CGUID+112,@CGUID+113,@CGUID+114,@CGUID+115,@CGUID+116,@CGUID+117,@CGUID+118,@CGUID+119,@CGUID+120,@CGUID+122,@CGUID+124,@CGUID+125,@CGUID+126,@CGUID+127,@CGUID+128,@CGUID+139,@CGUID+140,@CGUID+141,@CGUID+142,@CGUID+143,@CGUID+144,@CGUID+145,@CGUID+146,@CGUID+147,@CGUID+148,@CGUID+149,@CGUID+150,@CGUID+151,@CGUID+152,@CGUID+153,@CGUID+154);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(@CGUID+103, @CGUID+103, 3),
|
||||
(@CGUID+103, @CGUID+21, 3),
|
||||
(@CGUID+103, @CGUID+25, 3),
|
||||
(@CGUID+30, @CGUID+30, 3),
|
||||
(@CGUID+30, @CGUID+95, 3),
|
||||
(@CGUID+30, @CGUID+114, 3),
|
||||
(@CGUID+30, @CGUID+83, 3),
|
||||
(@CGUID+110, @CGUID+110, 3),
|
||||
(@CGUID+110, @CGUID+77, 3),
|
||||
(@CGUID+110, @CGUID+79, 3),
|
||||
(@CGUID+22, @CGUID+22, 3),
|
||||
(@CGUID+22, @CGUID+84, 3),
|
||||
(@CGUID+22, @CGUID+99, 3),
|
||||
(@CGUID+26, @CGUID+26, 3),
|
||||
(@CGUID+26, @CGUID+96, 3),
|
||||
(@CGUID+26, @CGUID+112, 3),
|
||||
(@CGUID+26, @CGUID+27, 3),
|
||||
(@CGUID+28, @CGUID+28, 3),
|
||||
(@CGUID+28, @CGUID+29, 3),
|
||||
(@CGUID+28, @CGUID+100, 3),
|
||||
(@CGUID+28, @CGUID+111, 3),
|
||||
(@CGUID+23, @CGUID+23, 3),
|
||||
(@CGUID+23, @CGUID+78, 3),
|
||||
(@CGUID+23, @CGUID+101, 3),
|
||||
(@CGUID+23, @CGUID+24, 3),
|
||||
(@CGUID+86, @CGUID+86, 3),
|
||||
(@CGUID+86, @CGUID+87, 3),
|
||||
(@CGUID+86, @CGUID+115, 3),
|
||||
(@CGUID+86, @CGUID+106, 3),
|
||||
(@CGUID+80, @CGUID+80, 3),
|
||||
(@CGUID+80, @CGUID+98, 3),
|
||||
(@CGUID+80, @CGUID+82, 3),
|
||||
(@CGUID+80, @CGUID+113, 3),
|
||||
(@CGUID+44, @CGUID+44, 27),
|
||||
(@CGUID+44, @CGUID+124, 27),
|
||||
(@CGUID+44, @CGUID+125, 27),
|
||||
(@CGUID+61, @CGUID+61, 3),
|
||||
(@CGUID+61, @CGUID+62, 3),
|
||||
(@CGUID+102, @CGUID+102, 3),
|
||||
(@CGUID+102, @CGUID+33, 3),
|
||||
(@CGUID+102, @CGUID+34, 3),
|
||||
(@CGUID+37, @CGUID+37, 3),
|
||||
(@CGUID+37, @CGUID+91, 3),
|
||||
(@CGUID+37, @CGUID+67, 3),
|
||||
(@CGUID+37, @CGUID+66, 3),
|
||||
(@CGUID+36, @CGUID+36, 3),
|
||||
(@CGUID+36, @CGUID+90, 3),
|
||||
(@CGUID+36, @CGUID+89, 3),
|
||||
(@CGUID+36, @CGUID+64, 3),
|
||||
(@CGUID+31, @CGUID+31, 3),
|
||||
(@CGUID+31, @CGUID+32, 3),
|
||||
(@CGUID+31, @CGUID+38, 3),
|
||||
(@CGUID+31, @CGUID+70, 3),
|
||||
(@CGUID+63, @CGUID+63, 3),
|
||||
(@CGUID+63, @CGUID+65, 3),
|
||||
(@CGUID+120, @CGUID+120, 3),
|
||||
(@CGUID+120, @CGUID+122, 3),
|
||||
(@CGUID+139, @CGUID+139, 3),
|
||||
(@CGUID+139, @CGUID+146, 3),
|
||||
(@CGUID+139, @CGUID+143, 3),
|
||||
(@CGUID+139, @CGUID+145, 3),
|
||||
(@CGUID+139, @CGUID+147, 3),
|
||||
(@CGUID+139, @CGUID+149, 3),
|
||||
(@CGUID+139, @CGUID+154, 3),
|
||||
(@CGUID+139, @CGUID+144, 3),
|
||||
(@CGUID+140, @CGUID+140, 3),
|
||||
(@CGUID+140, @CGUID+152, 3),
|
||||
(@CGUID+140, @CGUID+142, 3),
|
||||
(@CGUID+140, @CGUID+150, 3),
|
||||
(@CGUID+140, @CGUID+153, 3),
|
||||
(@CGUID+140, @CGUID+151, 3),
|
||||
(@CGUID+140, @CGUID+141, 3),
|
||||
(@CGUID+140, @CGUID+148, 3),
|
||||
(@CGUID+43, @CGUID+43, 3),
|
||||
(@CGUID+43, @CGUID+127, 3),
|
||||
(@CGUID+43, @CGUID+126, 3),
|
||||
(@CGUID+43, @CGUID+128, 3),
|
||||
(@CGUID+72, @CGUID+72, 3),
|
||||
(@CGUID+72, @CGUID+116, 3),
|
||||
(@CGUID+72, @CGUID+71, 3),
|
||||
(@CGUID+72, @CGUID+40, 3),
|
||||
(@CGUID+117, @CGUID+117, 3),
|
||||
(@CGUID+117, @CGUID+74, 3),
|
||||
(@CGUID+117, @CGUID+73, 3),
|
||||
(@CGUID+117, @CGUID+92, 3),
|
||||
(@CGUID+41, @CGUID+41, 3),
|
||||
(@CGUID+41, @CGUID+75, 3),
|
||||
(@CGUID+41, @CGUID+118, 3),
|
||||
(@CGUID+41, @CGUID+93, 3),
|
||||
(@CGUID+42, @CGUID+42, 3),
|
||||
(@CGUID+42, @CGUID+76, 3),
|
||||
(@CGUID+42, @CGUID+94, 3),
|
||||
(@CGUID+42, @CGUID+119, 3);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@CGUID+103, @CGUID+103, 0, 0, 3),
|
||||
(@CGUID+103, @CGUID+21, 0, 0, 3),
|
||||
(@CGUID+103, @CGUID+25, 0, 0, 3),
|
||||
(@CGUID+30, @CGUID+30, 0, 0, 3),
|
||||
(@CGUID+30, @CGUID+95, 0, 0, 3),
|
||||
(@CGUID+30, @CGUID+114, 0, 0, 3),
|
||||
(@CGUID+30, @CGUID+83, 0, 0, 3),
|
||||
(@CGUID+110, @CGUID+110, 0, 0, 3),
|
||||
(@CGUID+110, @CGUID+77, 0, 0, 3),
|
||||
(@CGUID+110, @CGUID+79, 0, 0, 3),
|
||||
(@CGUID+22, @CGUID+22, 0, 0, 3),
|
||||
(@CGUID+22, @CGUID+84, 0, 0, 3),
|
||||
(@CGUID+22, @CGUID+99, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+26, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+96, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+112, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+27, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+28, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+29, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+100, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+111, 0, 0, 3),
|
||||
(@CGUID+23, @CGUID+23, 0, 0, 3),
|
||||
(@CGUID+23, @CGUID+78, 0, 0, 3),
|
||||
(@CGUID+23, @CGUID+101, 0, 0, 3),
|
||||
(@CGUID+23, @CGUID+24, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+86, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+87, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+115, 0, 0, 3),
|
||||
(@CGUID+86, @CGUID+106, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+80, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+98, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+113, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+44, 0, 0, 27),
|
||||
(@CGUID+44, @CGUID+124, 0, 0, 27),
|
||||
(@CGUID+44, @CGUID+125, 0, 0, 27),
|
||||
(@CGUID+61, @CGUID+61, 0, 0, 3),
|
||||
(@CGUID+61, @CGUID+62, 0, 0, 3),
|
||||
(@CGUID+102, @CGUID+102, 0, 0, 3),
|
||||
(@CGUID+102, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+102, @CGUID+34, 0, 0, 3),
|
||||
(@CGUID+37, @CGUID+37, 0, 0, 3),
|
||||
(@CGUID+37, @CGUID+91, 0, 0, 3),
|
||||
(@CGUID+37, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+37, @CGUID+66, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+36, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+90, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+89, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+64, 0, 0, 3),
|
||||
(@CGUID+31, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+31, @CGUID+32, 0, 0, 3),
|
||||
(@CGUID+31, @CGUID+38, 0, 0, 3),
|
||||
(@CGUID+31, @CGUID+70, 0, 0, 3),
|
||||
(@CGUID+63, @CGUID+63, 0, 0, 3),
|
||||
(@CGUID+63, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+120, @CGUID+120, 0, 0, 3),
|
||||
(@CGUID+120, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+139, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+145, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+147, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+154, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+144, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+140, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+142, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+150, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+151, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+141, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+126, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+128, 0, 0, 3),
|
||||
(@CGUID+72, @CGUID+72, 0, 0, 3),
|
||||
(@CGUID+72, @CGUID+116, 0, 0, 3),
|
||||
(@CGUID+72, @CGUID+71, 0, 0, 3),
|
||||
(@CGUID+72, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+117, @CGUID+117, 0, 0, 3),
|
||||
(@CGUID+117, @CGUID+74, 0, 0, 3),
|
||||
(@CGUID+117, @CGUID+73, 0, 0, 3),
|
||||
(@CGUID+117, @CGUID+92, 0, 0, 3),
|
||||
(@CGUID+41, @CGUID+41, 0, 0, 3),
|
||||
(@CGUID+41, @CGUID+75, 0, 0, 3),
|
||||
(@CGUID+41, @CGUID+118, 0, 0, 3),
|
||||
(@CGUID+41, @CGUID+93, 0, 0, 3),
|
||||
(@CGUID+42, @CGUID+42, 0, 0, 3),
|
||||
(@CGUID+42, @CGUID+76, 0, 0, 3),
|
||||
(@CGUID+42, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+42, @CGUID+119, 0, 0, 3);
|
||||
|
||||
@@ -1239,162 +1239,162 @@ INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_
|
||||
*/
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `groupAI` = 3 AND `leaderGUID` IN (@CGUID+28,@CGUID+29,@CGUID+34,@CGUID+36,@CGUID+39,@CGUID+43,@CGUID+44,@CGUID+45,@CGUID+50,@CGUID+52,@CGUID+53,@CGUID+58,@CGUID+66,@CGUID+68,@CGUID+80,@CGUID+81,@CGUID+89,@CGUID+91,@CGUID+113,@CGUID+116,@CGUID+121,@CGUID+122,@CGUID+125,@CGUID+126,@CGUID+136,@CGUID+141,@CGUID+159,@CGUID+164,@CGUID+183,@CGUID+186,@CGUID+206,@CGUID+211,@CGUID+213,@CGUID+217,@CGUID+221,@CGUID+26) AND `memberGUID` IN (@CGUID+50,@CGUID+70,@CGUID+71,@CGUID+52,@CGUID+73,@CGUID+89,@CGUID+99,@CGUID+97,@CGUID+96,@CGUID+95,@CGUID+93,@CGUID+68,@CGUID+69,@CGUID+66,@CGUID+47,@CGUID+46,@CGUID+43,@CGUID+64,@CGUID+45,@CGUID+65,@CGUID+39,@CGUID+88,@CGUID+94,@CGUID+60,@CGUID+58,@CGUID+37,@CGUID+38,@CGUID+116,@CGUID+114,@CGUID+117,@CGUID+231,@CGUID+121,@CGUID+119,@CGUID+120,@CGUID+233,@CGUID+113,@CGUID+118,@CGUID+115,@CGUID+230,@CGUID+122,@CGUID+124,@CGUID+123,@CGUID+234,@CGUID+125,@CGUID+127,@CGUID+128,@CGUID+235,@CGUID+126,@CGUID+129,@CGUID+130,@CGUID+232,@CGUID+44,@CGUID+79,@CGUID+63,@CGUID+31,@CGUID+80,@CGUID+41,@CGUID+62,@CGUID+42,@CGUID+32,@CGUID+81,@CGUID+49,@CGUID+33,@CGUID+48,@CGUID+67,@CGUID+34,@CGUID+82,@CGUID+72,@CGUID+51,@CGUID+102,@CGUID+92,@CGUID+53,@CGUID+35,@CGUID+91,@CGUID+101,@CGUID+40,@CGUID+78,@CGUID+61,@CGUID+30,@CGUID+29,@CGUID+57,@CGUID+186,@CGUID+188,@CGUID+187,@CGUID+185,@CGUID+36,@CGUID+55,@CGUID+56,@CGUID+28,@CGUID+54,@CGUID+183,@CGUID+181,@CGUID+182,@CGUID+180,@CGUID+159,@CGUID+158,@CGUID+161,@CGUID+165,@CGUID+166,@CGUID+177,@CGUID+172,@CGUID+176,@CGUID+168,@CGUID+160,@CGUID+164,@CGUID+163,@CGUID+162,@CGUID+167,@CGUID+169,@CGUID+175,@CGUID+173,@CGUID+170,@CGUID+171,@CGUID+174,@CGUID+136,@CGUID+149,@CGUID+145,@CGUID+152,@CGUID+155,@CGUID+153,@CGUID+144,@CGUID+140,@CGUID+137,@CGUID+147,@CGUID+141,@CGUID+150,@CGUID+154,@CGUID+151,@CGUID+146,@CGUID+142,@CGUID+148,@CGUID+143,@CGUID+138,@CGUID+139,@CGUID+211,@CGUID+212,@CGUID+213,@CGUID+214,@CGUID+215,@CGUID+216,@CGUID+217,@CGUID+218,@CGUID+219,@CGUID+220,@CGUID+221,@CGUID+222,@CGUID+223,@CGUID+224,@CGUID+206,@CGUID+207,@CGUID+208,@CGUID+26,@CGUID+191,@CGUID+195,@CGUID+85);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(@CGUID+50, @CGUID+50, 3),
|
||||
(@CGUID+50, @CGUID+70, 3),
|
||||
(@CGUID+50, @CGUID+71, 3),
|
||||
(@CGUID+52, @CGUID+52, 3),
|
||||
(@CGUID+52, @CGUID+73, 3),
|
||||
(@CGUID+89, @CGUID+89, 3),
|
||||
(@CGUID+89, @CGUID+99, 3),
|
||||
(@CGUID+89, @CGUID+97, 3),
|
||||
(@CGUID+89, @CGUID+96, 3),
|
||||
(@CGUID+89, @CGUID+95, 3),
|
||||
(@CGUID+89, @CGUID+93, 3),
|
||||
(@CGUID+68, @CGUID+68, 3),
|
||||
(@CGUID+68, @CGUID+69, 3),
|
||||
(@CGUID+66, @CGUID+66, 3),
|
||||
(@CGUID+66, @CGUID+47, 3),
|
||||
(@CGUID+66, @CGUID+46, 3),
|
||||
(@CGUID+43, @CGUID+43, 3),
|
||||
(@CGUID+43, @CGUID+64, 3),
|
||||
(@CGUID+45, @CGUID+45, 3),
|
||||
(@CGUID+45, @CGUID+65, 3),
|
||||
(@CGUID+39, @CGUID+39, 3),
|
||||
(@CGUID+39, @CGUID+88, 3),
|
||||
(@CGUID+39, @CGUID+94, 3),
|
||||
(@CGUID+39, @CGUID+60, 3),
|
||||
(@CGUID+58, @CGUID+58, 3),
|
||||
(@CGUID+58, @CGUID+37, 3),
|
||||
(@CGUID+58, @CGUID+38, 3),
|
||||
(@CGUID+116, @CGUID+116, 3),
|
||||
(@CGUID+116, @CGUID+114, 3),
|
||||
(@CGUID+116, @CGUID+117, 3),
|
||||
(@CGUID+116, @CGUID+231, 3),
|
||||
(@CGUID+121, @CGUID+121, 3),
|
||||
(@CGUID+121, @CGUID+119, 3),
|
||||
(@CGUID+121, @CGUID+120, 3),
|
||||
(@CGUID+121, @CGUID+233, 3),
|
||||
(@CGUID+113, @CGUID+113, 3),
|
||||
(@CGUID+113, @CGUID+118, 3),
|
||||
(@CGUID+113, @CGUID+115, 3),
|
||||
(@CGUID+113, @CGUID+230, 3),
|
||||
(@CGUID+122, @CGUID+122, 3),
|
||||
(@CGUID+122, @CGUID+124, 3),
|
||||
(@CGUID+122, @CGUID+123, 3),
|
||||
(@CGUID+122, @CGUID+234, 3),
|
||||
(@CGUID+125, @CGUID+125, 3),
|
||||
(@CGUID+125, @CGUID+127, 3),
|
||||
(@CGUID+125, @CGUID+128, 3),
|
||||
(@CGUID+125, @CGUID+235, 3),
|
||||
(@CGUID+126, @CGUID+126, 3),
|
||||
(@CGUID+126, @CGUID+129, 3),
|
||||
(@CGUID+126, @CGUID+130, 3),
|
||||
(@CGUID+126, @CGUID+232, 3),
|
||||
(@CGUID+44, @CGUID+44, 3),
|
||||
(@CGUID+44, @CGUID+79, 3),
|
||||
(@CGUID+44, @CGUID+63, 3),
|
||||
(@CGUID+44, @CGUID+31, 3),
|
||||
(@CGUID+80, @CGUID+80, 3),
|
||||
(@CGUID+80, @CGUID+41, 3),
|
||||
(@CGUID+80, @CGUID+62, 3),
|
||||
(@CGUID+80, @CGUID+42, 3),
|
||||
(@CGUID+80, @CGUID+32, 3),
|
||||
(@CGUID+81, @CGUID+81, 3),
|
||||
(@CGUID+81, @CGUID+49, 3),
|
||||
(@CGUID+81, @CGUID+33, 3),
|
||||
(@CGUID+81, @CGUID+48, 3),
|
||||
(@CGUID+81, @CGUID+67, 3),
|
||||
(@CGUID+34, @CGUID+34, 3),
|
||||
(@CGUID+34, @CGUID+82, 3),
|
||||
(@CGUID+34, @CGUID+72, 3),
|
||||
(@CGUID+34, @CGUID+51, 3),
|
||||
(@CGUID+34, @CGUID+102, 3),
|
||||
(@CGUID+34, @CGUID+92, 3),
|
||||
(@CGUID+53, @CGUID+53, 3),
|
||||
(@CGUID+53, @CGUID+35, 3),
|
||||
(@CGUID+91, @CGUID+91, 3),
|
||||
(@CGUID+91, @CGUID+101, 3),
|
||||
(@CGUID+91, @CGUID+40, 3),
|
||||
(@CGUID+91, @CGUID+78, 3),
|
||||
(@CGUID+91, @CGUID+61, 3),
|
||||
(@CGUID+91, @CGUID+30, 3),
|
||||
(@CGUID+29, @CGUID+29, 3),
|
||||
(@CGUID+29, @CGUID+57, 3),
|
||||
(@CGUID+186, @CGUID+186, 3),
|
||||
(@CGUID+186, @CGUID+188, 3),
|
||||
(@CGUID+186, @CGUID+187, 3),
|
||||
(@CGUID+186, @CGUID+185, 3),
|
||||
(@CGUID+36, @CGUID+36, 3),
|
||||
(@CGUID+36, @CGUID+55, 3),
|
||||
(@CGUID+36, @CGUID+56, 3),
|
||||
(@CGUID+28, @CGUID+28, 3),
|
||||
(@CGUID+28, @CGUID+54, 3),
|
||||
(@CGUID+183, @CGUID+183, 3),
|
||||
(@CGUID+183, @CGUID+181, 3),
|
||||
(@CGUID+183, @CGUID+182, 3),
|
||||
(@CGUID+183, @CGUID+180, 3),
|
||||
(@CGUID+159, @CGUID+159, 3),
|
||||
(@CGUID+159, @CGUID+158, 3),
|
||||
(@CGUID+159, @CGUID+161, 3),
|
||||
(@CGUID+159, @CGUID+165, 3),
|
||||
(@CGUID+159, @CGUID+166, 3),
|
||||
(@CGUID+159, @CGUID+177, 3),
|
||||
(@CGUID+159, @CGUID+172, 3),
|
||||
(@CGUID+159, @CGUID+176, 3),
|
||||
(@CGUID+159, @CGUID+168, 3),
|
||||
(@CGUID+159, @CGUID+160, 3),
|
||||
(@CGUID+164, @CGUID+164, 3),
|
||||
(@CGUID+164, @CGUID+163, 3),
|
||||
(@CGUID+164, @CGUID+162, 3),
|
||||
(@CGUID+164, @CGUID+167, 3),
|
||||
(@CGUID+164, @CGUID+169, 3),
|
||||
(@CGUID+164, @CGUID+175, 3),
|
||||
(@CGUID+164, @CGUID+173, 3),
|
||||
(@CGUID+164, @CGUID+170, 3),
|
||||
(@CGUID+164, @CGUID+171, 3),
|
||||
(@CGUID+164, @CGUID+174, 3),
|
||||
(@CGUID+136, @CGUID+136, 3),
|
||||
(@CGUID+136, @CGUID+149, 3),
|
||||
(@CGUID+136, @CGUID+145, 3),
|
||||
(@CGUID+136, @CGUID+152, 3),
|
||||
(@CGUID+136, @CGUID+155, 3),
|
||||
(@CGUID+136, @CGUID+153, 3),
|
||||
(@CGUID+136, @CGUID+144, 3),
|
||||
(@CGUID+136, @CGUID+140, 3),
|
||||
(@CGUID+136, @CGUID+137, 3),
|
||||
(@CGUID+136, @CGUID+147, 3),
|
||||
(@CGUID+141, @CGUID+141, 3),
|
||||
(@CGUID+141, @CGUID+150, 3),
|
||||
(@CGUID+141, @CGUID+154, 3),
|
||||
(@CGUID+141, @CGUID+151, 3),
|
||||
(@CGUID+141, @CGUID+146, 3),
|
||||
(@CGUID+141, @CGUID+142, 3),
|
||||
(@CGUID+141, @CGUID+148, 3),
|
||||
(@CGUID+141, @CGUID+143, 3),
|
||||
(@CGUID+141, @CGUID+138, 3),
|
||||
(@CGUID+141, @CGUID+139, 3),
|
||||
(@CGUID+211, @CGUID+211, 3),
|
||||
(@CGUID+211, @CGUID+212, 3),
|
||||
(@CGUID+213, @CGUID+213, 3),
|
||||
(@CGUID+213, @CGUID+214, 3),
|
||||
(@CGUID+213, @CGUID+215, 3),
|
||||
(@CGUID+213, @CGUID+216, 3),
|
||||
(@CGUID+217, @CGUID+217, 3),
|
||||
(@CGUID+217, @CGUID+218, 3),
|
||||
(@CGUID+217, @CGUID+219, 3),
|
||||
(@CGUID+217, @CGUID+220, 3),
|
||||
(@CGUID+221, @CGUID+221, 3),
|
||||
(@CGUID+221, @CGUID+222, 3),
|
||||
(@CGUID+221, @CGUID+223, 3),
|
||||
(@CGUID+221, @CGUID+224, 3),
|
||||
(@CGUID+206, @CGUID+206, 3),
|
||||
(@CGUID+206, @CGUID+207, 3),
|
||||
(@CGUID+206, @CGUID+208, 3),
|
||||
(@CGUID+26, @CGUID+26, 3),
|
||||
(@CGUID+26, @CGUID+191, 3),
|
||||
(@CGUID+26, @CGUID+195, 3),
|
||||
(@CGUID+26, @CGUID+85, 3);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@CGUID+50, @CGUID+50, 0, 0, 3),
|
||||
(@CGUID+50, @CGUID+70, 0, 0, 3),
|
||||
(@CGUID+50, @CGUID+71, 0, 0, 3),
|
||||
(@CGUID+52, @CGUID+52, 0, 0, 3),
|
||||
(@CGUID+52, @CGUID+73, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+89, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+99, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+97, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+96, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+95, 0, 0, 3),
|
||||
(@CGUID+89, @CGUID+93, 0, 0, 3),
|
||||
(@CGUID+68, @CGUID+68, 0, 0, 3),
|
||||
(@CGUID+68, @CGUID+69, 0, 0, 3),
|
||||
(@CGUID+66, @CGUID+66, 0, 0, 3),
|
||||
(@CGUID+66, @CGUID+47, 0, 0, 3),
|
||||
(@CGUID+66, @CGUID+46, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+43, 0, 0, 3),
|
||||
(@CGUID+43, @CGUID+64, 0, 0, 3),
|
||||
(@CGUID+45, @CGUID+45, 0, 0, 3),
|
||||
(@CGUID+45, @CGUID+65, 0, 0, 3),
|
||||
(@CGUID+39, @CGUID+39, 0, 0, 3),
|
||||
(@CGUID+39, @CGUID+88, 0, 0, 3),
|
||||
(@CGUID+39, @CGUID+94, 0, 0, 3),
|
||||
(@CGUID+39, @CGUID+60, 0, 0, 3),
|
||||
(@CGUID+58, @CGUID+58, 0, 0, 3),
|
||||
(@CGUID+58, @CGUID+37, 0, 0, 3),
|
||||
(@CGUID+58, @CGUID+38, 0, 0, 3),
|
||||
(@CGUID+116, @CGUID+116, 0, 0, 3),
|
||||
(@CGUID+116, @CGUID+114, 0, 0, 3),
|
||||
(@CGUID+116, @CGUID+117, 0, 0, 3),
|
||||
(@CGUID+116, @CGUID+231, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+121, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+119, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+120, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+233, 0, 0, 3),
|
||||
(@CGUID+113, @CGUID+113, 0, 0, 3),
|
||||
(@CGUID+113, @CGUID+118, 0, 0, 3),
|
||||
(@CGUID+113, @CGUID+115, 0, 0, 3),
|
||||
(@CGUID+113, @CGUID+230, 0, 0, 3),
|
||||
(@CGUID+122, @CGUID+122, 0, 0, 3),
|
||||
(@CGUID+122, @CGUID+124, 0, 0, 3),
|
||||
(@CGUID+122, @CGUID+123, 0, 0, 3),
|
||||
(@CGUID+122, @CGUID+234, 0, 0, 3),
|
||||
(@CGUID+125, @CGUID+125, 0, 0, 3),
|
||||
(@CGUID+125, @CGUID+127, 0, 0, 3),
|
||||
(@CGUID+125, @CGUID+128, 0, 0, 3),
|
||||
(@CGUID+125, @CGUID+235, 0, 0, 3),
|
||||
(@CGUID+126, @CGUID+126, 0, 0, 3),
|
||||
(@CGUID+126, @CGUID+129, 0, 0, 3),
|
||||
(@CGUID+126, @CGUID+130, 0, 0, 3),
|
||||
(@CGUID+126, @CGUID+232, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+44, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+79, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+63, 0, 0, 3),
|
||||
(@CGUID+44, @CGUID+31, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+80, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+41, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+62, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+42, 0, 0, 3),
|
||||
(@CGUID+80, @CGUID+32, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+81, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+49, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+33, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+48, 0, 0, 3),
|
||||
(@CGUID+81, @CGUID+67, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+34, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+82, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+72, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+51, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+102, 0, 0, 3),
|
||||
(@CGUID+34, @CGUID+92, 0, 0, 3),
|
||||
(@CGUID+53, @CGUID+53, 0, 0, 3),
|
||||
(@CGUID+53, @CGUID+35, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+91, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+101, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+40, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+78, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+61, 0, 0, 3),
|
||||
(@CGUID+91, @CGUID+30, 0, 0, 3),
|
||||
(@CGUID+29, @CGUID+29, 0, 0, 3),
|
||||
(@CGUID+29, @CGUID+57, 0, 0, 3),
|
||||
(@CGUID+186, @CGUID+186, 0, 0, 3),
|
||||
(@CGUID+186, @CGUID+188, 0, 0, 3),
|
||||
(@CGUID+186, @CGUID+187, 0, 0, 3),
|
||||
(@CGUID+186, @CGUID+185, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+36, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+55, 0, 0, 3),
|
||||
(@CGUID+36, @CGUID+56, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+28, 0, 0, 3),
|
||||
(@CGUID+28, @CGUID+54, 0, 0, 3),
|
||||
(@CGUID+183, @CGUID+183, 0, 0, 3),
|
||||
(@CGUID+183, @CGUID+181, 0, 0, 3),
|
||||
(@CGUID+183, @CGUID+182, 0, 0, 3),
|
||||
(@CGUID+183, @CGUID+180, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+159, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+161, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+165, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+166, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+177, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+172, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+176, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+168, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+160, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+164, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+163, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+162, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+167, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+169, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+175, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+173, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+170, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+171, 0, 0, 3),
|
||||
(@CGUID+164, @CGUID+174, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+136, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+149, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+145, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+152, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+155, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+144, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+140, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+147, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+141, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+150, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+154, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+151, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+146, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+142, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+138, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+139, 0, 0, 3),
|
||||
(@CGUID+211, @CGUID+211, 0, 0, 3),
|
||||
(@CGUID+211, @CGUID+212, 0, 0, 3),
|
||||
(@CGUID+213, @CGUID+213, 0, 0, 3),
|
||||
(@CGUID+213, @CGUID+214, 0, 0, 3),
|
||||
(@CGUID+213, @CGUID+215, 0, 0, 3),
|
||||
(@CGUID+213, @CGUID+216, 0, 0, 3),
|
||||
(@CGUID+217, @CGUID+217, 0, 0, 3),
|
||||
(@CGUID+217, @CGUID+218, 0, 0, 3),
|
||||
(@CGUID+217, @CGUID+219, 0, 0, 3),
|
||||
(@CGUID+217, @CGUID+220, 0, 0, 3),
|
||||
(@CGUID+221, @CGUID+221, 0, 0, 3),
|
||||
(@CGUID+221, @CGUID+222, 0, 0, 3),
|
||||
(@CGUID+221, @CGUID+223, 0, 0, 3),
|
||||
(@CGUID+221, @CGUID+224, 0, 0, 3),
|
||||
(@CGUID+206, @CGUID+206, 0, 0, 3),
|
||||
(@CGUID+206, @CGUID+207, 0, 0, 3),
|
||||
(@CGUID+206, @CGUID+208, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+26, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+191, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+195, 0, 0, 3),
|
||||
(@CGUID+26, @CGUID+85, 0, 0, 3);
|
||||
|
||||
-- Linked Respawn for the respawning creatures in Murmur's Room
|
||||
DELETE FROM `linked_respawn` WHERE `guid` IN (@CGUID+225, @CGUID+226, @CGUID+227, @CGUID+228, @CGUID+229) AND `linkType`=0;
|
||||
|
||||
@@ -1395,90 +1395,90 @@ INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`,
|
||||
(@CGUID+180, @CGUID+182, 3, 270, 515);
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (@CGUID+006,@CGUID+007,@CGUID+010,@CGUID+011,@CGUID+012,@CGUID+013,@CGUID+014,@CGUID+015,@CGUID+016,@CGUID+017,@CGUID+018,@CGUID+008,@CGUID+009,@CGUID+019,@CGUID+023,@CGUID+021,@CGUID+022,@CGUID+020,@CGUID+024,@CGUID+027,@CGUID+025,@CGUID+028,@CGUID+026,@CGUID+029,@CGUID+032,@CGUID+030,@CGUID+033,@CGUID+031,@CGUID+034,@CGUID+035,@CGUID+036,@CGUID+037,@CGUID+038,@CGUID+039,@CGUID+040,@CGUID+041,@CGUID+094,@CGUID+095,@CGUID+096,@CGUID+097,@CGUID+121,@CGUID+122,@CGUID+123,@CGUID+124,@CGUID+131,@CGUID+134,@CGUID+132,@CGUID+135,@CGUID+133,@CGUID+136,@CGUID+137,@CGUID+138,@CGUID+139,@CGUID+140,@CGUID+141,@CGUID+142,@CGUID+175,@CGUID+176,@CGUID+177,@CGUID+178,@CGUID+183,@CGUID+184,@CGUID+192,@CGUID+193,@CGUID+046,@CGUID+047,@CGUID+048,@CGUID+148,@CGUID+149,@CGUID+150,@CGUID+151,@CGUID+152,@CGUID+143,@CGUID+144,@CGUID+145,@CGUID+147,@CGUID+146,@CGUID+153,@CGUID+155,@CGUID+157,@CGUID+154,@CGUID+156,@CGUID+158,@CGUID+159,@CGUID+160,@CGUID+161,@CGUID+162);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `groupAI`) VALUES
|
||||
(@CGUID+006,@CGUID+006,3),
|
||||
(@CGUID+007,@CGUID+006,3),
|
||||
(@CGUID+011,@CGUID+011,3),
|
||||
(@CGUID+012,@CGUID+011,3),
|
||||
(@CGUID+013,@CGUID+013,3),
|
||||
(@CGUID+014,@CGUID+013,3),
|
||||
(@CGUID+015,@CGUID+015,3),
|
||||
(@CGUID+016,@CGUID+015,3),
|
||||
(@CGUID+017,@CGUID+017,3),
|
||||
(@CGUID+018,@CGUID+017,3),
|
||||
(@CGUID+008,@CGUID+008,3),
|
||||
(@CGUID+009,@CGUID+008,3),
|
||||
(@CGUID+019,@CGUID+019,3),
|
||||
(@CGUID+023,@CGUID+019,3),
|
||||
(@CGUID+021,@CGUID+019,3),
|
||||
(@CGUID+022,@CGUID+019,3),
|
||||
(@CGUID+020,@CGUID+019,3),
|
||||
(@CGUID+024,@CGUID+024,3),
|
||||
(@CGUID+027,@CGUID+024,3),
|
||||
(@CGUID+025,@CGUID+024,3),
|
||||
(@CGUID+028,@CGUID+024,3),
|
||||
(@CGUID+026,@CGUID+024,3),
|
||||
(@CGUID+029,@CGUID+029,3),
|
||||
(@CGUID+032,@CGUID+029,3),
|
||||
(@CGUID+030,@CGUID+029,3),
|
||||
(@CGUID+033,@CGUID+029,3),
|
||||
(@CGUID+031,@CGUID+029,3),
|
||||
(@CGUID+034,@CGUID+029,3),
|
||||
(@CGUID+035,@CGUID+035,3),
|
||||
(@CGUID+036,@CGUID+035,3),
|
||||
(@CGUID+037,@CGUID+035,3),
|
||||
(@CGUID+038,@CGUID+035,3),
|
||||
(@CGUID+039,@CGUID+035,3),
|
||||
(@CGUID+040,@CGUID+035,3),
|
||||
(@CGUID+041,@CGUID+035,3),
|
||||
(@CGUID+094,@CGUID+094,3),
|
||||
(@CGUID+095,@CGUID+094,3),
|
||||
(@CGUID+096,@CGUID+094,3),
|
||||
(@CGUID+097,@CGUID+094,3),
|
||||
(@CGUID+121,@CGUID+121,3),
|
||||
(@CGUID+122,@CGUID+121,3),
|
||||
(@CGUID+123,@CGUID+121,3),
|
||||
(@CGUID+124,@CGUID+121,3),
|
||||
(@CGUID+131,@CGUID+131,3),
|
||||
(@CGUID+134,@CGUID+131,3),
|
||||
(@CGUID+132,@CGUID+131,3),
|
||||
(@CGUID+135,@CGUID+131,3),
|
||||
(@CGUID+133,@CGUID+131,3),
|
||||
(@CGUID+136,@CGUID+131,3),
|
||||
(@CGUID+137,@CGUID+137,3),
|
||||
(@CGUID+138,@CGUID+137,3),
|
||||
(@CGUID+139,@CGUID+137,3),
|
||||
(@CGUID+140,@CGUID+137,3),
|
||||
(@CGUID+141,@CGUID+137,3),
|
||||
(@CGUID+142,@CGUID+137,3),
|
||||
(@CGUID+175,@CGUID+175,3),
|
||||
(@CGUID+176,@CGUID+175,3),
|
||||
(@CGUID+177,@CGUID+177,3),
|
||||
(@CGUID+178,@CGUID+177,3),
|
||||
(@CGUID+183,@CGUID+183,3),
|
||||
(@CGUID+184,@CGUID+183,3),
|
||||
(@CGUID+192,@CGUID+192,3),
|
||||
(@CGUID+193,@CGUID+192,3),
|
||||
(@CGUID+046,@CGUID+046,3),
|
||||
(@CGUID+047,@CGUID+046,3),
|
||||
(@CGUID+048,@CGUID+046,3),
|
||||
(@CGUID+148,@CGUID+148,3),
|
||||
(@CGUID+149,@CGUID+148,3),
|
||||
(@CGUID+150,@CGUID+148,3),
|
||||
(@CGUID+151,@CGUID+148,3),
|
||||
(@CGUID+152,@CGUID+148,3),
|
||||
(@CGUID+143,@CGUID+143,3),
|
||||
(@CGUID+144,@CGUID+143,3),
|
||||
(@CGUID+145,@CGUID+143,3),
|
||||
(@CGUID+147,@CGUID+143,3),
|
||||
(@CGUID+146,@CGUID+143,3),
|
||||
(@CGUID+153,@CGUID+153,3),
|
||||
(@CGUID+155,@CGUID+153,3),
|
||||
(@CGUID+157,@CGUID+153,3),
|
||||
(@CGUID+154,@CGUID+153,3),
|
||||
(@CGUID+156,@CGUID+153,3),
|
||||
(@CGUID+158,@CGUID+158,3),
|
||||
(@CGUID+159,@CGUID+158,3),
|
||||
(@CGUID+160,@CGUID+158,3),
|
||||
(@CGUID+161,@CGUID+158,3),
|
||||
(@CGUID+162,@CGUID+158,3);
|
||||
INSERT INTO `creature_formations` (`memberGUID`, `leaderGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@CGUID+006, @CGUID+006, 0, 0, 3),
|
||||
(@CGUID+007, @CGUID+006, 0, 0, 3),
|
||||
(@CGUID+011, @CGUID+011, 0, 0, 3),
|
||||
(@CGUID+012, @CGUID+011, 0, 0, 3),
|
||||
(@CGUID+013, @CGUID+013, 0, 0, 3),
|
||||
(@CGUID+014, @CGUID+013, 0, 0, 3),
|
||||
(@CGUID+015, @CGUID+015, 0, 0, 3),
|
||||
(@CGUID+016, @CGUID+015, 0, 0, 3),
|
||||
(@CGUID+017, @CGUID+017, 0, 0, 3),
|
||||
(@CGUID+018, @CGUID+017, 0, 0, 3),
|
||||
(@CGUID+008, @CGUID+008, 0, 0, 3),
|
||||
(@CGUID+009, @CGUID+008, 0, 0, 3),
|
||||
(@CGUID+019, @CGUID+019, 0, 0, 3),
|
||||
(@CGUID+023, @CGUID+019, 0, 0, 3),
|
||||
(@CGUID+021, @CGUID+019, 0, 0, 3),
|
||||
(@CGUID+022, @CGUID+019, 0, 0, 3),
|
||||
(@CGUID+020, @CGUID+019, 0, 0, 3),
|
||||
(@CGUID+024, @CGUID+024, 0, 0, 3),
|
||||
(@CGUID+027, @CGUID+024, 0, 0, 3),
|
||||
(@CGUID+025, @CGUID+024, 0, 0, 3),
|
||||
(@CGUID+028, @CGUID+024, 0, 0, 3),
|
||||
(@CGUID+026, @CGUID+024, 0, 0, 3),
|
||||
(@CGUID+029, @CGUID+029, 0, 0, 3),
|
||||
(@CGUID+032, @CGUID+029, 0, 0, 3),
|
||||
(@CGUID+030, @CGUID+029, 0, 0, 3),
|
||||
(@CGUID+033, @CGUID+029, 0, 0, 3),
|
||||
(@CGUID+031, @CGUID+029, 0, 0, 3),
|
||||
(@CGUID+034, @CGUID+029, 0, 0, 3),
|
||||
(@CGUID+035, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+036, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+037, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+038, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+039, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+040, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+041, @CGUID+035, 0, 0, 3),
|
||||
(@CGUID+094, @CGUID+094, 0, 0, 3),
|
||||
(@CGUID+095, @CGUID+094, 0, 0, 3),
|
||||
(@CGUID+096, @CGUID+094, 0, 0, 3),
|
||||
(@CGUID+097, @CGUID+094, 0, 0, 3),
|
||||
(@CGUID+121, @CGUID+121, 0, 0, 3),
|
||||
(@CGUID+122, @CGUID+121, 0, 0, 3),
|
||||
(@CGUID+123, @CGUID+121, 0, 0, 3),
|
||||
(@CGUID+124, @CGUID+121, 0, 0, 3),
|
||||
(@CGUID+131, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+134, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+132, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+135, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+133, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+136, @CGUID+131, 0, 0, 3),
|
||||
(@CGUID+137, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+138, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+139, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+140, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+141, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+142, @CGUID+137, 0, 0, 3),
|
||||
(@CGUID+175, @CGUID+175, 0, 0, 3),
|
||||
(@CGUID+176, @CGUID+175, 0, 0, 3),
|
||||
(@CGUID+177, @CGUID+177, 0, 0, 3),
|
||||
(@CGUID+178, @CGUID+177, 0, 0, 3),
|
||||
(@CGUID+183, @CGUID+183, 0, 0, 3),
|
||||
(@CGUID+184, @CGUID+183, 0, 0, 3),
|
||||
(@CGUID+192, @CGUID+192, 0, 0, 3),
|
||||
(@CGUID+193, @CGUID+192, 0, 0, 3),
|
||||
(@CGUID+046, @CGUID+046, 0, 0, 3),
|
||||
(@CGUID+047, @CGUID+046, 0, 0, 3),
|
||||
(@CGUID+048, @CGUID+046, 0, 0, 3),
|
||||
(@CGUID+148, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+149, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+150, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+151, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+152, @CGUID+148, 0, 0, 3),
|
||||
(@CGUID+143, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+144, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+145, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+147, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+146, @CGUID+143, 0, 0, 3),
|
||||
(@CGUID+153, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+155, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+157, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+154, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+156, @CGUID+153, 0, 0, 3),
|
||||
(@CGUID+158, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+159, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+160, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+161, @CGUID+158, 0, 0, 3),
|
||||
(@CGUID+162, @CGUID+158, 0, 0, 3);
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Clamp VerifiedBuild literals to signed MEDIUMINT range for DBs that still use
|
||||
MEDIUMINT on VerifiedBuild (see data/sql/old/db_world/8.x/2022_10_30_01.sql).
|
||||
|
||||
Processes INSERT (explicit column lists) and simple UPDATE ... VerifiedBuild = N.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MAX_SIGNED_MEDIUMINT = 8388607
|
||||
MIN_SIGNED_MEDIUMINT = -8388608
|
||||
|
||||
INSERT_RE = re.compile(
|
||||
r"INSERT\s+INTO\s+`(?P<table>\w+)`\s*\((?P<cols>[^)]+)\)\s*VALUES\s*",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Base dumps: full row order ends with VerifiedBuild (6- or 8-column layouts).
|
||||
INSERT_SPELL_TP_VALUES_RE = re.compile(
|
||||
r"INSERT\s+INTO\s+`spell_target_position`\s*VALUES\s*",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
STMT_START = (
|
||||
"INSERT ",
|
||||
"DELETE ",
|
||||
"UPDATE ",
|
||||
"ALTER ",
|
||||
"DROP ",
|
||||
"CREATE ",
|
||||
"SET ",
|
||||
"REPLACE ",
|
||||
)
|
||||
|
||||
|
||||
def split_fields(inner: str) -> list[str]:
|
||||
fields: list[str] = []
|
||||
cur: list[str] = []
|
||||
depth = 0
|
||||
in_str = False
|
||||
str_ch = ""
|
||||
esc = False
|
||||
for ch in inner:
|
||||
if in_str:
|
||||
cur.append(ch)
|
||||
if esc:
|
||||
esc = False
|
||||
elif ch == "\\":
|
||||
esc = True
|
||||
elif ch == str_ch:
|
||||
in_str = False
|
||||
continue
|
||||
if ch in "'\"":
|
||||
in_str = True
|
||||
str_ch = ch
|
||||
cur.append(ch)
|
||||
continue
|
||||
if ch == "(":
|
||||
depth += 1
|
||||
elif ch == ")":
|
||||
depth -= 1
|
||||
if ch == "," and depth == 0:
|
||||
fields.append("".join(cur).strip())
|
||||
cur = []
|
||||
else:
|
||||
cur.append(ch)
|
||||
fields.append("".join(cur).strip())
|
||||
return fields
|
||||
|
||||
|
||||
def join_fields(fields: list[str]) -> str:
|
||||
return ", ".join(fields)
|
||||
|
||||
|
||||
def clamp_tuple(tuple_str: str, vb_idx: int) -> str:
|
||||
t = tuple_str.strip()
|
||||
if not (t.startswith("(") and t.endswith(")")):
|
||||
return tuple_str
|
||||
fields = split_fields(t[1:-1])
|
||||
if vb_idx >= len(fields):
|
||||
return tuple_str
|
||||
raw = fields[vb_idx].strip()
|
||||
if not re.fullmatch(r"-?\d+", raw):
|
||||
return tuple_str
|
||||
n = int(raw)
|
||||
if MIN_SIGNED_MEDIUMINT <= n <= MAX_SIGNED_MEDIUMINT:
|
||||
return tuple_str
|
||||
fields[vb_idx] = "0"
|
||||
return "(" + join_fields(fields) + ")"
|
||||
|
||||
|
||||
def process_value_segment(segment: str, vb_idx: int) -> tuple[str, int]:
|
||||
out: list[str] = []
|
||||
changes = 0
|
||||
i, n = 0, len(segment)
|
||||
while i < n:
|
||||
if segment[i] == "(":
|
||||
depth = 1
|
||||
j = i + 1
|
||||
while j < n and depth > 0:
|
||||
if segment[j] == "(":
|
||||
depth += 1
|
||||
elif segment[j] == ")":
|
||||
depth -= 1
|
||||
j += 1
|
||||
tup = segment[i:j]
|
||||
new_tup = clamp_tuple(tup, vb_idx)
|
||||
if new_tup != tup:
|
||||
changes += 1
|
||||
out.append(new_tup)
|
||||
i = j
|
||||
continue
|
||||
out.append(segment[i])
|
||||
i += 1
|
||||
return "".join(out), changes
|
||||
|
||||
|
||||
def clamp_update_verifiedbuild(line: str) -> tuple[str, int]:
|
||||
changes = 0
|
||||
|
||||
def repl(m: re.Match[str]) -> str:
|
||||
nonlocal changes
|
||||
num = m.group(1)
|
||||
n = int(num)
|
||||
if MIN_SIGNED_MEDIUMINT <= n <= MAX_SIGNED_MEDIUMINT:
|
||||
return m.group(0)
|
||||
changes += 1
|
||||
return f"`VerifiedBuild` = 0"
|
||||
|
||||
new_line = re.sub(
|
||||
r"`VerifiedBuild`\s*=\s*([0-9]+)",
|
||||
repl,
|
||||
line,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
return new_line, changes
|
||||
|
||||
|
||||
def first_tuple_vb_index(segment: str) -> int | None:
|
||||
i, n = 0, len(segment)
|
||||
while i < n:
|
||||
if segment[i] == "(":
|
||||
depth = 1
|
||||
j = i + 1
|
||||
while j < n and depth > 0:
|
||||
if segment[j] == "(":
|
||||
depth += 1
|
||||
elif segment[j] == ")":
|
||||
depth -= 1
|
||||
j += 1
|
||||
tup = segment[i:j]
|
||||
fields = split_fields(tup[1:-1])
|
||||
if fields:
|
||||
return len(fields) - 1
|
||||
return None
|
||||
i += 1
|
||||
return None
|
||||
|
||||
|
||||
def process_sql_text(text: str) -> tuple[str, int]:
|
||||
lines = text.splitlines(keepends=True)
|
||||
out: list[str] = []
|
||||
mode: str | None = None
|
||||
vb_idx = 0
|
||||
total_changes = 0
|
||||
|
||||
for line in lines:
|
||||
nl, ch = clamp_update_verifiedbuild(line)
|
||||
total_changes += ch
|
||||
line = nl
|
||||
|
||||
stripped = line.lstrip()
|
||||
|
||||
if mode == "insert_values":
|
||||
if stripped and not stripped.startswith("(") and not stripped.startswith("--"):
|
||||
if any(stripped.startswith(p) for p in STMT_START):
|
||||
mode = None
|
||||
|
||||
if mode == "spell_tp_values":
|
||||
if stripped and not stripped.startswith("(") and not stripped.startswith("--"):
|
||||
if any(stripped.startswith(p) for p in STMT_START):
|
||||
mode = None
|
||||
|
||||
if mode is None:
|
||||
m = INSERT_RE.search(line)
|
||||
if m and "`VerifiedBuild`" in m.group("cols"):
|
||||
cols = [c.strip().strip("`") for c in m.group("cols").split(",")]
|
||||
vb_idx = cols.index("VerifiedBuild")
|
||||
mode = "insert_values"
|
||||
prefix = line[: m.end()]
|
||||
suffix = line[m.end() :]
|
||||
if suffix.strip():
|
||||
new_suf, ch2 = process_value_segment(suffix, vb_idx)
|
||||
total_changes += ch2
|
||||
line = prefix + new_suf
|
||||
if ");" in line or line.rstrip().endswith(");"):
|
||||
mode = None
|
||||
out.append(line)
|
||||
continue
|
||||
m2 = INSERT_SPELL_TP_VALUES_RE.search(line)
|
||||
if m2:
|
||||
mode = "spell_tp_values"
|
||||
vb_idx = -1
|
||||
prefix = line[: m2.end()]
|
||||
suffix = line[m2.end() :]
|
||||
if suffix.strip():
|
||||
vb_idx = first_tuple_vb_index(suffix)
|
||||
if vb_idx is None:
|
||||
vb_idx = 7
|
||||
new_suf, ch2 = process_value_segment(suffix, vb_idx)
|
||||
total_changes += ch2
|
||||
line = prefix + new_suf
|
||||
if ");" in line or line.rstrip().endswith(");"):
|
||||
mode = None
|
||||
out.append(line)
|
||||
continue
|
||||
out.append(line)
|
||||
continue
|
||||
|
||||
if mode == "spell_tp_values":
|
||||
if vb_idx < 0:
|
||||
vb_idx = first_tuple_vb_index(line)
|
||||
if vb_idx is None:
|
||||
vb_idx = 7
|
||||
new_line, ch3 = process_value_segment(line, vb_idx)
|
||||
total_changes += ch3
|
||||
out.append(new_line)
|
||||
if ");" in line or line.rstrip().endswith(");"):
|
||||
mode = None
|
||||
continue
|
||||
|
||||
# insert_values continuation
|
||||
new_line, ch3 = process_value_segment(line, vb_idx)
|
||||
total_changes += ch3
|
||||
out.append(new_line)
|
||||
if ");" in line or line.rstrip().endswith(");"):
|
||||
mode = None
|
||||
|
||||
return "".join(out), total_changes
|
||||
|
||||
|
||||
def main() -> int:
|
||||
sql_root = Path(__file__).resolve().parents[1]
|
||||
roots = [
|
||||
sql_root / "archive" / "db_world",
|
||||
sql_root / "updates" / "db_world",
|
||||
sql_root / "base" / "db_world",
|
||||
]
|
||||
file_count = 0
|
||||
change_lines = 0
|
||||
for root in roots:
|
||||
if not root.exists():
|
||||
continue
|
||||
for path in sorted(root.glob("*.sql")):
|
||||
text = path.read_text(encoding="utf-8", errors="strict")
|
||||
new_text, ch = process_sql_text(text)
|
||||
if ch:
|
||||
path.write_text(new_text, encoding="utf-8")
|
||||
change_lines += ch
|
||||
file_count += 1
|
||||
print(f"{path.relative_to(sql_root)}: {ch} change(s)")
|
||||
print(f"Done. {file_count} file(s) written, {change_lines} change(s).")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -31,15 +31,15 @@ INSERT INTO `creature` (`guid`, `id1`, `map`, `zoneId`, `areaId`, `spawnMask`, `
|
||||
UPDATE `creature_template` SET `flags_extra` = `flags_extra`|33554432 WHERE `entry` IN (28732, 28733, 28734, 28731, 28730, 28729, 28684, 31612, 31616, 31615, 31617, 31608, 31605, 31606);
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` IN (12758, 12759, 12760);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(12758, 12758, 11),
|
||||
(12758, 12762, 11),
|
||||
(12758, 12761, 11),
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(12758, 12758, 0, 0, 11),
|
||||
(12758, 12762, 0, 0, 11),
|
||||
(12758, 12761, 0, 0, 11),
|
||||
|
||||
(12759, 12759, 11),
|
||||
(12759, 12763, 11),
|
||||
(12759, 12764, 11),
|
||||
(12759, 12759, 0, 0, 11),
|
||||
(12759, 12763, 0, 0, 11),
|
||||
(12759, 12764, 0, 0, 11),
|
||||
|
||||
(12760, 12760, 11),
|
||||
(12760, 12765, 11),
|
||||
(12760, 12766, 11);
|
||||
(12760, 12760, 0, 0, 11),
|
||||
(12760, 12765, 0, 0, 11),
|
||||
(12760, 12766, 0, 0, 11);
|
||||
|
||||
@@ -19,37 +19,37 @@ INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_
|
||||
(16505, 0, 3, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 0, 39, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Naxxramas Follower - On Aggro - Call For Help');
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `memberGUID` IN (127800, 127987, 127988, 127989, 127990, 127991, 127992, 127993, 127994, 127995, 127996, 127997, 127998, 127999, 128000, 128001, 128019, 128020, 128021, 128022, 128023, 128024, 128025, 128026, 128027, 128028, 128029, 128030, 128031, 128032, 128033, 128034, 128035);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(127800, 127800, 1),
|
||||
(127800, 127987, 1),
|
||||
(127800, 127988, 1),
|
||||
(127800, 127989, 1),
|
||||
(127800, 127990, 1),
|
||||
(127800, 127991, 1),
|
||||
(127800, 127992, 1),
|
||||
(127800, 127993, 1),
|
||||
(127800, 127994, 1),
|
||||
(127800, 127995, 1),
|
||||
(127800, 127996, 1),
|
||||
(127800, 127997, 1),
|
||||
(127800, 127998, 1),
|
||||
(127800, 127999, 1),
|
||||
(127800, 128000, 1),
|
||||
(127800, 128001, 1),
|
||||
(127800, 128019, 1),
|
||||
(127800, 128020, 1),
|
||||
(127800, 128021, 1),
|
||||
(127800, 128022, 1),
|
||||
(127800, 128023, 1),
|
||||
(127800, 128024, 1),
|
||||
(127800, 128025, 1),
|
||||
(127800, 128026, 1),
|
||||
(127800, 128027, 1),
|
||||
(127800, 128028, 1),
|
||||
(127800, 128029, 1),
|
||||
(127800, 128030, 1),
|
||||
(127800, 128031, 1),
|
||||
(127800, 128032, 1),
|
||||
(127800, 128033, 1),
|
||||
(127800, 128034, 1),
|
||||
(127800, 128035, 1);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(127800, 127800, 0, 0, 1),
|
||||
(127800, 127987, 0, 0, 1),
|
||||
(127800, 127988, 0, 0, 1),
|
||||
(127800, 127989, 0, 0, 1),
|
||||
(127800, 127990, 0, 0, 1),
|
||||
(127800, 127991, 0, 0, 1),
|
||||
(127800, 127992, 0, 0, 1),
|
||||
(127800, 127993, 0, 0, 1),
|
||||
(127800, 127994, 0, 0, 1),
|
||||
(127800, 127995, 0, 0, 1),
|
||||
(127800, 127996, 0, 0, 1),
|
||||
(127800, 127997, 0, 0, 1),
|
||||
(127800, 127998, 0, 0, 1),
|
||||
(127800, 127999, 0, 0, 1),
|
||||
(127800, 128000, 0, 0, 1),
|
||||
(127800, 128001, 0, 0, 1),
|
||||
(127800, 128019, 0, 0, 1),
|
||||
(127800, 128020, 0, 0, 1),
|
||||
(127800, 128021, 0, 0, 1),
|
||||
(127800, 128022, 0, 0, 1),
|
||||
(127800, 128023, 0, 0, 1),
|
||||
(127800, 128024, 0, 0, 1),
|
||||
(127800, 128025, 0, 0, 1),
|
||||
(127800, 128026, 0, 0, 1),
|
||||
(127800, 128027, 0, 0, 1),
|
||||
(127800, 128028, 0, 0, 1),
|
||||
(127800, 128029, 0, 0, 1),
|
||||
(127800, 128030, 0, 0, 1),
|
||||
(127800, 128031, 0, 0, 1),
|
||||
(127800, 128032, 0, 0, 1),
|
||||
(127800, 128033, 0, 0, 1),
|
||||
(127800, 128034, 0, 0, 1),
|
||||
(127800, 128035, 0, 0, 1);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
-- DB update 2026_01_04_00 -> 2026_01_04_01
|
||||
--
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` IN (12758, 12759, 12760);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(12758, 12758, 7),
|
||||
(12758, 12762, 7),
|
||||
(12758, 12761, 7),
|
||||
(12759, 12759, 7),
|
||||
(12759, 12763, 7),
|
||||
(12759, 12764, 7),
|
||||
(12760, 12760, 7),
|
||||
(12760, 12765, 7),
|
||||
(12760, 12766, 7);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(12758, 12758, 0, 0, 7),
|
||||
(12758, 12762, 0, 0, 7),
|
||||
(12758, 12761, 0, 0, 7),
|
||||
(12759, 12759, 0, 0, 7),
|
||||
(12759, 12763, 0, 0, 7),
|
||||
(12759, 12764, 0, 0, 7),
|
||||
(12760, 12760, 0, 0, 7),
|
||||
(12760, 12765, 0, 0, 7),
|
||||
(12760, 12766, 0, 0, 7);
|
||||
|
||||
DELETE FROM `linked_respawn` WHERE `linkedGuid` = 127214 AND `linkType` = 0;
|
||||
INSERT INTO `linked_respawn` (`guid`, `linkedGuid`, `linkType`) VALUES
|
||||
|
||||
@@ -2,41 +2,41 @@
|
||||
-- Hellfire Peninsula - Pools of Aggonar ooze aggro linking
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` BETWEEN 58465 and 58497;
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` = 58786;
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(58465, 58465, 3), (58465, 58498, 3), (58465, 58499, 3),
|
||||
(58466, 58466, 3), (58466, 58500, 3), (58466, 58504, 3),
|
||||
(58467, 58467, 3), (58467, 58501, 3), (58467, 58503, 3),
|
||||
(58468, 58468, 3), (58468, 58561, 3), (58468, 58562, 3),
|
||||
(58469, 58469, 3), (58469, 58507, 3), (58469, 58508, 3),
|
||||
(58470, 58470, 3), (58470, 58509, 3), (58470, 58510, 3),
|
||||
(58471, 58471, 3), (58471, 58502, 3), (58471, 58787, 3),
|
||||
(58786, 58786, 3), (58786, 58513, 3), (58786, 58514, 3),
|
||||
(58472, 58472, 3), (58472, 58511, 3), (58472, 58512, 3),
|
||||
(58473, 58473, 3), (58473, 58515, 3), (58473, 58516, 3),
|
||||
(58474, 58474, 3), (58474, 58517, 3), (58474, 58518, 3),
|
||||
(58475, 58475, 3), (58475, 58519, 3), (58475, 58520, 3),
|
||||
(58476, 58476, 3), (58476, 58521, 3), (58476, 58522, 3),
|
||||
(58477, 58477, 3), (58477, 58523, 3), (58477, 58524, 3),
|
||||
(58478, 58478, 3), (58478, 58525, 3), (58478, 58526, 3),
|
||||
(58479, 58479, 3), (58479, 58527, 3), (58479, 58528, 3),
|
||||
(58480, 58480, 3), (58480, 58529, 3), (58480, 58530, 3),
|
||||
(58481, 58481, 3), (58481, 58531, 3), (58481, 58532, 3),
|
||||
(58482, 58482, 3), (58482, 58535, 3), (58482, 58536, 3),
|
||||
(58483, 58483, 3), (58483, 58533, 3), (58483, 58534, 3),
|
||||
(58484, 58484, 3), (58484, 58537, 3), (58484, 58538, 3),
|
||||
(58485, 58485, 3), (58485, 58539, 3), (58485, 58540, 3),
|
||||
(58486, 58486, 3), (58486, 58541, 3), (58486, 58542, 3),
|
||||
(58487, 58487, 3), (58487, 58543, 3), (58487, 58544, 3),
|
||||
(58488, 58488, 3), (58488, 58545, 3), (58488, 58546, 3),
|
||||
(58489, 58489, 3), (58489, 58552, 3), (58489, 58553, 3),
|
||||
(58490, 58490, 3), (58490, 58554, 3), (58490, 58547, 3),
|
||||
(58491, 58491, 3), (58491, 58549, 3), (58491, 58548, 3),
|
||||
(58492, 58492, 3), (58492, 58550, 3), (58492, 58551, 3),
|
||||
(58493, 58493, 3), (58493, 58555, 3), (58493, 58556, 3),
|
||||
(58494, 58494, 3), (58494, 58557, 3), (58494, 58558, 3),
|
||||
(58495, 58495, 3), (58495, 58559, 3), (58495, 58560, 3),
|
||||
(58496, 58496, 3), (58496, 58505, 3), (58496, 58506, 3),
|
||||
(58497, 58497, 3), (58497, 58563, 3), (58497, 58564, 3);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(58465, 58465, 0, 0, 3), (58465, 58498, 0, 0, 3), (58465, 58499, 0, 0, 3),
|
||||
(58466, 58466, 0, 0, 3), (58466, 58500, 0, 0, 3), (58466, 58504, 0, 0, 3),
|
||||
(58467, 58467, 0, 0, 3), (58467, 58501, 0, 0, 3), (58467, 58503, 0, 0, 3),
|
||||
(58468, 58468, 0, 0, 3), (58468, 58561, 0, 0, 3), (58468, 58562, 0, 0, 3),
|
||||
(58469, 58469, 0, 0, 3), (58469, 58507, 0, 0, 3), (58469, 58508, 0, 0, 3),
|
||||
(58470, 58470, 0, 0, 3), (58470, 58509, 0, 0, 3), (58470, 58510, 0, 0, 3),
|
||||
(58471, 58471, 0, 0, 3), (58471, 58502, 0, 0, 3), (58471, 58787, 0, 0, 3),
|
||||
(58786, 58786, 0, 0, 3), (58786, 58513, 0, 0, 3), (58786, 58514, 0, 0, 3),
|
||||
(58472, 58472, 0, 0, 3), (58472, 58511, 0, 0, 3), (58472, 58512, 0, 0, 3),
|
||||
(58473, 58473, 0, 0, 3), (58473, 58515, 0, 0, 3), (58473, 58516, 0, 0, 3),
|
||||
(58474, 58474, 0, 0, 3), (58474, 58517, 0, 0, 3), (58474, 58518, 0, 0, 3),
|
||||
(58475, 58475, 0, 0, 3), (58475, 58519, 0, 0, 3), (58475, 58520, 0, 0, 3),
|
||||
(58476, 58476, 0, 0, 3), (58476, 58521, 0, 0, 3), (58476, 58522, 0, 0, 3),
|
||||
(58477, 58477, 0, 0, 3), (58477, 58523, 0, 0, 3), (58477, 58524, 0, 0, 3),
|
||||
(58478, 58478, 0, 0, 3), (58478, 58525, 0, 0, 3), (58478, 58526, 0, 0, 3),
|
||||
(58479, 58479, 0, 0, 3), (58479, 58527, 0, 0, 3), (58479, 58528, 0, 0, 3),
|
||||
(58480, 58480, 0, 0, 3), (58480, 58529, 0, 0, 3), (58480, 58530, 0, 0, 3),
|
||||
(58481, 58481, 0, 0, 3), (58481, 58531, 0, 0, 3), (58481, 58532, 0, 0, 3),
|
||||
(58482, 58482, 0, 0, 3), (58482, 58535, 0, 0, 3), (58482, 58536, 0, 0, 3),
|
||||
(58483, 58483, 0, 0, 3), (58483, 58533, 0, 0, 3), (58483, 58534, 0, 0, 3),
|
||||
(58484, 58484, 0, 0, 3), (58484, 58537, 0, 0, 3), (58484, 58538, 0, 0, 3),
|
||||
(58485, 58485, 0, 0, 3), (58485, 58539, 0, 0, 3), (58485, 58540, 0, 0, 3),
|
||||
(58486, 58486, 0, 0, 3), (58486, 58541, 0, 0, 3), (58486, 58542, 0, 0, 3),
|
||||
(58487, 58487, 0, 0, 3), (58487, 58543, 0, 0, 3), (58487, 58544, 0, 0, 3),
|
||||
(58488, 58488, 0, 0, 3), (58488, 58545, 0, 0, 3), (58488, 58546, 0, 0, 3),
|
||||
(58489, 58489, 0, 0, 3), (58489, 58552, 0, 0, 3), (58489, 58553, 0, 0, 3),
|
||||
(58490, 58490, 0, 0, 3), (58490, 58554, 0, 0, 3), (58490, 58547, 0, 0, 3),
|
||||
(58491, 58491, 0, 0, 3), (58491, 58549, 0, 0, 3), (58491, 58548, 0, 0, 3),
|
||||
(58492, 58492, 0, 0, 3), (58492, 58550, 0, 0, 3), (58492, 58551, 0, 0, 3),
|
||||
(58493, 58493, 0, 0, 3), (58493, 58555, 0, 0, 3), (58493, 58556, 0, 0, 3),
|
||||
(58494, 58494, 0, 0, 3), (58494, 58557, 0, 0, 3), (58494, 58558, 0, 0, 3),
|
||||
(58495, 58495, 0, 0, 3), (58495, 58559, 0, 0, 3), (58495, 58560, 0, 0, 3),
|
||||
(58496, 58496, 0, 0, 3), (58496, 58505, 0, 0, 3), (58496, 58506, 0, 0, 3),
|
||||
(58497, 58497, 0, 0, 3), (58497, 58563, 0, 0, 3), (58497, 58564, 0, 0, 3);
|
||||
|
||||
-- Reposition oozes to be closer to group members
|
||||
UPDATE `creature` SET `position_x`=381.658, `position_y`=3482.38, `position_z`=61.609, `orientation`=5.43889 WHERE `guid` = 58496 AND `id1` = 16901;
|
||||
|
||||
@@ -392,27 +392,27 @@ INSERT INTO `creature_addon` (`guid`, `path_id`) VALUES
|
||||
(@GUID+28, (@GUID+28)*10);
|
||||
|
||||
DELETE FROM `creature_formations` WHERE `leaderGUID` IN (@GUID+32,@GUID+38,@GUID+41,@GUID+47,@GUID+16,@GUID+4,@GUID+9,@GUID+12,@GUID+2,@GUID+26);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES
|
||||
(@GUID+32, @GUID+32, 3),
|
||||
(@GUID+32, @GUID+33, 3),
|
||||
(@GUID+2, @GUID+2 , 3),
|
||||
(@GUID+2, @GUID+3 , 3),
|
||||
(@GUID+26, @GUID+26, 3),
|
||||
(@GUID+26, @GUID+27, 3),
|
||||
(@GUID+38, @GUID+38, 3),
|
||||
(@GUID+38, @GUID+39, 3),
|
||||
(@GUID+41, @GUID+41, 3),
|
||||
(@GUID+41, @GUID+42, 3),
|
||||
(@GUID+47, @GUID+47, 3),
|
||||
(@GUID+47, @GUID+48, 3),
|
||||
(@GUID+16, @GUID+16, 3),
|
||||
(@GUID+16, @GUID+17, 3),
|
||||
(@GUID+4, @GUID+4 , 3),
|
||||
(@GUID+4, @GUID+5 , 3),
|
||||
(@GUID+9, @GUID+9 , 3),
|
||||
(@GUID+9, @GUID+10, 3),
|
||||
(@GUID+12, @GUID+12, 3),
|
||||
(@GUID+12, @GUID+13, 3);
|
||||
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES
|
||||
(@GUID+32, @GUID+32, 0, 0, 3),
|
||||
(@GUID+32, @GUID+33, 0, 0, 3),
|
||||
(@GUID+2, @GUID+2, 0, 0, 3),
|
||||
(@GUID+2, @GUID+3, 0, 0, 3),
|
||||
(@GUID+26, @GUID+26, 0, 0, 3),
|
||||
(@GUID+26, @GUID+27, 0, 0, 3),
|
||||
(@GUID+38, @GUID+38, 0, 0, 3),
|
||||
(@GUID+38, @GUID+39, 0, 0, 3),
|
||||
(@GUID+41, @GUID+41, 0, 0, 3),
|
||||
(@GUID+41, @GUID+42, 0, 0, 3),
|
||||
(@GUID+47, @GUID+47, 0, 0, 3),
|
||||
(@GUID+47, @GUID+48, 0, 0, 3),
|
||||
(@GUID+16, @GUID+16, 0, 0, 3),
|
||||
(@GUID+16, @GUID+17, 0, 0, 3),
|
||||
(@GUID+4, @GUID+4, 0, 0, 3),
|
||||
(@GUID+4, @GUID+5, 0, 0, 3),
|
||||
(@GUID+9, @GUID+9, 0, 0, 3),
|
||||
(@GUID+9, @GUID+10, 0, 0, 3),
|
||||
(@GUID+12, @GUID+12, 0, 0, 3),
|
||||
(@GUID+12, @GUID+13, 0, 0, 3);
|
||||
|
||||
DELETE FROM `creature_addon` WHERE `guid` IN (@GUID+32,@GUID+33,@GUID+2 ,@GUID+3 ,@GUID+26,@GUID+27,@GUID+38,@GUID+39,@GUID+41,@GUID+42,@GUID+47,@GUID+48,@GUID+16,@GUID+17,@GUID+4 ,@GUID+5 ,@GUID+9 ,@GUID+10,@GUID+12,@GUID+13);
|
||||
INSERT INTO `creature_addon` (`guid`, `bytes1`) VALUES
|
||||
|
||||
@@ -30,3 +30,14 @@ Auto-detected by `modules/CMakeLists.txt` (`GetModuleSourceList` globs
|
||||
every subdirectory). No additional CMake plumbing is needed; rebuild
|
||||
the worldserver image and the loader symbol `Addmod_paragonScripts`
|
||||
gets linked into the static `modules` target.
|
||||
|
||||
## SQL layout
|
||||
|
||||
SQL files live under `data/sql/db-world/base/` and
|
||||
`data/sql/db-characters/base/` — the standard AzerothCore module path
|
||||
that the built-in DBUpdater scans (see
|
||||
`src/server/database/Updater/UpdateFetcher.cpp`). Files placed there
|
||||
are applied automatically by `worldserver` / `dbimport` on startup and
|
||||
recorded by hash in the `updates` table of the target database, so
|
||||
re-runs are idempotent. Any new SQL added under those directories will
|
||||
be picked up on the next container/server start without manual import.
|
||||
|
||||
@@ -12,6 +12,11 @@ Paragon.StickyComboPoints = 1
|
||||
# in addition to runes/runic power. Required for the patch-enUS-5.MPQ player
|
||||
# frame to populate Mana/Rage/Energy bars - otherwise the server treats those
|
||||
# powers as inactive and never sends max values, leaving the bars empty.
|
||||
# Also required for core rage generation: Unit::DealDamage only calls
|
||||
# RewardRage() when the attacker HasActivePowerType(POWER_RAGE); if this is off,
|
||||
# Paragon white swings never grant rage (users without this line in any loaded
|
||||
# config used to hit the C++ fallback default of false). Default is on; set 0
|
||||
# only if you intentionally want a stripped-down Paragon test build.
|
||||
Paragon.MultiResource.HasActivePowers = 1
|
||||
|
||||
# Ability / Talent Essence (AE/TE) — Ascension-inspired currency
|
||||
@@ -23,12 +28,27 @@ Paragon.Currency.GrantLevelMin = 10
|
||||
Paragon.Currency.AE.PerLevel = 1
|
||||
Paragon.Currency.TE.PerLevel = 1
|
||||
# Flat TE cost per successful talent rank learn (hook runs once per LearnTalent).
|
||||
# Applies to passive / aura-only talents (addToSpellBook == 0).
|
||||
Paragon.Currency.TE.TalentLearnCost = 1
|
||||
# AE cost per rank for addToSpellBook talents (Starfall, Bladestorm, …).
|
||||
# Those talents also charge TE.TalentLearnCost per rank — each rank costs
|
||||
# both essences at the configured amounts.
|
||||
Paragon.Currency.AE.TalentLearnCost = 1
|
||||
# Default AE cost when spell is not listed in world.paragon_spell_ae_cost.
|
||||
Paragon.Currency.AE.DefaultSpellCost = 2
|
||||
# (Phase 3a: every learnable spell baked into the Character Advancement panel
|
||||
# has an explicit row of value 1 in that table, so this default only kicks in
|
||||
# for spells learned via .paragon learn that aren't in the panel's bake.)
|
||||
Paragon.Currency.AE.DefaultSpellCost = 1
|
||||
|
||||
# Diagnostics ----------------------------------------------------------------
|
||||
# When enabled, dumps every Paragon's rune cooldown state to the server log
|
||||
# every 5 seconds (channel "module"). Use with `.paragon runes` for in-game
|
||||
# verification. Leave at 0 in production — it's noisy.
|
||||
Paragon.Diag.RuneTrace = 0
|
||||
|
||||
# When enabled, traces every PanelLearnSpellChain commit: chain ids, before/
|
||||
# after spell-map sizes for each rank learn, and the classification of every
|
||||
# auto-granted side spell (chain rank / passive dep / active dep revoked).
|
||||
# Use to diagnose "spell X reappears in spellbook on relog" style bugs.
|
||||
# Leave at 0 in production.
|
||||
Paragon.Diag.PanelLearn = 0
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
-- Spells and talents learned only through Character Advancement (Lock In / .paragon learn).
|
||||
-- Apply to the character database (same as `characters`, `character_spell`, etc.).
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_panel_spells` (
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`guid`, `spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: spells purchased via Character Advancement';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_panel_talents` (
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`talent_id` SMALLINT UNSIGNED NOT NULL,
|
||||
`rank` TINYINT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`guid`, `talent_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: talent ranks purchased via Character Advancement';
|
||||
|
||||
-- Passive "dependent" spells that AzerothCore's `addSpell` machinery
|
||||
-- (via spell_learn_spell + SPELL_EFFECT_LEARN_SPELL) auto-grants when a
|
||||
-- panel-purchased spell is learned. We keep them learned (some are
|
||||
-- required for the parent ability to function -- e.g. Frost Fever for
|
||||
-- Icy Touch, Blood Plague for Plague Strike) but record them here so
|
||||
-- Reset Abilities / Reset Everything can unlearn them alongside the
|
||||
-- parent. Only passive auto-learns are tracked here; active dependents
|
||||
-- (Death Coil, Death Grip, ...) are revoked at learn time and never
|
||||
-- reach this table.
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_panel_spell_children` (
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`parent_spell_id` INT UNSIGNED NOT NULL COMMENT 'character_paragon_panel_spells.spell_id',
|
||||
`child_spell_id` INT UNSIGNED NOT NULL COMMENT 'auto-learned passive spell id',
|
||||
PRIMARY KEY (`guid`, `parent_spell_id`, `child_spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: passive auto-learn dependents to unlearn on reset';
|
||||
|
||||
-- Active "dependent" spells that AzerothCore's `addSpell` /
|
||||
-- `learnSkillRewardedSpells` machinery auto-grants alongside a
|
||||
-- panel-purchased spell but that the player did NOT buy (e.g. Blood
|
||||
-- Presence, Death Coil, Death Grip from purchasing Plague Strike).
|
||||
-- We revoke them at panel-commit time, but AC's skill cascade re-runs
|
||||
-- on every login (`Player::_LoadSkills` -> `learnSkillRewardedSpells`)
|
||||
-- and silently re-grants them. We persist the revoke decisions here
|
||||
-- and re-revoke at `OnPlayerLogin` so the spellbook stays in sync with
|
||||
-- what the player actually purchased through Character Advancement.
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_panel_spell_revoked` (
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`parent_spell_id` INT UNSIGNED NOT NULL COMMENT 'character_paragon_panel_spells.spell_id',
|
||||
`revoked_spell_id` INT UNSIGNED NOT NULL COMMENT 'active spell id auto-granted by skill cascade and revoked',
|
||||
PRIMARY KEY (`guid`, `parent_spell_id`, `revoked_spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: active auto-learn dependents to keep revoked across logins';
|
||||
@@ -0,0 +1,20 @@
|
||||
-- mod-paragon: tracking table for active spell dependents the panel
|
||||
-- revoked at commit time. AzerothCore's `Player::_LoadSkills` ->
|
||||
-- `learnSkillRewardedSpells` re-grants skill-rewarded actives (Blood
|
||||
-- Presence, Death Coil, Death Grip, ...) on every login. Persisting
|
||||
-- the revoke decisions here lets `OnPlayerLogin` re-revoke them after
|
||||
-- the cascade has run, so the spellbook stays in sync with what was
|
||||
-- actually purchased through Character Advancement.
|
||||
--
|
||||
-- This file lives under `updates/` so AC's DBUpdater applies it
|
||||
-- incrementally on existing databases (the matching `CREATE TABLE
|
||||
-- IF NOT EXISTS` block in base/character_paragon_panel_learned.sql
|
||||
-- handles fresh installs).
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_panel_spell_revoked` (
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`parent_spell_id` INT UNSIGNED NOT NULL COMMENT 'character_paragon_panel_spells.spell_id',
|
||||
`revoked_spell_id` INT UNSIGNED NOT NULL COMMENT 'active spell id auto-granted by skill cascade and revoked',
|
||||
PRIMARY KEY (`guid`, `parent_spell_id`, `revoked_spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: active auto-learn dependents to keep revoked across logins';
|
||||
@@ -0,0 +1,62 @@
|
||||
-- mod-paragon Character Advancement: Build catalog (saved loadouts).
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- A "build" is a named, icon-tagged loadout of panel-purchased spells and
|
||||
-- talent ranks. Each Paragon character can save many builds and swap
|
||||
-- between them via the Builds page in the Character Advancement panel.
|
||||
--
|
||||
-- Swap workflow (see HandleBuildLoad in Paragon_Builds.cpp):
|
||||
-- 1. If a build is currently active, snapshot the player's current
|
||||
-- panel-purchased spells + per-spec talent ranks into that build's
|
||||
-- recipe rows (overwriting the stored recipe).
|
||||
-- 2. If the active build's hunter pet is currently summoned, unsummon
|
||||
-- it to PET_SAVE_NOT_IN_SLOT and store its `pet_number` on the
|
||||
-- active build row so it can be restored on swap-back.
|
||||
-- 3. Reset all panel-bought abilities and talents (refunding AE/TE).
|
||||
-- 4. Re-buy each spell + talent in the target build's recipe (charging
|
||||
-- AE/TE; aborts if insufficient AE/TE -- player keeps refunded
|
||||
-- currency in that case and active becomes NULL).
|
||||
-- 5. Move the target build's parked pet (if any) back to current.
|
||||
-- 6. Update active_build pointer.
|
||||
--
|
||||
-- Pet ownership: a parked pet sits in `character_pet` with slot=100
|
||||
-- (PET_SAVE_NOT_IN_SLOT), exactly like the engine's stable-master
|
||||
-- offload, but tied to the build via `pet_number` instead of any
|
||||
-- in-game stable slot. Build deletion drops the parked pet rows
|
||||
-- entirely (PET_SAVE_AS_DELETED equivalent) -- player is warned.
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_builds` (
|
||||
`build_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`name` VARCHAR(32) NOT NULL,
|
||||
`icon` VARCHAR(64) NOT NULL DEFAULT 'INV_Misc_QuestionMark',
|
||||
`is_favorite` TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`pet_number` INT UNSIGNED NULL COMMENT 'character_pet.id of parked hunter pet, NULL when no pet bound to this build',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`build_id`),
|
||||
KEY `idx_guid` (`guid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: saved Character Advancement build catalog';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_build_spells` (
|
||||
`build_id` INT UNSIGNED NOT NULL,
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`build_id`, `spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: per-build recipe -- panel-purchased spells';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_build_talents` (
|
||||
`build_id` INT UNSIGNED NOT NULL,
|
||||
`spec` TINYINT UNSIGNED NOT NULL COMMENT '0 = primary spec, 1 = secondary (dual spec)',
|
||||
`talent_id` SMALLINT UNSIGNED NOT NULL,
|
||||
`rank` TINYINT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`build_id`, `spec`, `talent_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: per-build recipe -- panel-purchased talent ranks per spec';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_active_build` (
|
||||
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
|
||||
`build_id` INT UNSIGNED NOT NULL COMMENT 'character_paragon_builds.build_id (per-character active pointer)',
|
||||
PRIMARY KEY (`guid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: pointer to whichever build is currently loaded (one row per Paragon character)';
|
||||
@@ -0,0 +1,30 @@
|
||||
-- mod-paragon Character Advancement: Builds catalog schema cleanup.
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Two changes:
|
||||
-- 1. Drop `is_favorite` -- the favorite flag and shift-click-to-favorite
|
||||
-- flow are removed. Builds are now ordered solely by build_id ASC.
|
||||
-- 2. Add `share_code` CHAR(6) -- a random alphanumeric token generated
|
||||
-- server-side at build creation that uniquely identifies a saved
|
||||
-- build across the realm. Players exchange codes out-of-band and
|
||||
-- use the BuildsPane "Load Build!" share box to import a copy of
|
||||
-- the build (name + icon + spell + talent recipe) into their own
|
||||
-- catalog. The copy gets a fresh share_code so re-sharing is
|
||||
-- always traceable to the latest owner; the original isn't touched.
|
||||
--
|
||||
-- The column is NULL-tolerant so any rows that pre-date this migration
|
||||
-- (created under 2026_05_10_03's schema) coexist cleanly. The server
|
||||
-- backfills NULLs lazily in PushBuildCatalog -- the next time a player
|
||||
-- opens the BuildsPane on a Paragon character, any of their builds that
|
||||
-- still have a NULL share_code will get one generated and persisted.
|
||||
--
|
||||
-- Charset: 31 unambiguous chars (A-Z minus I/O minus 0/1) gives 31^6 ~=
|
||||
-- 887M codes; collision retry on insert keeps probability of a duplicate
|
||||
-- vanishing for any realistic catalog size.
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
ALTER TABLE `character_paragon_builds`
|
||||
DROP COLUMN `is_favorite`,
|
||||
ADD COLUMN `share_code` CHAR(6) NULL DEFAULT NULL
|
||||
COMMENT 'random alphanumeric token for import-by-code; lazily generated'
|
||||
AFTER `icon`,
|
||||
ADD UNIQUE INDEX `uk_share_code` (`share_code`);
|
||||
@@ -0,0 +1,34 @@
|
||||
-- mod-paragon: preserve superseded share codes as importable snapshots.
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- When an active build is updated (Learn All), the live row gets a new
|
||||
-- share_code and a fresh recipe. Older codes the player posted to Discord
|
||||
-- must keep working: each retired code is frozen here with its spell/talent
|
||||
-- recipe so `C BUILD IMPORT <code>` still materializes that exact loadout.
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_build_share_archive` (
|
||||
`share_code` CHAR(6) NOT NULL COMMENT 'retired code (same charset as live builds)',
|
||||
`name` VARCHAR(32) NOT NULL,
|
||||
`icon` VARCHAR(64) NOT NULL DEFAULT 'INV_Misc_QuestionMark',
|
||||
`archived_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`share_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: frozen build metadata for retired share codes';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_build_share_archive_spells` (
|
||||
`share_code` CHAR(6) NOT NULL,
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`share_code`, `spell_id`),
|
||||
KEY `idx_share` (`share_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: spell recipe rows for an archived share code';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `character_paragon_build_share_archive_talents` (
|
||||
`share_code` CHAR(6) NOT NULL,
|
||||
`spec` TINYINT UNSIGNED NOT NULL,
|
||||
`talent_id` SMALLINT UNSIGNED NOT NULL,
|
||||
`rank` TINYINT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`share_code`, `spec`, `talent_id`),
|
||||
KEY `idx_share` (`share_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: talent recipe rows for an archived share code';
|
||||
@@ -0,0 +1,482 @@
|
||||
-- Per-spell AE costs for Paragon spell purchases (.paragon learn / panel Lock In).
|
||||
-- Auto-generated by tools/_gen_paragon_spell_ae_cost_sql.py.
|
||||
-- Apply to the *world* database (AzerothCore's SQL updater handles this on worldserver start).
|
||||
-- The flat 1-AE cost is a Phase 3 placeholder; tune individual rows here as the
|
||||
-- economy gets balanced (e.g., 5 AE for top-rank baseline like Cyclone).
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `paragon_spell_ae_cost` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`ae_cost` SMALLINT UNSIGNED NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='mod-paragon: AE cost per spell';
|
||||
|
||||
-- Bulk-load: replace the entire table with the current bake. Manual edits
|
||||
-- to specific rows will be lost when this script regenerates the file --
|
||||
-- track per-spell tuning in a separate INSERT ... ON DUPLICATE KEY UPDATE
|
||||
-- file (e.g. paragon_spell_ae_cost_overrides.sql) if needed.
|
||||
DELETE FROM `paragon_spell_ae_cost`;
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(10, 1),
|
||||
(17, 1),
|
||||
(53, 1),
|
||||
(66, 1),
|
||||
(72, 1),
|
||||
(75, 1),
|
||||
(78, 1),
|
||||
(99, 1),
|
||||
(100, 1),
|
||||
(116, 1),
|
||||
(118, 1),
|
||||
(120, 1),
|
||||
(122, 1),
|
||||
(126, 1),
|
||||
(130, 1),
|
||||
(131, 1),
|
||||
(132, 1),
|
||||
(133, 1),
|
||||
(136, 1),
|
||||
(139, 1),
|
||||
(168, 1),
|
||||
(172, 1),
|
||||
(324, 1),
|
||||
(331, 1),
|
||||
(339, 1),
|
||||
(348, 1),
|
||||
(370, 1),
|
||||
(403, 1),
|
||||
(408, 1),
|
||||
(421, 1),
|
||||
(453, 1),
|
||||
(465, 1),
|
||||
(467, 1),
|
||||
(469, 1),
|
||||
(475, 1),
|
||||
(498, 1),
|
||||
(526, 1),
|
||||
(527, 1),
|
||||
(528, 1),
|
||||
(543, 1),
|
||||
(546, 1),
|
||||
(552, 1),
|
||||
(556, 1),
|
||||
(585, 1),
|
||||
(586, 1),
|
||||
(587, 1),
|
||||
(588, 1),
|
||||
(589, 1),
|
||||
(596, 1),
|
||||
(603, 1),
|
||||
(604, 1),
|
||||
(605, 1),
|
||||
(633, 1),
|
||||
(635, 1),
|
||||
(642, 1),
|
||||
(676, 1),
|
||||
(686, 1),
|
||||
(687, 1),
|
||||
(688, 1),
|
||||
(689, 1),
|
||||
(691, 1),
|
||||
(693, 1),
|
||||
(694, 1),
|
||||
(697, 1),
|
||||
(698, 1),
|
||||
(702, 1),
|
||||
(703, 1),
|
||||
(706, 1),
|
||||
(710, 1),
|
||||
(712, 1),
|
||||
(740, 1),
|
||||
(755, 1),
|
||||
(759, 1),
|
||||
(768, 1),
|
||||
(770, 1),
|
||||
(772, 1),
|
||||
(774, 1),
|
||||
(779, 1),
|
||||
(781, 1),
|
||||
(783, 1),
|
||||
(845, 1),
|
||||
(853, 1),
|
||||
(871, 1),
|
||||
(879, 1),
|
||||
(883, 1),
|
||||
(921, 1),
|
||||
(976, 1),
|
||||
(980, 1),
|
||||
(982, 1),
|
||||
(1002, 1),
|
||||
(1008, 1),
|
||||
(1022, 1),
|
||||
(1038, 1),
|
||||
(1044, 1),
|
||||
(1064, 1),
|
||||
(1066, 1),
|
||||
(1079, 1),
|
||||
(1082, 1),
|
||||
(1098, 1),
|
||||
(1120, 1),
|
||||
(1126, 1),
|
||||
(1130, 1),
|
||||
(1152, 1),
|
||||
(1160, 1),
|
||||
(1161, 1),
|
||||
(1243, 1),
|
||||
(1449, 1),
|
||||
(1454, 1),
|
||||
(1459, 1),
|
||||
(1462, 1),
|
||||
(1463, 1),
|
||||
(1464, 1),
|
||||
(1490, 1),
|
||||
(1494, 1),
|
||||
(1495, 1),
|
||||
(1499, 1),
|
||||
(1510, 1),
|
||||
(1513, 1),
|
||||
(1515, 1),
|
||||
(1535, 1),
|
||||
(1543, 1),
|
||||
(1680, 1),
|
||||
(1706, 1),
|
||||
(1714, 1),
|
||||
(1715, 1),
|
||||
(1719, 1),
|
||||
(1725, 1),
|
||||
(1752, 1),
|
||||
(1766, 1),
|
||||
(1776, 1),
|
||||
(1784, 1),
|
||||
(1822, 1),
|
||||
(1833, 1),
|
||||
(1842, 1),
|
||||
(1850, 1),
|
||||
(1856, 1),
|
||||
(1943, 1),
|
||||
(1949, 1),
|
||||
(1953, 1),
|
||||
(1966, 1),
|
||||
(1978, 1),
|
||||
(2006, 1),
|
||||
(2008, 1),
|
||||
(2050, 1),
|
||||
(2054, 1),
|
||||
(2060, 1),
|
||||
(2061, 1),
|
||||
(2062, 1),
|
||||
(2094, 1),
|
||||
(2096, 1),
|
||||
(2098, 1),
|
||||
(2120, 1),
|
||||
(2136, 1),
|
||||
(2139, 1),
|
||||
(2362, 1),
|
||||
(2457, 1),
|
||||
(2458, 1),
|
||||
(2484, 1),
|
||||
(2565, 1),
|
||||
(2637, 1),
|
||||
(2641, 1),
|
||||
(2643, 1),
|
||||
(2645, 1),
|
||||
(2687, 1),
|
||||
(2782, 1),
|
||||
(2812, 1),
|
||||
(2825, 1),
|
||||
(2893, 1),
|
||||
(2894, 1),
|
||||
(2908, 1),
|
||||
(2912, 1),
|
||||
(2944, 1),
|
||||
(2948, 1),
|
||||
(2973, 1),
|
||||
(2974, 1),
|
||||
(2983, 1),
|
||||
(3034, 1),
|
||||
(3043, 1),
|
||||
(3044, 1),
|
||||
(3045, 1),
|
||||
(3411, 1),
|
||||
(3561, 1),
|
||||
(3562, 1),
|
||||
(3563, 1),
|
||||
(3565, 1),
|
||||
(3566, 1),
|
||||
(3567, 1),
|
||||
(3714, 1),
|
||||
(3738, 1),
|
||||
(4987, 1),
|
||||
(5116, 1),
|
||||
(5118, 1),
|
||||
(5138, 1),
|
||||
(5143, 1),
|
||||
(5171, 1),
|
||||
(5176, 1),
|
||||
(5185, 1),
|
||||
(5209, 1),
|
||||
(5211, 1),
|
||||
(5215, 1);
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(5217, 1),
|
||||
(5221, 1),
|
||||
(5225, 1),
|
||||
(5229, 1),
|
||||
(5246, 1),
|
||||
(5277, 1),
|
||||
(5308, 1),
|
||||
(5384, 1),
|
||||
(5484, 1),
|
||||
(5487, 1),
|
||||
(5500, 1),
|
||||
(5502, 1),
|
||||
(5504, 1),
|
||||
(5675, 1),
|
||||
(5676, 1),
|
||||
(5697, 1),
|
||||
(5730, 1),
|
||||
(5740, 1),
|
||||
(5782, 1),
|
||||
(5938, 1),
|
||||
(6117, 1),
|
||||
(6143, 1),
|
||||
(6196, 1),
|
||||
(6197, 1),
|
||||
(6201, 1),
|
||||
(6229, 1),
|
||||
(6343, 1),
|
||||
(6346, 1),
|
||||
(6353, 1),
|
||||
(6366, 1),
|
||||
(6495, 1),
|
||||
(6552, 1),
|
||||
(6572, 1),
|
||||
(6673, 1),
|
||||
(6770, 1),
|
||||
(6785, 1),
|
||||
(6789, 1),
|
||||
(6795, 1),
|
||||
(6807, 1),
|
||||
(6940, 1),
|
||||
(7294, 1),
|
||||
(7302, 1),
|
||||
(7384, 1),
|
||||
(8004, 1),
|
||||
(8017, 1),
|
||||
(8024, 1),
|
||||
(8033, 1),
|
||||
(8042, 1),
|
||||
(8050, 1),
|
||||
(8056, 1),
|
||||
(8075, 1),
|
||||
(8092, 1),
|
||||
(8122, 1),
|
||||
(8129, 1),
|
||||
(8143, 1),
|
||||
(8170, 1),
|
||||
(8177, 1),
|
||||
(8181, 1),
|
||||
(8184, 1),
|
||||
(8190, 1),
|
||||
(8227, 1),
|
||||
(8232, 1),
|
||||
(8512, 1),
|
||||
(8647, 1),
|
||||
(8676, 1),
|
||||
(8921, 1),
|
||||
(8936, 1),
|
||||
(8998, 1),
|
||||
(9005, 1),
|
||||
(9484, 1),
|
||||
(10059, 1),
|
||||
(10326, 1),
|
||||
(10595, 1),
|
||||
(11416, 1),
|
||||
(11417, 1),
|
||||
(11418, 1),
|
||||
(11419, 1),
|
||||
(11420, 1),
|
||||
(12051, 1),
|
||||
(13159, 1),
|
||||
(13161, 1),
|
||||
(13163, 1),
|
||||
(13165, 1),
|
||||
(13795, 1),
|
||||
(13809, 1),
|
||||
(13813, 1),
|
||||
(14752, 1),
|
||||
(14914, 1),
|
||||
(15237, 1),
|
||||
(16689, 1),
|
||||
(16857, 1),
|
||||
(16914, 1),
|
||||
(18499, 1),
|
||||
(19263, 1),
|
||||
(19740, 1),
|
||||
(19742, 1),
|
||||
(19746, 1),
|
||||
(19750, 1),
|
||||
(19752, 1),
|
||||
(19801, 1),
|
||||
(19876, 1),
|
||||
(19878, 1),
|
||||
(19879, 1),
|
||||
(19880, 1),
|
||||
(19882, 1),
|
||||
(19883, 1),
|
||||
(19884, 1),
|
||||
(19885, 1),
|
||||
(19888, 1),
|
||||
(19891, 1),
|
||||
(20043, 1),
|
||||
(20154, 1),
|
||||
(20164, 1),
|
||||
(20165, 1),
|
||||
(20166, 1),
|
||||
(20217, 1),
|
||||
(20230, 1),
|
||||
(20252, 1),
|
||||
(20484, 1),
|
||||
(20736, 1),
|
||||
(21562, 1),
|
||||
(21849, 1),
|
||||
(22568, 1),
|
||||
(22570, 1),
|
||||
(22812, 1),
|
||||
(22842, 1),
|
||||
(23028, 1),
|
||||
(23161, 1),
|
||||
(23214, 1),
|
||||
(23920, 1),
|
||||
(23922, 1),
|
||||
(24275, 1),
|
||||
(25780, 1),
|
||||
(25782, 1),
|
||||
(25894, 1),
|
||||
(25898, 1),
|
||||
(25899, 1),
|
||||
(26573, 1),
|
||||
(26679, 1),
|
||||
(27243, 1),
|
||||
(27681, 1),
|
||||
(27683, 1),
|
||||
(28176, 1),
|
||||
(29166, 1),
|
||||
(29722, 1),
|
||||
(29858, 1),
|
||||
(29893, 1),
|
||||
(30449, 1),
|
||||
(30451, 1),
|
||||
(30455, 1),
|
||||
(30482, 1),
|
||||
(31224, 1),
|
||||
(31789, 1),
|
||||
(31801, 1),
|
||||
(31884, 1),
|
||||
(32182, 1),
|
||||
(32223, 1),
|
||||
(32266, 1),
|
||||
(32267, 1),
|
||||
(32271, 1),
|
||||
(32272, 1),
|
||||
(32375, 1),
|
||||
(32379, 1),
|
||||
(32546, 1),
|
||||
(32645, 1),
|
||||
(33076, 1),
|
||||
(33690, 1),
|
||||
(33691, 1),
|
||||
(33745, 1),
|
||||
(33763, 1),
|
||||
(33786, 1),
|
||||
(33943, 1),
|
||||
(34026, 1),
|
||||
(34074, 1),
|
||||
(34428, 1),
|
||||
(34433, 1),
|
||||
(34477, 1),
|
||||
(34600, 1),
|
||||
(34767, 1),
|
||||
(35715, 1),
|
||||
(35717, 1),
|
||||
(36936, 1),
|
||||
(42650, 1),
|
||||
(42955, 1),
|
||||
(43265, 1),
|
||||
(43987, 1),
|
||||
(44614, 1),
|
||||
(45438, 1),
|
||||
(45462, 1),
|
||||
(45477, 1),
|
||||
(45524, 1),
|
||||
(45529, 1),
|
||||
(45902, 1),
|
||||
(46584, 1),
|
||||
(47476, 1),
|
||||
(47528, 1),
|
||||
(47541, 1),
|
||||
(47568, 1),
|
||||
(47897, 1),
|
||||
(48018, 1);
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(48020, 1),
|
||||
(48045, 1),
|
||||
(48263, 1),
|
||||
(48265, 1),
|
||||
(48266, 1),
|
||||
(48707, 1),
|
||||
(48721, 1),
|
||||
(48743, 1),
|
||||
(48792, 1),
|
||||
(49020, 1),
|
||||
(49358, 1),
|
||||
(49359, 1),
|
||||
(49360, 1),
|
||||
(49361, 1),
|
||||
(49576, 1),
|
||||
(49998, 1),
|
||||
(50464, 1),
|
||||
(50769, 1),
|
||||
(50842, 1),
|
||||
(51505, 1),
|
||||
(51514, 1),
|
||||
(51722, 1),
|
||||
(51723, 1),
|
||||
(51730, 1),
|
||||
(52127, 1),
|
||||
(52610, 1),
|
||||
(53140, 1),
|
||||
(53142, 1),
|
||||
(53271, 1),
|
||||
(53351, 1),
|
||||
(53407, 1),
|
||||
(53408, 1),
|
||||
(53600, 1),
|
||||
(53601, 1),
|
||||
(53736, 1),
|
||||
(54428, 1),
|
||||
(55342, 1),
|
||||
(55694, 1),
|
||||
(56222, 1),
|
||||
(56641, 1),
|
||||
(56815, 1),
|
||||
(57330, 1),
|
||||
(57755, 1),
|
||||
(57934, 1),
|
||||
(57994, 1),
|
||||
(60192, 1),
|
||||
(61846, 1),
|
||||
(61999, 1),
|
||||
(62078, 1),
|
||||
(62124, 1),
|
||||
(62757, 1),
|
||||
(64382, 1),
|
||||
(64843, 1),
|
||||
(64901, 1),
|
||||
(66842, 1),
|
||||
(66843, 1),
|
||||
(66844, 1);
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
-- mod-paragon: server-side DBC overlay for class 12 (Paragon).
|
||||
-- Auto-generated by fractured-tooling/from-workspace-root/
|
||||
-- _gen_paragon_dbc_overlay_sql.py
|
||||
--
|
||||
-- AzerothCore's DBCStores.cpp::LoadDBC merges every <table>_dbc
|
||||
-- world-DB row on top of the on-disk DBC store at startup
|
||||
-- (storage.LoadFromDB). We use that to ship Paragon's class-12
|
||||
-- DBC deltas in SQL form so a stock data/dbc/ tree (e.g. the
|
||||
-- vanilla `ac-wotlk-client-data` Docker image) still resolves
|
||||
-- class 12 in sChrClassesStore and class-12 entries in
|
||||
-- sSkillRaceClassInfoStore.
|
||||
--
|
||||
-- Without this migration, fresh installs hit:
|
||||
-- CHAR_CREATE_FAILED -- "Class (12) not found in DBC ..."
|
||||
-- the moment a contributor tries to roll a Paragon character.
|
||||
--
|
||||
-- This file is regenerated end-to-end from patch-enUS-4.MPQ;
|
||||
-- do not hand-edit. Update the patched DBC source and rerun
|
||||
-- the bake script.
|
||||
|
||||
-- chrclasses_dbc: classes added or modified by patch-enUS-4.MPQ.
|
||||
-- AzerothCore merges this on top of the on-disk ChrClasses.dbc
|
||||
-- so a stock data/dbc tree still gets class 12 at runtime.
|
||||
DELETE FROM `chrclasses_dbc` WHERE `ID` IN (12);
|
||||
INSERT INTO `chrclasses_dbc` (`ID`,`Field01`,`DisplayPower`,`PetNameToken`,`Name_Lang_enUS`,`Name_Lang_Mask`,`Name_Female_Lang_Mask`,`Name_Male_Lang_Mask`,`Filename`,`SpellClassSet`,`Flags`,`CinematicSequenceID`,`Required_Expansion`) VALUES
|
||||
(12, 0, 0, 0, 'Paragon', 0, 0, 0, 'PARAGON', 4, 50, 0, 2);
|
||||
|
||||
-- skillraceclassinfo_dbc: rows where patch-enUS-4 OR'd the
|
||||
-- class-12 bit (0x800) into ClassMask, opening every
|
||||
-- baseline skill to Paragon. Replaces the stock row by ID so
|
||||
-- AzerothCore picks the patched mask on the SQL merge pass.
|
||||
DELETE FROM `skillraceclassinfo_dbc` WHERE `ID` IN (
|
||||
57,301,107,82,75,140,328,638,872,880,881,885,886,910,117,335,628,629,630,912,126,127,133,134,635,31,39,135,325,636,637,643,644,888,889,914,125,626,884,898,901,58,60,916,59,40,41,68,48,49,44,45,42,43,50,51,131,132,883,913,105,71,70,69,925,54,25,138,139,91,882,85,84,93,88,865,87,441,94,443,92,481,89,442,123,124,624,625,702,908,6,922,33,243,899,241,122,621,622,701,907,970,129,323,631,632,633,634,641,642,142,143,639,640,28,63,282,29,284,65,97,244,940,72,128,878,879,137,144,136,915,55,79,81,76,149,112,111,106,66,26,83,74,73,108,109,110,113,38,35,36,37,61,62,64,24,34,21,906,46,47,52,53,281,104,102,101,27,95,98,96,30,145,146,147,148,151,155,158,159,271,175,178,183,186,270,189,191,193,198,200,265,266,203,204,205,268,269,246,272,330,381,403,445,446,461,501,463,464,521,522,541,544,581,601,741,742,781,841,861,862,866,867,877,934,892,896,897,951,895,900,936,938,939,947
|
||||
);
|
||||
INSERT INTO `skillraceclassinfo_dbc` (`ID`,`SkillID`,`RaceMask`,`ClassMask`,`Flags`,`MinLevel`,`SkillTierID`,`SkillCostIndex`) VALUES
|
||||
(57,6,-1,2176,1040,0,0,0),
|
||||
(301,8,-1,2176,1040,0,0,0),
|
||||
(107,26,-1,2049,1040,0,0,0),
|
||||
(82,38,-1,2056,1040,0,0,0),
|
||||
(75,39,-1,2056,1040,0,0,0),
|
||||
(140,43,1115,2049,128,0,0,0),
|
||||
(328,43,3071,2052,128,0,0,0),
|
||||
(638,43,164,2049,128,0,0,0),
|
||||
(872,43,32767,2056,128,0,0,0),
|
||||
(880,43,1024,2052,128,0,0,0),
|
||||
(881,43,32767,2432,128,0,0,0),
|
||||
(885,43,1029,2050,128,0,0,0),
|
||||
(886,43,512,2050,128,0,0,0),
|
||||
(910,43,262143,2080,128,0,0,0),
|
||||
(117,44,166,2052,128,0,0,0),
|
||||
(335,44,2147483647,2122,128,0,0,0),
|
||||
(628,44,1544,2052,128,0,0,0),
|
||||
(629,44,167,2049,128,0,0,0),
|
||||
(630,44,1112,2049,128,0,0,0),
|
||||
(912,44,262143,2080,128,0,0,0),
|
||||
(126,45,650,2052,128,0,0,0),
|
||||
(127,45,32767,2061,128,0,0,0),
|
||||
(133,46,36,2052,128,0,0,0),
|
||||
(134,46,32767,2057,128,0,0,0),
|
||||
(635,46,1674,2052,128,0,0,0),
|
||||
(31,50,-1,2052,1040,0,0,0),
|
||||
(39,51,-1,2052,1040,0,0,0),
|
||||
(135,54,2147483647,2128,128,0,0,0),
|
||||
(325,54,-1,2056,128,0,0,0),
|
||||
(636,54,1133,2049,128,0,0,0),
|
||||
(637,54,658,2049,128,0,0,0),
|
||||
(643,54,8,3072,128,0,0,0),
|
||||
(644,54,32,3072,128,0,0,0),
|
||||
(888,54,261631,2050,128,0,0,0),
|
||||
(889,54,512,2050,128,0,0,0),
|
||||
(914,54,262143,2080,128,0,0,0),
|
||||
(125,55,262143,2052,128,0,0,0),
|
||||
(626,55,163839,2049,128,0,0,0),
|
||||
(884,55,512,2050,128,0,0,0),
|
||||
(898,55,262143,2080,128,0,0,0),
|
||||
(901,55,261631,2050,128,0,0,0),
|
||||
(58,56,-1,2064,1040,0,0,0),
|
||||
(60,78,-1,2064,1040,0,0,0),
|
||||
(916,95,524287,2080,640,0,0,0),
|
||||
(59,96,2047,3072,1168,0,0,0),
|
||||
(40,98,1101,3583,128,0,0,0),
|
||||
(41,98,674,3551,160,0,21,0),
|
||||
(68,101,4,3583,1170,0,0,0),
|
||||
(48,109,690,3583,128,0,0,0),
|
||||
(49,109,1101,3551,160,0,21,0),
|
||||
(44,111,4,3583,128,0,0,0),
|
||||
(45,111,2043,3551,160,0,21,0),
|
||||
(42,113,8,3583,128,0,0,0),
|
||||
(43,113,2039,3551,160,0,21,0),
|
||||
(50,115,32,3583,128,0,0,0),
|
||||
(51,115,2015,3551,160,0,21,0),
|
||||
(131,118,32767,2056,146,1,0,0),
|
||||
(132,118,32767,2053,146,20,0,0),
|
||||
(883,118,32767,2112,402,0,0,0),
|
||||
(913,118,262143,2080,146,0,0,0),
|
||||
(105,120,2047,2304,1170,0,0,0),
|
||||
(71,124,32,3583,1170,0,0,0),
|
||||
(70,125,2,3583,146,0,0,0),
|
||||
(69,126,8,3583,1170,0,0,0),
|
||||
(925,129,-1,2080,128,0,63,0),
|
||||
(54,130,2047,2176,1168,4,0,0),
|
||||
(25,134,-1,3072,1040,10,0,0),
|
||||
(138,136,32767,3536,128,0,0,0),
|
||||
(139,136,32767,2053,128,0,0,0),
|
||||
(91,137,1535,3551,160,0,21,0),
|
||||
(882,137,512,3583,128,0,0,0),
|
||||
(85,138,2047,3583,128,0,0,0),
|
||||
(84,139,2047,3583,160,0,21,0),
|
||||
(93,140,2047,3583,128,0,0,0),
|
||||
(88,141,2047,3583,160,0,21,0),
|
||||
(865,142,2047,3583,0,0,0,0),
|
||||
(87,148,1,3551,1170,0,181,0),
|
||||
(441,148,222,3583,1170,0,182,0),
|
||||
(94,149,2,3551,1170,0,181,0),
|
||||
(443,149,509,3583,1170,0,182,0),
|
||||
(92,150,8,3551,1170,0,181,0),
|
||||
(481,150,215,3583,1170,0,182,0),
|
||||
(89,152,4,3551,1170,0,181,0),
|
||||
(442,152,219,3583,1170,0,182,0),
|
||||
(123,160,262143,2050,128,0,0,0),
|
||||
(124,160,-1,3072,128,0,0,0),
|
||||
(624,160,32,2049,128,0,0,0),
|
||||
(625,160,262111,2049,128,0,0,0),
|
||||
(702,160,-1,2112,128,0,0,0),
|
||||
(908,160,262143,2080,128,0,0,0),
|
||||
(6,162,2147483647,3551,128,0,0,0),
|
||||
(922,162,262143,2080,128,0,0,0),
|
||||
(33,163,-1,2052,1040,0,0,0),
|
||||
(243,164,2047,3583,160,0,41,0),
|
||||
(899,165,2047,3583,160,0,41,0),
|
||||
(241,171,2047,3583,160,0,41,0),
|
||||
(122,172,163839,2050,128,0,0,0),
|
||||
(621,172,6,2049,128,0,0,0),
|
||||
(622,172,1529,2049,128,0,0,0),
|
||||
(701,172,163839,2112,128,0,0,0),
|
||||
(907,172,524287,2080,128,0,0,0),
|
||||
(970,172,163839,2052,128,0,0,0),
|
||||
(129,173,32767,2312,128,0,0,0),
|
||||
(323,173,32767,2256,128,0,0,0),
|
||||
(631,173,520,2052,128,0,0,0),
|
||||
(632,173,1190,2052,128,0,0,0),
|
||||
(633,173,216,2049,128,0,0,0),
|
||||
(634,173,1063,2049,128,0,0,0),
|
||||
(641,173,32,3072,128,0,0,0),
|
||||
(642,173,8,3072,128,0,0,0),
|
||||
(142,176,-1,2056,128,0,0,0),
|
||||
(143,176,-1,2052,128,0,0,0),
|
||||
(639,176,128,2049,128,0,0,0),
|
||||
(640,176,262015,2049,128,0,0,0),
|
||||
(28,182,2047,3583,160,0,2,0),
|
||||
(63,184,-1,2050,1040,0,0,0),
|
||||
(282,185,2047,3583,128,0,61,0),
|
||||
(29,186,2047,3583,160,0,2,0),
|
||||
(284,197,2047,3583,160,0,62,0),
|
||||
(65,198,2047,2050,1168,0,0,0),
|
||||
(97,199,2047,2112,1168,0,0,0),
|
||||
(244,202,2047,3583,160,0,41,0),
|
||||
(940,205,524287,2176,2048,0,0,0),
|
||||
(72,220,16,3583,1170,0,0,0),
|
||||
(128,226,32767,2057,128,0,0,0),
|
||||
(878,226,1024,2052,128,0,0,0),
|
||||
(879,226,31743,2052,128,0,0,0),
|
||||
(137,227,2047,3077,128,0,0,0),
|
||||
(144,228,-1,2448,128,0,0,0),
|
||||
(136,229,32767,3079,128,20,0,0),
|
||||
(915,229,262143,2080,128,0,0,0),
|
||||
(55,237,-1,2176,1040,0,0,0),
|
||||
(79,238,2047,2056,1168,4,0,0),
|
||||
(81,239,2047,2056,1168,0,0,0),
|
||||
(76,241,2047,2056,128,40,0,0),
|
||||
(149,242,2047,2056,1168,16,0,0),
|
||||
(112,243,2047,2049,1170,0,0,0),
|
||||
(111,244,2047,2049,1168,0,0,0),
|
||||
(106,245,2047,2049,1168,0,0,0),
|
||||
(66,246,2047,2050,1168,0,0,0),
|
||||
(26,247,2047,3072,1168,20,0,0),
|
||||
(83,252,2047,2057,128,0,0,0),
|
||||
(74,253,-1,2056,1040,0,0,0),
|
||||
(73,254,2047,2056,1168,10,0,0),
|
||||
(108,255,2047,2049,1168,0,0,0),
|
||||
(109,256,-1,2049,1040,0,0,0),
|
||||
(110,257,-1,2049,1040,0,0,0),
|
||||
(113,258,2047,2049,1168,10,0,0),
|
||||
(38,260,2047,2052,128,0,0,0),
|
||||
(35,262,2047,2052,128,0,0,0),
|
||||
(36,263,2047,2052,128,0,0,0),
|
||||
(37,264,2047,2052,128,0,0,0),
|
||||
(61,267,-1,2050,1040,0,0,0),
|
||||
(62,268,2047,2050,1170,0,0,0),
|
||||
(64,269,2047,2050,1168,0,0,0),
|
||||
(24,272,2047,3072,1168,10,0,0),
|
||||
(34,273,2047,2052,128,0,0,0),
|
||||
(21,293,2047,2051,128,40,0,0),
|
||||
(906,293,262143,2080,128,0,0,0),
|
||||
(46,313,64,3583,128,0,0,0),
|
||||
(47,313,1983,3551,160,0,21,0),
|
||||
(52,315,128,3583,128,0,0,0),
|
||||
(53,315,1919,3551,160,0,21,0),
|
||||
(281,333,2047,3583,160,0,62,0),
|
||||
(104,353,2047,2304,1170,0,0,0),
|
||||
(102,354,-1,2304,1040,0,0,0),
|
||||
(101,355,-1,2304,1040,0,0,0),
|
||||
(27,356,2047,3583,128,0,23,0),
|
||||
(95,373,-1,2112,1040,0,0,0),
|
||||
(98,374,262143,2112,1040,0,0,0),
|
||||
(96,375,262143,2112,1040,0,0,0),
|
||||
(30,393,2047,3583,160,0,161,0),
|
||||
(145,413,2047,2116,128,40,0,0),
|
||||
(146,413,2047,2083,128,0,0,0),
|
||||
(147,414,2047,3183,128,0,0,0),
|
||||
(148,415,2047,3583,128,0,0,0),
|
||||
(151,416,2047,2049,192,0,0,0),
|
||||
(155,416,2047,2050,192,0,0,1),
|
||||
(158,416,2047,3136,192,0,0,1),
|
||||
(159,416,2047,2060,192,0,0,1),
|
||||
(271,416,2047,2448,192,0,0,2),
|
||||
(175,418,2047,2049,384,0,0,0),
|
||||
(178,418,2047,2050,384,0,0,0),
|
||||
(183,418,2047,3332,384,0,0,1),
|
||||
(186,418,2047,2192,384,0,0,1),
|
||||
(270,418,2047,2120,384,0,0,1),
|
||||
(189,419,2047,2060,640,0,0,2),
|
||||
(191,419,2047,3072,640,0,0,1),
|
||||
(193,419,2047,2192,640,0,0,0),
|
||||
(198,419,2047,2050,640,0,0,1),
|
||||
(200,419,2047,2049,640,0,0,2),
|
||||
(265,419,2047,2304,640,0,0,0),
|
||||
(266,419,2047,2112,640,0,0,1),
|
||||
(203,420,2047,2061,1152,0,0,2),
|
||||
(204,420,2047,3074,1152,0,0,1),
|
||||
(205,420,2047,2320,1152,0,0,0),
|
||||
(268,420,2047,2176,1152,0,0,0),
|
||||
(269,420,2047,2112,1152,0,0,1),
|
||||
(246,433,2047,2115,128,0,0,0),
|
||||
(272,453,2047,2051,128,0,0,0),
|
||||
(330,473,4095,3149,130,0,0,0),
|
||||
(381,493,8,3583,164,0,0,0),
|
||||
(403,515,2047,3551,128,0,0,0),
|
||||
(445,533,128,3583,1170,0,181,0),
|
||||
(446,533,95,3551,1170,0,182,0),
|
||||
(461,553,64,3551,1170,0,181,0),
|
||||
(501,553,4,3583,1170,0,182,0),
|
||||
(463,554,16,3551,1170,0,181,0),
|
||||
(464,554,207,3583,1170,0,182,0),
|
||||
(521,573,-1,3072,1040,0,0,0),
|
||||
(522,574,-1,3072,1040,0,0,0),
|
||||
(541,593,-1,2304,1040,0,0,0),
|
||||
(544,594,-1,2050,1040,0,0,0),
|
||||
(581,613,-1,2064,1040,0,0,0),
|
||||
(601,633,-1,2056,128,0,0,0),
|
||||
(741,673,16,3583,128,0,0,0),
|
||||
(742,673,2031,3551,160,0,21,0),
|
||||
(781,713,255,3583,1170,0,181,0),
|
||||
(841,733,128,3583,1170,0,0,0),
|
||||
(861,753,64,3583,1170,0,0,0),
|
||||
(862,754,1,3583,1170,0,0,0),
|
||||
(866,755,2047,3583,160,0,41,0),
|
||||
(867,756,512,3583,146,0,0,0),
|
||||
(877,760,1024,3583,146,0,0,0),
|
||||
(934,762,524287,2080,144,0,223,0),
|
||||
(892,769,32767,3583,1040,0,0,0),
|
||||
(896,770,-1,2080,1040,0,0,0),
|
||||
(897,771,262143,2080,1040,0,0,0),
|
||||
(951,771,2097151,3583,0,0,0,0),
|
||||
(895,772,-1,2080,1040,0,0,0),
|
||||
(900,773,262143,3583,160,0,41,0),
|
||||
(936,776,262143,2080,128,0,0,0),
|
||||
(938,777,524287,3583,2,0,0,0),
|
||||
(939,778,524287,3583,2,0,0,0),
|
||||
(947,778,2097151,3583,0,0,0,0);
|
||||
@@ -0,0 +1,179 @@
|
||||
-- mod-paragon: starter spawn data for class 12 (Paragon).
|
||||
--
|
||||
-- Companion to 2026_05_09_00.sql. The DBC overlay teaches the world
|
||||
-- server that class 12 exists; this migration teaches it WHERE
|
||||
-- characters of that class spawn, what action bar they boot with,
|
||||
-- and what per-level base stats to integrity-check against.
|
||||
--
|
||||
-- Without these rows, character creation fails inside Player::Create:
|
||||
--
|
||||
-- PlayerInfo const* info = sObjectMgr->GetPlayerInfo(race, class);
|
||||
-- if (!info) {
|
||||
-- LOG_ERROR("entities.player",
|
||||
-- "Player::Create: ... invalid race/class pair ({}/{})"
|
||||
-- " - refusing to do so.", ..., race, class);
|
||||
-- return false; // -> client sees "Error creating character"
|
||||
-- }
|
||||
--
|
||||
-- and on world load the player_class_stats integrity check trips:
|
||||
--
|
||||
-- "Class N Level L does not have stats data!"
|
||||
--
|
||||
-- Tables touched:
|
||||
-- - playercreateinfo : (race, class=12) -> map/zone/x/y/z
|
||||
-- Race-specific starting zones (Paragon
|
||||
-- spawns in each race's standard newbie
|
||||
-- area, NOT Acherus, since it is a
|
||||
-- from-level-1 class).
|
||||
-- - playercreateinfo_action : (race, class=12, button) -> action,type
|
||||
-- Default action bar layout per race.
|
||||
-- - player_class_stats : (class=12, level 1..80) -> base stats
|
||||
-- Per-level HP/Mana/STR/AGI/STA/INT/SPI
|
||||
-- used by Player::InitStatsForLevel.
|
||||
--
|
||||
-- Tables intentionally NOT touched here:
|
||||
-- - playercreateinfo_item : Paragon ships no per-class starting
|
||||
-- items; gear comes from the racial
|
||||
-- kit only.
|
||||
-- - playercreateinfo_skills / _cast_spell / _spell_custom :
|
||||
-- These are mask-based. Class-12 baseline
|
||||
-- weapon/defense skills come through
|
||||
-- classMask=0 ("all classes") rows that
|
||||
-- already cover Paragon. The DBC overlay
|
||||
-- in 2026_05_09_00.sql opens
|
||||
-- SkillRaceClassInfo for class 12.
|
||||
|
||||
-- Idempotent: blow away any pre-existing class-12 rows first so this
|
||||
-- migration can be replayed cleanly on a partially-seeded DB (e.g.
|
||||
-- after a contributor manually patched their local DB before this
|
||||
-- migration landed).
|
||||
DELETE FROM `playercreateinfo` WHERE `class` = 12;
|
||||
DELETE FROM `playercreateinfo_action` WHERE `class` = 12;
|
||||
DELETE FROM `player_class_stats` WHERE `Class` = 12;
|
||||
|
||||
-- ---------------------------------------------------------------
|
||||
-- playercreateinfo (10 rows: every DK-eligible race, racial start)
|
||||
-- ---------------------------------------------------------------
|
||||
INSERT INTO `playercreateinfo` (`race`, `class`, `map`, `zone`, `position_x`, `position_y`, `position_z`, `orientation`) VALUES
|
||||
( 1, 12, 0, 12, -8949.95, -132.493, 83.5312, 0 ), -- Human -> Northshire, Elwynn Forest
|
||||
( 2, 12, 1, 14, -618.518, -4251.67, 38.718, 0 ), -- Orc -> Valley of Trials, Durotar
|
||||
( 3, 12, 0, 1, -6240.32, 331.033, 382.758, 6.17716 ), -- Dwarf -> Coldridge Valley, Dun Morogh
|
||||
( 4, 12, 1, 141, 10311.3, 832.463, 1326.41, 5.69632 ), -- Night Elf -> Shadowglen, Teldrassil
|
||||
( 5, 12, 0, 85, 1676.71, 1678.31, 121.67, 2.70526 ), -- Undead -> Deathknell, Tirisfal
|
||||
( 6, 12, 1, 215, -2917.58, -257.98, 52.9968, 0 ), -- Tauren -> Camp Narache, Mulgore
|
||||
( 7, 12, 0, 1, -6240.32, 331.033, 382.758, 0 ), -- Gnome -> Coldridge Valley (shared)
|
||||
( 8, 12, 1, 14, -618.518, -4251.67, 38.718, 0 ), -- Troll -> Valley of Trials (shared)
|
||||
(10, 12, 530, 3431, 10349.6, -6357.29, 33.4026, 5.31605 ), -- Blood Elf -> Sunstrider Isle, Eversong
|
||||
(11, 12, 530, 3526, -3961.64,-13931.2, 100.615, 2.08364 ); -- Draenei -> Ammen Vale, Azuremyst Isle
|
||||
|
||||
-- ---------------------------------------------------------------
|
||||
-- playercreateinfo_action (46 rows)
|
||||
-- Buttons: 72=Attack(6603), 73=Eat(78), 74=racial, 75=race-extra,
|
||||
-- 82=Skinning(59752, Tauren only), 84=Attack, 96=Attack
|
||||
-- ---------------------------------------------------------------
|
||||
INSERT INTO `playercreateinfo_action` (`race`, `class`, `button`, `action`, `type`) VALUES
|
||||
( 1, 12, 72, 6603, 0), ( 1, 12, 73, 78, 0), ( 1, 12, 82, 59752, 0),
|
||||
( 1, 12, 84, 6603, 0), ( 1, 12, 96, 6603, 0),
|
||||
( 2, 12, 72, 6603, 0), ( 2, 12, 73, 78, 0), ( 2, 12, 74, 20572, 0),
|
||||
( 2, 12, 84, 6603, 0), ( 2, 12, 96, 6603, 0),
|
||||
( 3, 12, 72, 6603, 0), ( 3, 12, 73, 78, 0), ( 3, 12, 74, 20594, 0),
|
||||
( 3, 12, 75, 2481, 0), ( 3, 12, 84, 6603, 0), ( 3, 12, 96, 6603, 0),
|
||||
( 4, 12, 72, 6603, 0), ( 4, 12, 73, 78, 0), ( 4, 12, 74, 58984, 0),
|
||||
( 4, 12, 84, 6603, 0), ( 4, 12, 96, 6603, 0),
|
||||
( 5, 12, 72, 6603, 0), ( 5, 12, 73, 78, 0), ( 5, 12, 74, 20577, 0),
|
||||
( 5, 12, 84, 6603, 0), ( 5, 12, 96, 6603, 0),
|
||||
( 6, 12, 72, 6603, 0), ( 6, 12, 73, 78, 0), ( 6, 12, 74, 20549, 0),
|
||||
( 6, 12, 84, 6603, 0), ( 6, 12, 96, 6603, 0),
|
||||
( 7, 12, 72, 6603, 0), ( 7, 12, 73, 78, 0), ( 7, 12, 84, 6603, 0),
|
||||
( 7, 12, 96, 6603, 0),
|
||||
( 8, 12, 72, 6603, 0), ( 8, 12, 73, 78, 0), ( 8, 12, 74, 2764, 0),
|
||||
( 8, 12, 75, 26297, 0), ( 8, 12, 84, 6603, 0), ( 8, 12, 96, 6603, 0),
|
||||
(11, 12, 72, 6603, 0), (11, 12, 73, 78, 0), (11, 12, 74, 28880, 0),
|
||||
(11, 12, 84, 6603, 0), (11, 12, 96, 6603, 0);
|
||||
|
||||
-- ---------------------------------------------------------------
|
||||
-- player_class_stats (80 rows: levels 1..80 per-class base stats)
|
||||
-- Curve mirrors Warrior baseline -> Paladin past 60 (vehicle-style HP
|
||||
-- inflation past 60 to keep Paragon competitive in Wrath content).
|
||||
-- ---------------------------------------------------------------
|
||||
INSERT INTO `player_class_stats` (`Class`, `Level`, `BaseHP`, `BaseMana`, `Strength`, `Agility`, `Stamina`, `Intellect`, `Spirit`) VALUES
|
||||
(12, 1, 20, 60, 23, 20, 22, 20, 20),
|
||||
(12, 2, 29, 66, 24, 21, 23, 20, 20),
|
||||
(12, 3, 38, 73, 25, 21, 24, 20, 21),
|
||||
(12, 4, 47, 81, 26, 22, 25, 20, 21),
|
||||
(12, 5, 56, 90, 28, 23, 26, 20, 21),
|
||||
(12, 6, 65, 100, 29, 24, 27, 21, 21),
|
||||
(12, 7, 74, 111, 30, 24, 28, 21, 22),
|
||||
(12, 8, 83, 123, 31, 25, 29, 21, 22),
|
||||
(12, 9, 92, 136, 32, 26, 30, 21, 22),
|
||||
(12, 10, 97, 150, 33, 26, 31, 21, 23),
|
||||
(12, 11, 103, 165, 35, 27, 33, 21, 23),
|
||||
(12, 12, 109, 182, 36, 28, 34, 21, 23),
|
||||
(12, 13, 118, 200, 37, 29, 35, 21, 24),
|
||||
(12, 14, 128, 219, 39, 30, 36, 22, 24),
|
||||
(12, 15, 139, 239, 40, 30, 37, 22, 24),
|
||||
(12, 16, 151, 260, 41, 31, 38, 22, 25),
|
||||
(12, 17, 154, 282, 42, 32, 40, 22, 25),
|
||||
(12, 18, 168, 305, 44, 33, 41, 22, 25),
|
||||
(12, 19, 183, 329, 45, 34, 42, 22, 26),
|
||||
(12, 20, 199, 354, 47, 35, 43, 22, 26),
|
||||
(12, 21, 206, 380, 48, 35, 45, 23, 26),
|
||||
(12, 22, 224, 392, 49, 36, 46, 23, 27),
|
||||
(12, 23, 243, 420, 51, 37, 47, 23, 27),
|
||||
(12, 24, 253, 449, 52, 38, 49, 23, 28),
|
||||
(12, 25, 274, 479, 54, 39, 50, 23, 28),
|
||||
(12, 26, 296, 509, 55, 40, 51, 23, 28),
|
||||
(12, 27, 309, 524, 57, 41, 53, 23, 29),
|
||||
(12, 28, 333, 554, 58, 42, 54, 24, 29),
|
||||
(12, 29, 348, 584, 60, 43, 56, 24, 30),
|
||||
(12, 30, 374, 614, 62, 44, 57, 24, 30),
|
||||
(12, 31, 401, 629, 63, 45, 58, 24, 30),
|
||||
(12, 32, 419, 659, 65, 46, 60, 24, 31),
|
||||
(12, 33, 448, 689, 66, 47, 61, 24, 31),
|
||||
(12, 34, 468, 704, 68, 48, 63, 25, 32),
|
||||
(12, 35, 499, 734, 70, 49, 64, 25, 32),
|
||||
(12, 36, 521, 749, 72, 50, 66, 25, 33),
|
||||
(12, 37, 545, 779, 73, 51, 68, 25, 33),
|
||||
(12, 38, 581, 809, 75, 52, 69, 25, 33),
|
||||
(12, 39, 609, 824, 77, 53, 71, 26, 34),
|
||||
(12, 40, 649, 854, 79, 54, 72, 26, 34),
|
||||
(12, 41, 681, 869, 80, 56, 74, 26, 35),
|
||||
(12, 42, 715, 899, 82, 57, 76, 26, 35),
|
||||
(12, 43, 761, 914, 84, 58, 77, 26, 36),
|
||||
(12, 44, 799, 944, 86, 59, 79, 26, 36),
|
||||
(12, 45, 839, 959, 88, 60, 81, 27, 37),
|
||||
(12, 46, 881, 989, 90, 61, 83, 27, 37),
|
||||
(12, 47, 935, 1004, 92, 63, 84, 27, 38),
|
||||
(12, 48, 981, 1019, 94, 64, 86, 27, 38),
|
||||
(12, 49, 1029, 1049, 96, 65, 88, 28, 39),
|
||||
(12, 50, 1079, 1064, 98, 66, 90, 28, 39),
|
||||
(12, 51, 1131, 1079, 100, 68, 92, 28, 40),
|
||||
(12, 52, 1185, 1109, 102, 69, 94, 28, 40),
|
||||
(12, 53, 1241, 1124, 104, 70, 96, 28, 41),
|
||||
(12, 54, 1299, 1139, 106, 72, 98, 29, 42),
|
||||
(12, 55, 1359, 1154, 109, 73, 100, 29, 42),
|
||||
(12, 56, 1421, 1169, 111, 74, 102, 29, 43),
|
||||
(12, 57, 1485, 1199, 113, 76, 104, 29, 43),
|
||||
(12, 58, 1551, 1214, 115, 77, 106, 30, 44),
|
||||
(12, 59, 1619, 1229, 118, 79, 108, 30, 44),
|
||||
(12, 60, 1689, 1244, 120, 80, 110, 30, 45),
|
||||
(12, 61, 1902, 1357, 122, 81, 112, 30, 46),
|
||||
(12, 62, 2129, 1469, 125, 83, 114, 30, 46),
|
||||
(12, 63, 2357, 1582, 127, 84, 117, 31, 47),
|
||||
(12, 64, 2612, 1694, 130, 86, 119, 31, 47),
|
||||
(12, 65, 2883, 1807, 132, 88, 121, 31, 48),
|
||||
(12, 66, 3169, 1919, 135, 89, 123, 32, 49),
|
||||
(12, 67, 3455, 2032, 137, 91, 126, 32, 49),
|
||||
(12, 68, 3774, 2145, 140, 92, 128, 32, 50),
|
||||
(12, 69, 4109, 2257, 142, 94, 130, 32, 51),
|
||||
(12, 70, 4444, 2370, 145, 96, 133, 33, 51),
|
||||
(12, 71, 4720, 2482, 148, 97, 135, 33, 52),
|
||||
(12, 72, 5013, 2595, 150, 99, 138, 33, 53),
|
||||
(12, 73, 5325, 2708, 153, 101, 140, 33, 54),
|
||||
(12, 74, 5656, 2820, 156, 102, 143, 34, 54),
|
||||
(12, 75, 6008, 2933, 159, 104, 145, 34, 55),
|
||||
(12, 76, 6381, 3045, 162, 106, 148, 34, 56),
|
||||
(12, 77, 6778, 3158, 165, 108, 151, 35, 57),
|
||||
(12, 78, 7198, 3270, 168, 109, 153, 35, 57),
|
||||
(12, 79, 7646, 3383, 171, 111, 156, 35, 58),
|
||||
(12, 80, 8121, 3496, 174, 113, 159, 36, 59);
|
||||
@@ -0,0 +1,50 @@
|
||||
-- mod-paragon: starter weapon / armor skills for class 12 (Paragon).
|
||||
--
|
||||
-- Companion to 2026_05_10_00.sql. The spawn-data migration teaches
|
||||
-- Player::Create *that* class 12 exists at a given race; this one
|
||||
-- teaches it which weapon and armor skill lines to grant on first
|
||||
-- character login.
|
||||
--
|
||||
-- Without these rows a fresh Paragon character lands in their newbie
|
||||
-- zone with **no** weapon or armor proficiencies (auto-attack greys
|
||||
-- out the moment they equip anything beyond a fist). The classMask=0
|
||||
-- "all classes" rows in playercreateinfo_skills only cover Defense,
|
||||
-- Unarmed, Cloth, the racial / language skills, Mounts and
|
||||
-- Companion Pets -- which is exactly what bare-fisted, naked
|
||||
-- characters look like.
|
||||
--
|
||||
-- Paragon plays every class, so it grants every weapon / armor
|
||||
-- proficiency at level 1. The skillline rows themselves are still
|
||||
-- gated by skillraceclassinfo_dbc (handled in 2026_05_09_00.sql),
|
||||
-- so the client/server agree on what's allowed.
|
||||
--
|
||||
-- Idempotent: deletes any pre-existing classMask=2048 rows first
|
||||
-- (class 12 owns this bitmask on Fractured) so the migration can
|
||||
-- replay cleanly on a partially-seeded DB.
|
||||
|
||||
DELETE FROM `playercreateinfo_skills` WHERE `classMask` = 2048;
|
||||
|
||||
INSERT INTO `playercreateinfo_skills`
|
||||
(`raceMask`, `classMask`, `skill`, `rank`, `comment`) VALUES
|
||||
-- Weapon proficiencies
|
||||
(0, 2048, 43, 0, 'Paragon - Swords'),
|
||||
(0, 2048, 44, 0, 'Paragon - Axes'),
|
||||
(0, 2048, 45, 0, 'Paragon - Bows'),
|
||||
(0, 2048, 46, 0, 'Paragon - Guns'),
|
||||
(0, 2048, 54, 0, 'Paragon - Maces'),
|
||||
(0, 2048, 55, 0, 'Paragon - Two-Handed Swords'),
|
||||
(0, 2048, 118, 0, 'Paragon - Dual Wield'),
|
||||
(0, 2048, 136, 0, 'Paragon - Staves'),
|
||||
(0, 2048, 160, 0, 'Paragon - Two-Handed Maces'),
|
||||
(0, 2048, 172, 0, 'Paragon - Two-Handed Axes'),
|
||||
(0, 2048, 173, 0, 'Paragon - Daggers'),
|
||||
(0, 2048, 176, 0, 'Paragon - Thrown'),
|
||||
(0, 2048, 226, 0, 'Paragon - Crossbows'),
|
||||
(0, 2048, 228, 0, 'Paragon - Wands'),
|
||||
(0, 2048, 229, 0, 'Paragon - Polearms'),
|
||||
(0, 2048, 473, 0, 'Paragon - Fist Weapons'),
|
||||
-- Armor proficiencies (Cloth is in a classMask=0 row already)
|
||||
(0, 2048, 293, 0, 'Paragon - Plate Mail'),
|
||||
(0, 2048, 413, 0, 'Paragon - Mail'),
|
||||
(0, 2048, 414, 0, 'Paragon - Leather'),
|
||||
(0, 2048, 433, 0, 'Paragon - Shield');
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,27 @@
|
||||
-- mod-paragon: Blood Elf "Arcane Torrent" uses three spell IDs in WotLK
|
||||
-- (28730 mana/casters, 25046 rogue energy, 50613 death knight runic power),
|
||||
-- all on racial skill line 756. Migration 2026_05_10_02 OR'd class 12 into
|
||||
-- every SkillLineAbility delta from patch-enUS-4, so Paragon Blood Elves
|
||||
-- auto-learned all three and the spellbook showed three identical entries.
|
||||
--
|
||||
-- Paragon should learn a single combined Arcane Torrent that refunds mana,
|
||||
-- energy, AND runic power -- whichever pool the character is using at the
|
||||
-- moment. We keep spell 28730 as the in-book entry for class 12 and attach
|
||||
-- the SpellScript spell_paragon_arcane_torrent (modules/mod-paragon/src/
|
||||
-- Paragon_SC.cpp) so casts by a Paragon also EnergizeBySpell energy + RP on
|
||||
-- top of the stock mana effect. Other classes' Blood Elves are unaffected.
|
||||
--
|
||||
-- IDs 13338 / 17510 match stock WotLK SkillLineAbility rows for spells 25046
|
||||
-- / 50613 on skill line 756.
|
||||
|
||||
UPDATE `skilllineability_dbc`
|
||||
SET `ClassMask` = `ClassMask` & ~2048
|
||||
WHERE `ID` IN (13338, 17510);
|
||||
|
||||
-- Bind spell_paragon_arcane_torrent (defined in Paragon_SC.cpp) to spell
|
||||
-- 28730. AC's `spell_script_names` is the standard mapping: script name on
|
||||
-- the right, spell id on the left. Idempotent via DELETE + INSERT.
|
||||
DELETE FROM `spell_script_names`
|
||||
WHERE `spell_id` = 28730 AND `ScriptName` = 'spell_paragon_arcane_torrent';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(28730, 'spell_paragon_arcane_torrent');
|
||||
@@ -0,0 +1,30 @@
|
||||
-- mod-paragon: extend ItemTemplate::AllowableClass to include class 12
|
||||
-- (Paragon, bit 1<<11 = 2048) for every class-restricted item.
|
||||
--
|
||||
-- Server-side, Player::CanUseItem (PlayerStorage.cpp) already short-
|
||||
-- circuits the AllowableClass check for class 12. That's enough for any
|
||||
-- code path the server controls (vendor list filter, AH "usable" filter,
|
||||
-- CanRollForItemInLFG, CanBuyItem). It is NOT enough on the 3.3.5 client:
|
||||
-- the WoW.exe binary independently pre-checks AllowableClass against the
|
||||
-- player's class on right-click of a bag item and refuses *locally* with
|
||||
-- the red "You can't use that item." text in UIErrorsFrame, never sending
|
||||
-- CMSG_USE_ITEM at all. Server logs stay silent; only client knows it
|
||||
-- refused.
|
||||
--
|
||||
-- Fix: OR class 12's bit into AllowableClass on every class-restricted
|
||||
-- row so the client engine's pre-check passes for Paragon. Other
|
||||
-- classes' bits are unchanged, so e.g. a warrior-only item is still
|
||||
-- warrior-only for everyone except Paragon. Items with AllowableClass
|
||||
-- == -1 ("all classes") or 0 ("no restriction recorded") already pass
|
||||
-- the client engine's check and are not touched.
|
||||
--
|
||||
-- After applying this migration the *client* still caches item info in
|
||||
-- Cache/<locale>/itemcache.wdb. Players who already inspected the item
|
||||
-- before the change must delete that file (or the whole Cache folder)
|
||||
-- and reconnect to repopulate it from the worldserver, otherwise the
|
||||
-- stale cached AllowableClass keeps the engine pre-check failing.
|
||||
|
||||
UPDATE `item_template`
|
||||
SET `AllowableClass` = `AllowableClass` | 2048
|
||||
WHERE `AllowableClass` > 0
|
||||
AND (`AllowableClass` & 2048) = 0;
|
||||
@@ -0,0 +1,62 @@
|
||||
-- mod-paragon: backfill paragon_spell_ae_cost rows for spells newly exposed
|
||||
-- by the Character Advancement panel after removing the over-aggressive
|
||||
-- ClassMask=0 filter from tools/_gen_paragon_advancement_spells_lua.py.
|
||||
--
|
||||
-- The base file (data/sql/db-world/base/paragon_spell_ae_cost.sql) was
|
||||
-- regenerated alongside this migration so fresh deployments already have
|
||||
-- these rows. Existing servers do not re-run base files on content change,
|
||||
-- so this update inserts the new (spell_id, ae_cost) pairs idempotently.
|
||||
-- INSERT IGNORE keeps any per-row tuning a server operator may have already
|
||||
-- applied to spell_ids that happen to overlap.
|
||||
--
|
||||
-- New ids include: 51505 Lava Burst (Shaman), 12051 Evocation / 1066 Aqueous
|
||||
-- Form / Hex / Mage Ward / Spellsteal (Mage), 53351 Kill Shot / 19263
|
||||
-- Deterrence / 53271 Master's Call (Hunter), 3714 Path of Frost / 57330
|
||||
-- Horn of Winter / 56815 Rune Strike / 61999 Raise Ally / 56222 Dark Command
|
||||
-- (DK), and 39 other trainer-taught class abilities whose stock
|
||||
-- SkillLineAbility.dbc rows have ClassMask=0 (the skill line itself pins the
|
||||
-- class for these rows; ClassMask is redundant on class-spec lines).
|
||||
|
||||
INSERT IGNORE INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(66, 1), -- Invisibility (Mage)
|
||||
(126, 1), -- Eye of Kilrogg (Warlock)
|
||||
(526, 1), -- Cure Toxins (Shaman)
|
||||
(688, 1), -- Summon Imp (Warlock)
|
||||
(691, 1), -- Summon Felhunter (Warlock)
|
||||
(697, 1), -- Summon Voidwalker (Warlock)
|
||||
(712, 1), -- Summon Succubus (Warlock)
|
||||
(768, 1), -- Cat Form (Druid)
|
||||
(783, 1), -- Travel Form (Druid)
|
||||
(1066, 1), -- Aqueous Form (Mage)
|
||||
(2894, 1), -- Fire Resistance Totem (Shaman)
|
||||
(3714, 1), -- Path of Frost (DK)
|
||||
(5215, 1), -- Prowl (Druid)
|
||||
(5487, 1), -- Bear Form (Druid)
|
||||
(5504, 1), -- Conjure Refreshment (Mage)
|
||||
(6795, 1), -- Growl (Druid)
|
||||
(6807, 1), -- Maul (Druid)
|
||||
(12051, 1), -- Evocation (Mage)
|
||||
(19263, 1), -- Deterrence (Hunter)
|
||||
(23161, 1), -- Summon Dreadsteed (Warlock)
|
||||
(23214, 1), -- Summon Charger (Paladin)
|
||||
(30449, 1), -- Spellsteal (Mage)
|
||||
(33943, 1), -- Flight Form (Druid)
|
||||
(34767, 1), -- Summon Felguard (Warlock)
|
||||
(48018, 1), -- Demonic Circle: Summon (Warlock)
|
||||
(50769, 1), -- Revive (Druid)
|
||||
(51505, 1), -- Lava Burst (Shaman)
|
||||
(51514, 1), -- Hex (Shaman)
|
||||
(51730, 1), -- Earthliving Weapon (Shaman)
|
||||
(52127, 1), -- Water Shield (Shaman)
|
||||
(52610, 1), -- Savage Roar (Druid)
|
||||
(53271, 1), -- Master's Call (Hunter)
|
||||
(53351, 1), -- Kill Shot (Hunter)
|
||||
(56222, 1), -- Dark Command (DK)
|
||||
(56815, 1), -- Rune Strike (DK)
|
||||
(57330, 1), -- Horn of Winter (DK)
|
||||
(61999, 1), -- Raise Ally (DK)
|
||||
(64843, 1), -- Divine Hymn (Priest)
|
||||
(64901, 1), -- Hymn of Hope (Priest)
|
||||
(66842, 1), -- Call of the Elements (Shaman totem set)
|
||||
(66843, 1), -- Call of the Ancestors (Shaman totem set)
|
||||
(66844, 1); -- Call of the Spirits (Shaman totem set)
|
||||
@@ -0,0 +1,60 @@
|
||||
-- mod-paragon: Predatory Strikes (16972 / 16974 / 16975) Cataclysm-style
|
||||
-- finisher proc for CLASS_PARAGON characters.
|
||||
--
|
||||
-- The 3.3.5 Predatory Strikes is a passive AP / ranged-attack-power talent
|
||||
-- with no proc payload. The Cataclysm redesign added "Predator's Swiftness"
|
||||
-- (69369), which makes the next Nature spell <10s base cast time instant.
|
||||
-- That buff already exists in the WotLK Spell.dbc (because Blizzard reused
|
||||
-- the spell id), but no server-side trigger ever calls CastSpell(69369) on
|
||||
-- a 3.3.5 server. We need both halves: the proc handler AND a spell_proc
|
||||
-- row so the proc evaluator actually invokes our AuraScript.
|
||||
--
|
||||
-- AuraScript binding: spell_paragon_predatory_strikes is registered in
|
||||
-- modules/mod-paragon/src/Paragon_SC.cpp. It checks
|
||||
-- (a) caster is CLASS_PARAGON,
|
||||
-- (b) source spell consumes combo points (NeedsComboPoints),
|
||||
-- (c) source spell deals damage (DmgClass MELEE/RANGED + at least one
|
||||
-- damage effect or periodic-damage aura -- filters Slice and Dice,
|
||||
-- Savage Roar, Maim, Kidney Shot, Expose Armor, Recuperate),
|
||||
-- then rolls a per-rank chance of (CP * 3 / 5 / 7)% to cast 69369 on
|
||||
-- the caster.
|
||||
--
|
||||
-- spell_proc row params:
|
||||
-- ProcFlags = 0x40000 = PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS
|
||||
-- SpellTypeMask = 0x3 (DAMAGE | HEAL bitmask in proc engine; we
|
||||
-- filter precisely in CheckProc anyway, the
|
||||
-- mask just gates "spell-type events" through)
|
||||
-- SpellPhaseMask = 0x2 = PROC_SPELL_PHASE_CAST -- fires DURING cast
|
||||
-- so player->GetComboPoints() inside HandleProc
|
||||
-- still returns the pre-_handle_finish_phase
|
||||
-- value.
|
||||
-- Chance = 100 (the per-CP chance is rolled inside the script)
|
||||
--
|
||||
-- Note: this row's SpellFamilyName / SpellFamilyMask are 0 so the proc
|
||||
-- engine's IsAffected check is a wildcard at the entry-level. The
|
||||
-- AuraScript's CheckProc owns all real filtering. Combined with Phase A
|
||||
-- (Paragon SpellFamilyName wildcard) this is harmless on stock classes
|
||||
-- because non-Paragon characters cannot learn Predatory Strikes via the
|
||||
-- Character Advancement panel.
|
||||
|
||||
DELETE FROM `spell_script_names`
|
||||
WHERE `spell_id` IN (16972, 16974, 16975)
|
||||
AND `ScriptName` = 'spell_paragon_predatory_strikes';
|
||||
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(16972, 'spell_paragon_predatory_strikes'),
|
||||
(16974, 'spell_paragon_predatory_strikes'),
|
||||
(16975, 'spell_paragon_predatory_strikes');
|
||||
|
||||
DELETE FROM `spell_proc` WHERE `SpellId` IN (16972, 16974, 16975);
|
||||
|
||||
INSERT INTO `spell_proc`
|
||||
(`SpellId`, `SchoolMask`, `SpellFamilyName`,
|
||||
`SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`,
|
||||
`ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`,
|
||||
`AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`,
|
||||
`Chance`, `Cooldown`, `Charges`)
|
||||
VALUES
|
||||
(16972, 0, 0, 0, 0, 0, 0x40000, 0x3, 0x2, 0, 0, 0, 0, 100.0, 0, 0),
|
||||
(16974, 0, 0, 0, 0, 0, 0x40000, 0x3, 0x2, 0, 0, 0, 0, 100.0, 0, 0),
|
||||
(16975, 0, 0, 0, 0, 0, 0x40000, 0x3, 0x2, 0, 0, 0, 0, 100.0, 0, 0);
|
||||
@@ -0,0 +1,46 @@
|
||||
-- mod-paragon: Vampiric Embrace (15286) cross-family wildcard.
|
||||
--
|
||||
-- Stock 3.3.5 spell_proc row for Vampiric Embrace gates by SpellFamilyName=6
|
||||
-- (PRIEST) plus a Priest-Shadow-damage SpellFamilyMask. That blocks the proc
|
||||
-- engine from ever calling the AuraScript's CheckProc when a Paragon casts a
|
||||
-- non-Priest Shadow-school spell (e.g. Warlock Shadow Bolt, Death Knight
|
||||
-- Death Coil, etc.), because IsAffected's familyFlags gate fails before
|
||||
-- CheckProc runs even though the Phase A wildcard already loosens the
|
||||
-- familyName equality test (see SpellInfo::IsAffected, listenerOwner overload).
|
||||
--
|
||||
-- We relax this row so:
|
||||
-- * SchoolMask=32 (SHADOW) kept -- proc-engine still gates by school
|
||||
-- * SpellTypeMask=1 (DAMAGE) kept -- only damage events trigger CheckProc
|
||||
-- * SpellPhaseMask=2 (HIT) kept -- post-hit phase
|
||||
-- * AttributesMask=2 (TRIGGERED) kept -- triggered-spell payloads still proc
|
||||
-- * SpellFamilyName=0 wildcard -- IsAffected short-circuits to true
|
||||
-- * SpellFamilyMask{0,1,2}=0 wildcard -- no flag-bit gating at this layer
|
||||
--
|
||||
-- Real filtering moves into spell_pri_vampiric_embrace::CheckProc, which
|
||||
-- branches on IsParagonWildcardCaller(GetTarget()):
|
||||
--
|
||||
-- * For Paragon owners with `Paragon.WildcardFamilyMatching = 1`, accept any
|
||||
-- single-target Shadow-school spell (Mind Sear / AoE shadow spells like
|
||||
-- Seed of Corruption / Hellfire are filtered there via IsAffectingArea
|
||||
-- and the existing Mind Sear bit-mask).
|
||||
--
|
||||
-- * For stock Priest owners (and for the non-wildcard runtime path), the
|
||||
-- CheckProc re-enforces the EXACT original gate -- SpellFamilyName=6 plus
|
||||
-- the original 0x0280A010 / 0x00002402 / 0x00000008 SpellFamilyMask bits
|
||||
-- -- so behavior is byte-identical to before this change for any caster
|
||||
-- that is not a Paragon.
|
||||
--
|
||||
-- Net effect: Paragon characters with VE learned now leech-heal off any
|
||||
-- single-target Shadow spell they cast (Death Coil, Shadow Bolt, Searing
|
||||
-- Pain, Drain Soul, etc.); stock Shadow Priests are unchanged.
|
||||
|
||||
DELETE FROM `spell_proc` WHERE `SpellId` = 15286;
|
||||
|
||||
INSERT INTO `spell_proc`
|
||||
(`SpellId`, `SchoolMask`, `SpellFamilyName`,
|
||||
`SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`,
|
||||
`ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`,
|
||||
`AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`,
|
||||
`Chance`, `Cooldown`, `Charges`)
|
||||
VALUES
|
||||
(15286, 32, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0);
|
||||
@@ -0,0 +1,51 @@
|
||||
-- mod-paragon: Maelstrom Weapon (53817) cross-family wildcard.
|
||||
--
|
||||
-- Stock 3.3.5 spell_proc row for Maelstrom Weapon gates by SpellFamilyName=11
|
||||
-- (SHAMAN) plus a Shaman SpellFamilyMask covering Lightning Bolt, Chain
|
||||
-- Lightning, Lesser Healing Wave, Healing Wave and Hex (Mask0=451,
|
||||
-- Mask1=32768). The proc engine therefore never delivers an event to the
|
||||
-- AuraScript when a Paragon casts a non-Shaman cast-time spell, even if the
|
||||
-- IsAffected wildcard relaxes SpellFamilyName equality (the SpellFamilyMask
|
||||
-- AND-with-target-FamilyFlags check still fails because Mage / Warlock /
|
||||
-- Druid spell-class bits do not overlap with Shaman bits).
|
||||
--
|
||||
-- We relax this row so:
|
||||
-- * SchoolMask=0 wildcard -- proc engine no longer gates by school
|
||||
-- * SpellTypeMask=1 (DAMAGE) kept -- only damage spells trigger CheckProc
|
||||
-- * SpellPhaseMask=8 (FINISH) kept -- post-cast phase, on cast finish
|
||||
-- * SpellFamilyName=0 wildcard -- IsAffected short-circuits to true
|
||||
-- * SpellFamilyMask{0,1,2}=0 wildcard -- no flag-bit gating at this layer
|
||||
--
|
||||
-- Real filtering moves into spell_sha_maelstrom_weapon::CheckProc:
|
||||
--
|
||||
-- * For stock Shaman owners (and for the non-wildcard runtime path), the
|
||||
-- CheckProc re-enforces the EXACT original gate -- SpellFamilyName=11
|
||||
-- plus the original Mask0=451 / Mask1=32768 bits -- so behavior is
|
||||
-- byte-identical to before this change for any caster that is not a
|
||||
-- Paragon.
|
||||
--
|
||||
-- * For Paragon owners with `Paragon.WildcardFamilyMatching = 1`, the
|
||||
-- stock allowlist still passes, AND we additionally accept the curated
|
||||
-- Mage cast-time nukes Fireball / Frostbolt / Arcane Blast (any rank,
|
||||
-- matched via GetFirstRankSpell).
|
||||
--
|
||||
-- The matching IsAffectedBySpellMod hook in SpellInfo.cpp ensures the cast
|
||||
-- time + power cost spellmods on aura 53817 also bridge across families for
|
||||
-- the same Mage spell allowlist, so Paragons get the full Maelstrom Weapon
|
||||
-- experience (instant cast at 5 stacks + reduced mana cost) on Fireball,
|
||||
-- Frostbolt and Arcane Blast.
|
||||
--
|
||||
-- Net effect: Paragon characters with Maelstrom Weapon learned now spend
|
||||
-- stacks on Mage cast-time nukes in addition to the stock Shaman list;
|
||||
-- stock Enhancement Shamans are unchanged.
|
||||
|
||||
DELETE FROM `spell_proc` WHERE `SpellId` = 53817;
|
||||
|
||||
INSERT INTO `spell_proc`
|
||||
(`SpellId`, `SchoolMask`, `SpellFamilyName`,
|
||||
`SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`,
|
||||
`ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`,
|
||||
`AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`,
|
||||
`Chance`, `Cooldown`, `Charges`)
|
||||
VALUES
|
||||
(53817, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0);
|
||||
@@ -0,0 +1,66 @@
|
||||
-- mod-paragon: Frostbite + Fingers of Frost cross-family wildcard.
|
||||
--
|
||||
-- Both talents are normally gated by SpellFamilyName=3 (MAGE) plus a Mage
|
||||
-- SpellFamilyMask covering specific Mage Frost spells (Frostbolt / Frost Nova
|
||||
-- / Cone of Cold / Blizzard / Frostfire Bolt / Deep Freeze for FoF; Frost
|
||||
-- slow-applying spells for Frostbite). That blocks the proc engine from
|
||||
-- delivering an event to the AuraScript when a Paragon casts a non-Mage
|
||||
-- Frost-school chill effect (DK Howling Blast / Icy Touch / Chains of Ice,
|
||||
-- Hunter Frost Trap, Shaman Frost Shock, etc.), because IsAffected's
|
||||
-- familyFlags AND-with-target-FamilyFlags check fails before CheckProc runs
|
||||
-- even after the Paragon family-name wildcard.
|
||||
--
|
||||
-- We relax these rows so:
|
||||
-- * SchoolMask=16 (FROST) gate by Frost school at the proc engine
|
||||
-- * SpellTypeMask=1 (DAMAGE) only damage events trigger CheckProc
|
||||
-- * SpellPhaseMask=2 (HIT) post-hit phase
|
||||
-- * AttributesMask=2 (TRIGGERED) triggered chill payloads still proc
|
||||
-- * SpellFamilyName=0 wildcard -- IsAffected short-circuits to true
|
||||
-- * SpellFamilyMask{0,1,2}=0 wildcard -- no flag-bit gating at this layer
|
||||
--
|
||||
-- Real filtering moves into the Mage AuraScripts:
|
||||
--
|
||||
-- spell_mage_fingers_of_frost_talent attached to 44543 / 44545
|
||||
-- stock Mage : SpellFamilyName=MAGE AND original Mask0 0x100120 / Mask1 0x1000
|
||||
-- Paragon : accept (FROST + DAMAGE gate already enforced)
|
||||
--
|
||||
-- spell_mage_frostbite attached to 11071 / 12496 / 12497
|
||||
-- stock Mage : SpellFamilyName=MAGE AND original Mage Frost-slow Mask
|
||||
-- (Frostbolt / Frost Nova / Cone of Cold / Blizzard / FFB)
|
||||
-- Paragon : accept iff proc spell applies SPELL_AURA_MOD_DECREASE_SPEED
|
||||
-- OR the Paragon already has a slow on the proc target
|
||||
-- (covers the Improved-Blizzard-style "chill via separate
|
||||
-- triggered aura" cross-class case)
|
||||
--
|
||||
-- Net effect: Paragon characters with these talents now have FoF / Frostbite
|
||||
-- proc off cross-class Frost-school chill effects; stock Mages are unchanged.
|
||||
|
||||
DELETE FROM `spell_proc` WHERE `SpellId` IN (44543, 44545, 11071, 12496, 12497);
|
||||
|
||||
INSERT INTO `spell_proc`
|
||||
(`SpellId`, `SchoolMask`, `SpellFamilyName`,
|
||||
`SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`,
|
||||
`ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`,
|
||||
`AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`,
|
||||
`Chance`, `Cooldown`, `Charges`)
|
||||
VALUES
|
||||
-- Fingers of Frost talent ranks (Chance 7% / 15% preserved from stock row).
|
||||
(44543, 16, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 7, 0, 0),
|
||||
(44545, 16, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 15, 0, 0),
|
||||
-- Frostbite talent ranks (5% / 10% / 15% per rank, leave Chance=0 to use
|
||||
-- the DBC ProcChance which already encodes the per-rank percentage).
|
||||
(11071, 16, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0),
|
||||
(12496, 16, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0),
|
||||
(12497, 16, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0);
|
||||
|
||||
-- Bind the new AuraScripts (defined in src/server/scripts/Spells/spell_mage.cpp).
|
||||
DELETE FROM `spell_script_names`
|
||||
WHERE `spell_id` IN (44543, 44545, 11071, 12496, 12497)
|
||||
AND `ScriptName` IN ('spell_mage_fingers_of_frost_talent', 'spell_mage_frostbite');
|
||||
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(44543, 'spell_mage_fingers_of_frost_talent'),
|
||||
(44545, 'spell_mage_fingers_of_frost_talent'),
|
||||
(11071, 'spell_mage_frostbite'),
|
||||
(12496, 'spell_mage_frostbite'),
|
||||
(12497, 'spell_mage_frostbite');
|
||||
@@ -0,0 +1,51 @@
|
||||
-- mod-paragon: Maelstrom Weapon (53817) spell_proc fixup.
|
||||
--
|
||||
-- The previous migration (2026_05_11_02.sql) had two bugs in the rewritten
|
||||
-- spell_proc row that prevented stack consumption from firing at all -- not
|
||||
-- just for our new Mage targets, but also for the stock Shaman cast-time
|
||||
-- spells (Lightning Bolt, Chain Lightning, Lesser Healing Wave, etc.).
|
||||
--
|
||||
-- Bugs:
|
||||
--
|
||||
-- * SpellPhaseMask was set to 8. The valid values for SpellPhaseMask are
|
||||
-- PROC_SPELL_PHASE_CAST = 1
|
||||
-- PROC_SPELL_PHASE_HIT = 2
|
||||
-- PROC_SPELL_PHASE_FINISH = 4
|
||||
-- (see SpellMgr.h). Anything else, including 8, never matches a real
|
||||
-- proc event, so the proc engine silently dropped every event before it
|
||||
-- reached the AuraScript. The original stock row uses 1 (CAST), which
|
||||
-- is what fires when the cast packet's setup phase completes -- exactly
|
||||
-- when we want the spellmod-affected cast to consume the buff.
|
||||
--
|
||||
-- * AttributesMask was set to 0. The original stock row uses 8
|
||||
-- PROC_ATTR_REQ_SPELLMOD = 0x8
|
||||
-- which says "only proc on spells that were affected by one of this
|
||||
-- aura's spellmods". This is the bridge between IsAffectedBySpellMod
|
||||
-- (which records the aura into Spell::m_appliedMods when calculating
|
||||
-- cast time / cost) and the proc system (which then knows that the cast
|
||||
-- used the buff and should consume a charge). Without this attribute,
|
||||
-- the proc would either fire too aggressively or not at all depending
|
||||
-- on subsequent gating, but in practice the engine relies on it to
|
||||
-- correlate spellmod use with stack consumption.
|
||||
--
|
||||
-- Fixed row keeps the same family/mask wildcards from the previous
|
||||
-- migration (so the Paragon Mage allowlist in spell_sha_maelstrom_weapon's
|
||||
-- CheckProc still gets the chance to filter), restores SpellPhaseMask=1
|
||||
-- (CAST) and AttributesMask=8 (REQ_SPELLMOD) to match stock semantics, and
|
||||
-- resets SpellTypeMask to 0 (any spell type -- the REQ_SPELLMOD attribute
|
||||
-- already gates by "was the buff actually used", so an extra DAMAGE filter
|
||||
-- is redundant and would block e.g. Lesser Healing Wave on stock Shamans).
|
||||
--
|
||||
-- This restores stock Shaman behavior byte-identically and lets Paragon
|
||||
-- Mage casts also consume stacks via the IsAffectedBySpellMod allowlist.
|
||||
|
||||
DELETE FROM `spell_proc` WHERE `SpellId` = 53817;
|
||||
|
||||
INSERT INTO `spell_proc`
|
||||
(`SpellId`, `SchoolMask`, `SpellFamilyName`,
|
||||
`SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`,
|
||||
`ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`,
|
||||
`AttributesMask`, `DisableEffectsMask`, `ProcsPerMinute`,
|
||||
`Chance`, `Cooldown`, `Charges`)
|
||||
VALUES
|
||||
(53817, 0, 0, 0, 0, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0);
|
||||
@@ -1,11 +0,0 @@
|
||||
-- Optional per-spell AE costs for Paragon spell purchases (.paragon learn).
|
||||
-- Apply to the *world* database.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `paragon_spell_ae_cost` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`ae_cost` SMALLINT UNSIGNED NOT NULL DEFAULT '2',
|
||||
PRIMARY KEY (`spell_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='mod-paragon: AE cost per spell';
|
||||
|
||||
-- Example (uncomment to use):
|
||||
-- INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES (55050, 2);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,15 +5,24 @@
|
||||
* so Paragon can reuse other classes' mechanics in narrowly scoped contexts.
|
||||
*/
|
||||
|
||||
#include "Chat.h"
|
||||
#include "Config.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureData.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "UnitDefines.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
#include "GameTime.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class Paragon_PlayerScript : public PlayerScript
|
||||
@@ -30,7 +39,7 @@ public:
|
||||
{
|
||||
LOG_INFO("module", "[paragon] Paragon_PlayerScript registered "
|
||||
"(MultiResource.HasActivePowers={})",
|
||||
sConfigMgr->GetOption<bool>("Paragon.MultiResource.HasActivePowers", false));
|
||||
sConfigMgr->GetOption<bool>("Paragon.MultiResource.HasActivePowers", true));
|
||||
}
|
||||
|
||||
[[nodiscard]] Optional<bool> OnPlayerIsClass(Player const* player, Classes unitClass, ClassContext context) override
|
||||
@@ -38,27 +47,218 @@ public:
|
||||
if (!player || player->getClass() != CLASS_PARAGON)
|
||||
return std::nullopt;
|
||||
|
||||
// Death Knight rune / runic power ability stack (narrow on purpose).
|
||||
if (unitClass == CLASS_DEATH_KNIGHT && context == CLASS_CONTEXT_ABILITY)
|
||||
// ============================================================
|
||||
// Ability stack -- claim ALL nine vanilla classes.
|
||||
// ============================================================
|
||||
// CLASS_CONTEXT_ABILITY is read by every class-specific spell
|
||||
// gate in core / scripts: DK rune mechanics (Spell.cpp,
|
||||
// SpellEffects.cpp, spell_dk.cpp, SpellAuraEffects.cpp),
|
||||
// Warrior Titan's Grip / Bladestorm (Player.cpp 3783, 15432,
|
||||
// PlayerUpdates.cpp 1547), Paladin Rebuke (Player.cpp 15441),
|
||||
// Shaman dual-wield bookkeeping (Player.cpp 5028), Hunter pet
|
||||
// / Hunter's Mark gates (spell_item.cpp 3718), Druid Insect
|
||||
// Swarm / Wild Growth (SpellAuraEffects.cpp 2153, 2232),
|
||||
// Priest Spirit of Redemption out-of-bounds check (Unit.cpp
|
||||
// 14238), Rogue pickpocketing (LootHandler.cpp 86/165/385,
|
||||
// Vehicle.cpp 80). Paragon learns abilities from every class
|
||||
// through Character Advancement, so claiming all of them lets
|
||||
// every gated spell script execute its class-specific branch
|
||||
// for our players. The only downside is double-pathed scripts
|
||||
// (e.g. a spell with both warrior and rogue branches) will
|
||||
// pick whichever the script tests first -- acceptable.
|
||||
if (context == CLASS_CONTEXT_ABILITY)
|
||||
return true;
|
||||
|
||||
// Warrior ability stack: enables warrior-spec ability gates anywhere
|
||||
// they're checked. None of the currently-traced sites in core/scripts
|
||||
// gate on (CLASS_WARRIOR, CLASS_CONTEXT_ABILITY), so this is a safe
|
||||
// forward-compatible claim. Rage generation itself is gated on
|
||||
// HasActivePowerType(POWER_RAGE) and is wired below.
|
||||
if (unitClass == CLASS_WARRIOR && context == CLASS_CONTEXT_ABILITY)
|
||||
return true;
|
||||
|
||||
// Reactive melee states: Overpower-on-dodge (warrior), Counterattack window (hunter).
|
||||
// We intentionally do NOT claim CLASS_ROGUE here: that context skips the generic
|
||||
// AURA_STATE_DEFENSE update on dodge (Riposte path) in Unit::ProcDamageAndSpellFor.
|
||||
// ============================================================
|
||||
// Reactive melee states.
|
||||
// ============================================================
|
||||
// Warrior dodge -> AURA_STATE_DEFENSE (Overpower window).
|
||||
// Hunter parry -> AURA_STATE_HUNTER_PARRY (Counterattack).
|
||||
// We intentionally do NOT claim CLASS_ROGUE here:
|
||||
// Unit::ProcDamageAndSpellFor (Unit.cpp 12824) skips the
|
||||
// generic AURA_STATE_DEFENSE update on dodge for rogues so
|
||||
// Riposte can take over. Claiming rogue would silently kill
|
||||
// Overpower for Paragon, and Riposte already works for us via
|
||||
// the warrior-style state we already grant.
|
||||
if (context == CLASS_CONTEXT_ABILITY_REACTIVE)
|
||||
{
|
||||
if (unitClass == CLASS_WARRIOR || unitClass == CLASS_HUNTER)
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Pet ownership contexts.
|
||||
// ============================================================
|
||||
// CLASS_CONTEXT_PET is read by Pet::AddToWorld, Pet::CreateBase
|
||||
// AtCreatureInfo, Pet::InitStatsForLevel (twice -- the
|
||||
// MAX_PET_TYPE bootstrap branch and the per-class attack-time
|
||||
// scaling), Pet::IsPermanentPetFor, Player::SummonPet,
|
||||
// Player::CanResummonPet, Spell::EffectTameCreature,
|
||||
// SpellEffects.cpp (CreateTamedPet debug effects, Eyes of the
|
||||
// Beast), spell_generic.cpp 1760 (charm-as-pet conversion),
|
||||
// and PlayerGossip.cpp's hunter stable check.
|
||||
//
|
||||
// The cleanest disambiguation is by the *active pet's* shape:
|
||||
// HUNTER_PET -> hunter (beast tame)
|
||||
// SUMMON_PET + DEMON type -> warlock (Imp/VW/Succ/...)
|
||||
// SUMMON_PET + UNDEAD type -> DK ghoul / Army of Dead
|
||||
// SUMMON_PET + ELEMENTAL type -> mage water / shaman fire
|
||||
// For HUNTER specifically the no-pet case is also claimed so
|
||||
// Tame Beast's EffectTameCreature gate passes during cast.
|
||||
if (context == CLASS_CONTEXT_PET)
|
||||
{
|
||||
Pet const* activePet = const_cast<Player*>(player)->GetPet();
|
||||
|
||||
// Hunter beast: claim during taming OR when a HUNTER_PET is
|
||||
// already active. This is what makes Tame Beast / Call Pet
|
||||
// / pet stable / Counterattack pet aura feedback work.
|
||||
if (unitClass == CLASS_HUNTER)
|
||||
{
|
||||
if (!activePet || activePet->getPetType() == HUNTER_PET)
|
||||
return true;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// All other classes only claim when an active SUMMON_PET is
|
||||
// present. We then disambiguate by the creature's type
|
||||
// because warlock / DK / mage / shaman all use SUMMON_PET.
|
||||
if (!activePet || activePet->getPetType() != SUMMON_PET)
|
||||
return std::nullopt;
|
||||
|
||||
CreatureTemplate const* tmpl = activePet->GetCreatureTemplate();
|
||||
if (!tmpl)
|
||||
return std::nullopt;
|
||||
|
||||
switch (unitClass)
|
||||
{
|
||||
case CLASS_WARLOCK:
|
||||
// Drives Master Demonologist / Demonic Knowledge /
|
||||
// Demonic Pact propagation, last-pet-spell tracking
|
||||
// (Pet.cpp 112), and IsPermanentPetFor (Pet.cpp
|
||||
// 2288) so demon pets persist across logins.
|
||||
if (tmpl->type == CREATURE_TYPE_DEMON)
|
||||
return true;
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
// Risen Ghoul + Army of the Dead. Player.cpp 14354
|
||||
// and Pet.cpp 243 / 1046 / 2290 read this; without
|
||||
// it the ghoul is invisible to the owner mid-load
|
||||
// and ScriptedAI hooks on the ghoul mis-route.
|
||||
if (tmpl->type == CREATURE_TYPE_UNDEAD)
|
||||
return true;
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
// Glyph-of-Eternal-Water permanent Water Elemental
|
||||
// (entry 510, 37994). Used by Pet.cpp 1047/2292.
|
||||
if (tmpl->type == CREATURE_TYPE_ELEMENTAL)
|
||||
return true;
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
// Fire Elemental / Earth Elemental. The base
|
||||
// engine spawns these as creatures rather than
|
||||
// proper Pet instances in most code paths, so the
|
||||
// claim mostly matters for the Pet.cpp 1045 stat
|
||||
// bootstrap when one is loaded as a SUMMON_PET.
|
||||
if (tmpl->type == CREATURE_TYPE_ELEMENTAL)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Warlock pet-charm context (Enslave Demon -- Unit.cpp 14828,
|
||||
// 14894, 15025). Without this claim, charming a demon as a
|
||||
// Paragon doesn't get the warlock-flavor charm semantics
|
||||
// (faction-set-on-charm, action-bar layout, charm-break logic).
|
||||
if (unitClass == CLASS_WARLOCK && context == CLASS_CONTEXT_PET_CHARM)
|
||||
return true;
|
||||
|
||||
// ============================================================
|
||||
// Equipment contexts.
|
||||
// ============================================================
|
||||
// CLASS_CONTEXT_EQUIP_RELIC: PlayerStorage.cpp 224-240 +
|
||||
// 2475-2493. Routes Librams/Idols/Totems/Misc/Sigils into
|
||||
// EQUIPMENT_SLOT_RANGED for the matching class. Claim every
|
||||
// relic-bearing class so a Paragon can drop any of them into
|
||||
// the ranged slot.
|
||||
if (context == CLASS_CONTEXT_EQUIP_RELIC)
|
||||
{
|
||||
switch (unitClass)
|
||||
{
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_DRUID:
|
||||
case CLASS_SHAMAN:
|
||||
case CLASS_WARLOCK:
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// CLASS_CONTEXT_EQUIP_ARMOR_CLASS: PlayerStorage.cpp 2326,
|
||||
// 2330, 2503-2523. At level 40 each class auto-learns its
|
||||
// top armor proficiency. Paragon should pick up plate (via
|
||||
// paladin/DK), shields (paladin/warrior/shaman), mail
|
||||
// (hunter/shaman), and leather (rogue) so the level-40 train
|
||||
// event grants Paragon full proficiency and we don't have to
|
||||
// hand-curate it through the Paragon proficiency SQL.
|
||||
if (context == CLASS_CONTEXT_EQUIP_ARMOR_CLASS)
|
||||
{
|
||||
switch (unitClass)
|
||||
{
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
case CLASS_HUNTER:
|
||||
case CLASS_SHAMAN:
|
||||
case CLASS_DRUID:
|
||||
case CLASS_ROGUE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// CLASS_CONTEXT_EQUIP_SHIELDS: PlayerStorage.cpp 2467-2469.
|
||||
// Lets a Paragon equip shields without a paladin/warrior/
|
||||
// shaman skill gate.
|
||||
if (context == CLASS_CONTEXT_EQUIP_SHIELDS)
|
||||
{
|
||||
switch (unitClass)
|
||||
{
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_SHAMAN:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// CLASS_CONTEXT_WEAPON_SWAP: PlayerStorage.cpp 1920, 2838 --
|
||||
// rogue uses cooldown spell 6123 instead of 6119 on weapon
|
||||
// swap (Quick Draw / Combat Potency interactions). Claim
|
||||
// rogue so Paragon picks up the same cooldown spell.
|
||||
if (context == CLASS_CONTEXT_WEAPON_SWAP && unitClass == CLASS_ROGUE)
|
||||
return true;
|
||||
|
||||
// ============================================================
|
||||
// Contexts we DELIBERATELY DO NOT claim:
|
||||
// ============================================================
|
||||
// CLASS_CONTEXT_STATS -- Paragon has its own STR/AGI->AP and
|
||||
// INT/SPI->SP curves wired in StatSystem.cpp's CLASS_PARAGON
|
||||
// branch (level*2 + STR + AGI - 20 etc.). Claiming any
|
||||
// vanilla class here would override our curves with theirs.
|
||||
//
|
||||
// CLASS_CONTEXT_INIT, _TELEPORT, _QUEST, _TAXI, _SKILL,
|
||||
// _GRAVEYARD, _CLASS_TRAINER, _TALENT_POINT_CALC -- all
|
||||
// used by DK Ebon Hold / druid Moonglade starting-zone
|
||||
// scripts. Paragon doesn't go through those zones and we
|
||||
// don't want our players bound to Acherus or trapped in
|
||||
// the DK starting quest gates.
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -70,7 +270,7 @@ public:
|
||||
if (power == POWER_RUNIC_POWER || power == POWER_RUNE)
|
||||
return true;
|
||||
|
||||
if (sConfigMgr->GetOption<bool>("Paragon.MultiResource.HasActivePowers", false))
|
||||
if (sConfigMgr->GetOption<bool>("Paragon.MultiResource.HasActivePowers", true))
|
||||
{
|
||||
switch (power)
|
||||
{
|
||||
@@ -184,6 +384,45 @@ public:
|
||||
{
|
||||
player->ResyncRunes(MAX_RUNES);
|
||||
st.lastReadyMask = readyMask;
|
||||
|
||||
// Authoritative rune CD pump (PARAA "R RUNES cd0 cd1 ... cd5",
|
||||
// ms remaining per slot, 0 = ready). The 3.3.5 client engine
|
||||
// class-gates SMSG_RESYNC_RUNES / SMSG_SPELL_GO RUNE_LIST to DK,
|
||||
// so the Paragon RuneFrame sim drives the visual entirely off
|
||||
// COMBAT_LOG_EVENT_UNFILTERED:SPELL_CAST_SUCCESS. The combat log
|
||||
// arrives ~100–200ms after the server already started the
|
||||
// cooldown, so the client's local timer trails the server. When
|
||||
// the user spams a rune spell, the server's slot refreshes
|
||||
// first, accepts the next cast, but the client UI still shows
|
||||
// CD remaining → "leak-through" past a greyed icon. Pushing the
|
||||
// actual remaining ms on every mask transition keeps the
|
||||
// visual locked to server state.
|
||||
std::string body = "R RUNES";
|
||||
for (uint8 i = 0; i < MAX_RUNES; ++i)
|
||||
body += " " + std::to_string(player->GetRuneCooldown(i));
|
||||
std::string const payload = std::string(kParagonAddonPrefix) + "\t" + body;
|
||||
WorldPacket runePkt;
|
||||
ChatHandler::BuildChatPacket(runePkt, CHAT_MSG_WHISPER, LANG_ADDON, player, player, payload);
|
||||
player->SendDirectMessage(&runePkt);
|
||||
}
|
||||
|
||||
// Combo point pump: the 3.3.5 client engine class-gates SMSG_UPDATE_COMBO_POINTS
|
||||
// to rogue / druid, so the Paragon UI sim never sees CP changes from
|
||||
// Honor Among Thieves / Mutilate / etc. via either the engine state or
|
||||
// the client-side combat-log inference (HAT's 51699 trigger fires with a
|
||||
// null target and doesn't always emit SPELL_CAST_SUCCESS in the log).
|
||||
// Push the count over PARAA whenever it changes; the addon's combo
|
||||
// simulator listens for "R CP <n>" and overwrites paragonCP, so the
|
||||
// ComboFrame on the target frame paints reliably.
|
||||
int8 const cp = player->GetComboPoints();
|
||||
if (cp != st.lastCp)
|
||||
{
|
||||
std::string const payload = std::string(kParagonAddonPrefix) + "\t"
|
||||
+ fmt::format("R CP {}", int32(cp));
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_WHISPER, LANG_ADDON, player, player, payload);
|
||||
player->SendDirectMessage(&data);
|
||||
st.lastCp = cp;
|
||||
}
|
||||
|
||||
if (!sConfigMgr->GetOption<bool>("Paragon.Diag.RuneTrace", false))
|
||||
@@ -214,14 +453,197 @@ private:
|
||||
struct ParagonRuneSyncState
|
||||
{
|
||||
uint8 lastReadyMask{0xFFu}; // sentinel: no prior snapshot
|
||||
int8 lastCp{-1}; // sentinel: no prior snapshot
|
||||
};
|
||||
|
||||
static constexpr char const* kParagonAddonPrefix = "PARAA";
|
||||
|
||||
static std::unordered_map<ObjectGuid, ParagonRuneSyncState> runeSyncByGuid;
|
||||
};
|
||||
|
||||
std::unordered_map<ObjectGuid, Paragon_PlayerScript::ParagonRuneSyncState> Paragon_PlayerScript::runeSyncByGuid;
|
||||
|
||||
// Arcane Torrent (28730) for Paragon: Blood Elf racial skill line 756 has
|
||||
// three Arcane Torrent variants in stock WotLK (28730 mana, 25046 rogue
|
||||
// energy, 50613 DK runic power). For Paragon Blood Elves we keep only 28730
|
||||
// (see migration 2026_05_10_03.sql) and turn it into a "combined" version:
|
||||
// the stock spell already silences nearby enemies and energizes mana via its
|
||||
// own effects; this script adds energy, rage, and runic power energize on
|
||||
// top when the caster is class 12, so a single button refunds whichever
|
||||
// resource pool the player is actually using. Non-Paragon casters are
|
||||
// untouched and keep learning their stock racial variant.
|
||||
class spell_paragon_arcane_torrent : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_paragon_arcane_torrent);
|
||||
|
||||
void HandleAfterCast()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster || !caster->IsPlayer())
|
||||
return;
|
||||
|
||||
Player* player = caster->ToPlayer();
|
||||
if (player->getClass() != CLASS_PARAGON)
|
||||
return;
|
||||
|
||||
// Stock energize amounts from spell_dbc:
|
||||
// 25046 Arcane Torrent (Energy) -> 15 energy
|
||||
// 50613 Arcane Torrent (Runic Power) -> 15 displayed RP (= 150
|
||||
// internal; AC stores RP scaled 10x, see Player::SetMaxPower
|
||||
// POWER_RUNIC_POWER, 1000).
|
||||
// Rage uses the same 10x internal scaling as runic power (see
|
||||
// Player.cpp:Regenerate where rage decay is `-20` for "2 rage by
|
||||
// tick"), so 15 displayed rage = 150 internal.
|
||||
// ModifyPower no-ops on pools the player has no max for, so this is
|
||||
// safe even before the Paragon picks up energy/rage/RP abilities.
|
||||
constexpr int32 kEnergyGain = 15;
|
||||
constexpr int32 kRageGain = 150;
|
||||
constexpr int32 kRunicPowerGain = 150;
|
||||
|
||||
SpellInfo const* spellInfo = GetSpellInfo();
|
||||
uint32 const spellId = spellInfo ? spellInfo->Id : 28730u;
|
||||
|
||||
caster->EnergizeBySpell(player, spellId, kEnergyGain, POWER_ENERGY);
|
||||
caster->EnergizeBySpell(player, spellId, kRageGain, POWER_RAGE);
|
||||
caster->EnergizeBySpell(player, spellId, kRunicPowerGain, POWER_RUNIC_POWER);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterCast += SpellCastFn(spell_paragon_arcane_torrent::HandleAfterCast);
|
||||
}
|
||||
};
|
||||
|
||||
// Predatory Strikes (16972 / 16974 / 16975) for Paragon: re-implements the
|
||||
// Cataclysm-era proc behavior of the talent so a Paragon's damaging
|
||||
// finishers (Eviscerate / Envenom / Ferocious Bite / Rip / Rupture) can
|
||||
// roll Predator's Swiftness (69369) -- the same buff that real druids
|
||||
// get from the Cata redesign of this talent. Combined with the
|
||||
// Spell::prepare interception in core (Spell.cpp), 69369 makes the
|
||||
// Paragon's NEXT Nature-school spell with a base cast time below 10s
|
||||
// instant cast: Chain Lightning, Lightning Bolt, Healing Touch, Wrath,
|
||||
// Nourish, etc. -- not just the Druid-family Nature subset that the
|
||||
// stock SPELLMOD_CASTING_TIME mask on 69369 covers.
|
||||
//
|
||||
// Filter logic:
|
||||
// - Source spell must consume combo points (NeedsComboPoints() — gates
|
||||
// out non-finisher combo-point builders).
|
||||
// - "Damaging finisher": SPELL_ATTR1_FINISHING_MOVE_DAMAGE (Eviscerate,
|
||||
// Envenom, Ferocious Bite, ...) OR a SPELL_ATTR1_FINISHING_MOVE_DURATION
|
||||
// finisher that applies periodic damage (Rip, Rupture). Duration
|
||||
// finishers that only heal (Recuperate) or only buff / CC / armor shred
|
||||
// (Slice and Dice, Savage Roar, Kidney Shot, Maim, Expose Armor) are
|
||||
// rejected.
|
||||
//
|
||||
// Chance per combo point matches the Cataclysm tuning that the user's
|
||||
// client tooltip text reflects: rank 1 = 3% per CP, rank 2 = 5% per CP,
|
||||
// rank 3 = 7% per CP. At 5 CP that is 15% / 25% / 35%, capped at 100%.
|
||||
//
|
||||
// Combo-point read happens during PROC_SPELL_PHASE_CAST, which fires in
|
||||
// Spell::cast → Spell::ProcReflectProcs / Unit::ProcDamageAndSpellFor
|
||||
// BEFORE Spell::_handle_finish_phase clears the player's combo points
|
||||
// (see Spell.cpp:_handle_finish_phase clearing combo points). So
|
||||
// player->GetComboPoints() inside HandleProc returns the pre-clear value.
|
||||
class spell_paragon_predatory_strikes : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_paragon_predatory_strikes);
|
||||
|
||||
static constexpr uint32 SPELL_PARAGON_PREDATORS_SWIFTNESS = 69369;
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_PARAGON_PREDATORS_SWIFTNESS });
|
||||
}
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
|
||||
if (!spellInfo || !spellInfo->NeedsComboPoints())
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DAMAGE))
|
||||
return true;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DURATION))
|
||||
{
|
||||
bool periodicHeal = false;
|
||||
bool periodicDamage = false;
|
||||
for (SpellEffectInfo const& eff : spellInfo->Effects)
|
||||
{
|
||||
if (eff.Effect != SPELL_EFFECT_APPLY_AURA && eff.Effect != SPELL_EFFECT_APPLY_AREA_AURA_PARTY
|
||||
&& eff.Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA)
|
||||
continue;
|
||||
|
||||
switch (eff.ApplyAuraName)
|
||||
{
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
|
||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||
periodicHeal = true;
|
||||
break;
|
||||
case SPELL_AURA_PERIODIC_DAMAGE:
|
||||
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
|
||||
case SPELL_AURA_PERIODIC_LEECH:
|
||||
periodicDamage = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (periodicHeal)
|
||||
return false;
|
||||
|
||||
return periodicDamage;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandleProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
|
||||
Unit* actor = eventInfo.GetActor();
|
||||
Player* player = actor ? actor->ToPlayer() : nullptr;
|
||||
if (!player || player->getClass() != CLASS_PARAGON)
|
||||
return;
|
||||
|
||||
uint8 const cp = player->GetComboPoints();
|
||||
if (cp == 0)
|
||||
return;
|
||||
|
||||
SpellInfo const* talent = GetSpellInfo();
|
||||
if (!talent)
|
||||
return;
|
||||
|
||||
uint32 pctPerCP = 0;
|
||||
switch (talent->Id)
|
||||
{
|
||||
case 16972: pctPerCP = 3; break;
|
||||
case 16974: pctPerCP = 5; break;
|
||||
case 16975: pctPerCP = 7; break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 const chance = std::min<uint32>(100u, pctPerCP * uint32(cp));
|
||||
if (!roll_chance_i(int32(chance)))
|
||||
return;
|
||||
|
||||
player->CastSpell(player, SPELL_PARAGON_PREDATORS_SWIFTNESS, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_paragon_predatory_strikes::CheckProc);
|
||||
OnProc += AuraProcFn(spell_paragon_predatory_strikes::HandleProc);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_paragon()
|
||||
{
|
||||
new Paragon_PlayerScript();
|
||||
RegisterSpellScript(spell_paragon_arcane_torrent);
|
||||
RegisterSpellScript(spell_paragon_predatory_strikes);
|
||||
}
|
||||
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# Start AzerothCore authserver + worldserver detached from the SSH session (nohup + disown).
|
||||
# Stops any already-running authserver/worldserver processes first.
|
||||
#
|
||||
# Usage:
|
||||
# sudo bash scripts/start-azeroth-servers.sh
|
||||
# AZEROTH_BIN=/path/to/azeroth-server/bin bash scripts/start-azeroth-servers.sh
|
||||
#
|
||||
# Environment:
|
||||
# AZEROTH_BIN — directory with authserver and worldserver (default: /root/azeroth-server/bin)
|
||||
# AZEROTH_LOG_DIR — log directory (default: <parent of bin>/logs)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BIN_DIR="${AZEROTH_BIN:-/root/azeroth-server/bin}"
|
||||
LOG_DIR="${AZEROTH_LOG_DIR:-$(cd "$(dirname "$BIN_DIR")" && pwd)/logs}"
|
||||
|
||||
AUTH_BIN="${BIN_DIR}/authserver"
|
||||
WORLD_BIN="${BIN_DIR}/worldserver"
|
||||
|
||||
if [[ ! -x "$AUTH_BIN" ]]; then
|
||||
echo "error: not found or not executable: $AUTH_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -x "$WORLD_BIN" ]]; then
|
||||
echo "error: not found or not executable: $WORLD_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pkill -x authserver 2>/dev/null || true
|
||||
pkill -x worldserver 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
cd "$BIN_DIR"
|
||||
|
||||
nohup "$AUTH_BIN" >>"$LOG_DIR/authserver.log" 2>&1 &
|
||||
disown || true
|
||||
|
||||
sleep 2
|
||||
|
||||
nohup "$WORLD_BIN" >>"$LOG_DIR/worldserver.log" 2>&1 &
|
||||
disown || true
|
||||
|
||||
echo "Started authserver and worldserver (survives SSH disconnect)."
|
||||
echo "Bin: $BIN_DIR"
|
||||
echo "Logs: $LOG_DIR/authserver.log"
|
||||
echo " $LOG_DIR/worldserver.log"
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# Clone Dawnforger/Fractured and omit Docker-only paths. Use when this script is
|
||||
# already on disk (e.g. scp). Otherwise: git clone … && cd Fractured && bash scripts/vps-sparse-checkout-no-docker.sh
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/vps-clone-without-docker.sh /path/to/Fractured git@github.com:Dawnforger/Fractured.git
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TARGET="${1:?usage: $0 /path/to/Fractured <git-remote-url>}"
|
||||
REMOTE="${2:?usage: $0 /path/to/Fractured <git-remote-url>}"
|
||||
|
||||
if [[ -e "$TARGET" ]]; then
|
||||
echo "error: $TARGET already exists; remove it or pick another path." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$TARGET")"
|
||||
git clone "$REMOTE" "$TARGET"
|
||||
|
||||
cd "$TARGET"
|
||||
if [[ ! -f scripts/vps-sparse-checkout-no-docker.sh ]]; then
|
||||
echo "error: clone missing scripts/vps-sparse-checkout-no-docker.sh — pull latest main." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bash scripts/vps-sparse-checkout-no-docker.sh
|
||||
|
||||
echo "Done. Next: docs/DEPLOY_LINUX_VPS.md"
|
||||
Executable
+336
@@ -0,0 +1,336 @@
|
||||
#!/usr/bin/env bash
|
||||
# Collect VPS evidence for Paragon / DBUpdater / binary staleness triage.
|
||||
# Run ON the VPS (Linux). Safe: read-only; does not restart services.
|
||||
#
|
||||
# Usage (from clone):
|
||||
# bash scripts/vps-paragon-diagnostics.sh
|
||||
#
|
||||
# Optional environment:
|
||||
# FRACTURED_REPO — absolute path to Fractured git root (default: parent of scripts/)
|
||||
# FRACTURED_WS_BIN — path to worldserver binary (default: auto-detect)
|
||||
# FRACTURED_WORLDSERVER_CONF — path to worldserver.conf (default: guess from BIN + common layouts)
|
||||
# FRACTURED_SYSTEMD_UNITS — space-separated units to try (default: "fractured-world worldserver ac-worldserver")
|
||||
# FRACTURED_MYSQL — prefix to invoke mysql, e.g. 'mysql -uacore -pacore -h127.0.0.1'
|
||||
# (default Fractured local DB user/password are often both "acore"; use ~/.my.cnf if you prefer not to pass -p on the command line)
|
||||
# If unset, SQL blocks are printed for manual copy-paste only.
|
||||
# FRACTURED_SPELL_IDS — space-separated spell IDs for spell_dbc spot-check (defaults to common DK rune spenders)
|
||||
# FRACTURED_DIAG_OUTPUT — full log file path (default: <repo>/var/vps-paragon-diagnostics-last.txt)
|
||||
#
|
||||
# All output is mirrored to the log file (tee) while still printing to the terminal.
|
||||
# Default path lives under var/ (gitignored in this repo). Open that file in Cursor,
|
||||
# scp it down, or: git add -f var/vps-paragon-diagnostics-last.txt if you intend to commit it.
|
||||
|
||||
set -u
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO="${FRACTURED_REPO:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
||||
|
||||
DIAG_OUT="${FRACTURED_DIAG_OUTPUT:-$REPO/var/vps-paragon-diagnostics-last.txt}"
|
||||
mkdir -p "$(dirname "$DIAG_OUT")"
|
||||
exec > >(tee "$DIAG_OUT") 2>&1
|
||||
echo "Logging to: $DIAG_OUT"
|
||||
|
||||
hr() { printf '\n%s\n' "================================================================================"; }
|
||||
sub() { printf '\n-- %s\n' "$1"; }
|
||||
|
||||
detect_worldserver_bin() {
|
||||
local bin="" es path u units
|
||||
if [[ -n "${FRACTURED_WS_BIN:-}" ]]; then
|
||||
readlink -f "$FRACTURED_WS_BIN" 2>/dev/null && return
|
||||
echo "$FRACTURED_WS_BIN"
|
||||
return
|
||||
fi
|
||||
|
||||
units="${FRACTURED_SYSTEMD_UNITS:-fractured-world worldserver ac-worldserver}"
|
||||
for u in $units; do
|
||||
if systemctl is-active --quiet "$u" 2>/dev/null || systemctl is-enabled --quiet "$u" 2>/dev/null; then
|
||||
es=$(systemctl show "$u" -p ExecStart --value 2>/dev/null || true)
|
||||
if [[ -n "$es" ]]; then
|
||||
if [[ "$es" == \{*path=* ]]; then
|
||||
path=$(printf '%s' "$es" | sed -n 's/.*path=\([^;]*\).*/\1/p')
|
||||
else
|
||||
path=$(printf '%s' "$es" | awk '{print $1}' | sed 's/^path=//')
|
||||
fi
|
||||
if [[ -n "$path" && -x "$path" ]]; then
|
||||
readlink -f "$path" 2>/dev/null && return
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
local pid
|
||||
pid=$(pgrep -xo worldserver 2>/dev/null || true)
|
||||
if [[ -n "$pid" ]]; then
|
||||
readlink -f "/proc/$pid/exe" 2>/dev/null && return
|
||||
fi
|
||||
|
||||
if command -v worldserver >/dev/null 2>&1; then
|
||||
readlink -f "$(command -v worldserver)" 2>/dev/null && return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
guess_worldserver_conf() {
|
||||
local bin="$1"
|
||||
local d cands=()
|
||||
[[ -z "$bin" ]] && return
|
||||
d=$(dirname "$bin")
|
||||
cands+=("$d/../etc/worldserver.conf")
|
||||
cands+=("$d/../../etc/worldserver.conf")
|
||||
cands+=("$HOME/azeroth-server/etc/worldserver.conf")
|
||||
cands+=("$HOME/env/dist/etc/worldserver.conf")
|
||||
for f in "${cands[@]}"; do
|
||||
f=$(readlink -f "$f" 2>/dev/null || true)
|
||||
if [[ -n "$f" && -f "$f" ]]; then
|
||||
echo "$f"
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
binary_strings_paths() {
|
||||
local ws="$1"
|
||||
[[ -z "$ws" || ! -f "$ws" ]] && return
|
||||
strings "$ws" 2>/dev/null | grep -iE '/(home|root|opt|srv|var)[^[:space:]]*/(Fractured|fractured|azeroth|AzerothCore|acore)' | sort -u | head -40
|
||||
}
|
||||
|
||||
hr
|
||||
echo "Fractured Paragon / native VPS diagnostics"
|
||||
echo "Date (UTC): $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "Repo (expected): $REPO"
|
||||
|
||||
sub "1A — worldserver binary"
|
||||
WS=$(detect_worldserver_bin || true)
|
||||
if [[ -z "$WS" ]]; then
|
||||
echo "ERROR: Could not find worldserver. Set FRACTURED_WS_BIN=/full/path/to/worldserver and re-run."
|
||||
else
|
||||
echo "Binary: $WS"
|
||||
if stat -c 'binary mtime: %y' "$WS" 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
stat -f 'binary mtime: %Sm' -t '%Y-%m-%d %H:%M:%S %z' "$WS" 2>/dev/null || stat "$WS"
|
||||
fi
|
||||
fi
|
||||
|
||||
sub "1B — repo HEAD + Paragon_Essence.cpp mtime"
|
||||
if [[ -d "$REPO/.git" ]]; then
|
||||
(cd "$REPO" && git log -1 --format='HEAD commit: %h %ci %s')
|
||||
else
|
||||
echo "WARN: not a git repo: $REPO (set FRACTURED_REPO)"
|
||||
fi
|
||||
PE="$REPO/modules/mod-paragon/src/Paragon_Essence.cpp"
|
||||
if [[ -f "$PE" ]]; then
|
||||
if stat -c 'Paragon_Essence.cpp mtime: %y' "$PE" 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
stat -f 'Paragon_Essence.cpp mtime: %Sm' -t '%Y-%m-%d %H:%M:%S %z' "$PE" 2>/dev/null || stat "$PE"
|
||||
fi
|
||||
else
|
||||
echo "WARN: missing $PE"
|
||||
fi
|
||||
|
||||
sub "1C — strings heuristics (0 can mean stripped binary — use 1A+1B)"
|
||||
if [[ -n "$WS" && -f "$WS" ]]; then
|
||||
c1=$(strings "$WS" 2>/dev/null | grep -c 'CLASS_PARAGON' || true)
|
||||
c2=$(strings "$WS" 2>/dev/null | grep -c 'C BUILD SAVE_CURRENT' || true)
|
||||
c3=$(strings "$WS" 2>/dev/null | grep -c 'character_paragon_build_share_archive' || true)
|
||||
echo "CLASS_PARAGON count: $c1"
|
||||
echo "C BUILD SAVE_CURRENT count: $c2"
|
||||
echo "character_paragon_build_share_archive count: $c3"
|
||||
else
|
||||
echo "(skipped — no binary)"
|
||||
fi
|
||||
|
||||
sub "1D — binary fingerprint (compare sha256 across dev vs VPS)"
|
||||
if [[ -n "$WS" && -f "$WS" ]]; then
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "$WS"
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
shasum -a 256 "$WS"
|
||||
else
|
||||
echo "(no sha256sum — install coreutils)"
|
||||
fi
|
||||
echo "Embedded revision / version strings (first matches):"
|
||||
strings "$WS" 2>/dev/null | grep -iE 'azerothcore|revision|git|commit|build.*20[0-9]{2}' | head -25 || echo "(none matched)"
|
||||
else
|
||||
echo "(skipped — no binary)"
|
||||
fi
|
||||
|
||||
CONF="${FRACTURED_WORLDSERVER_CONF:-}"
|
||||
if [[ -z "$CONF" && -n "$WS" ]]; then
|
||||
CONF=$(guess_worldserver_conf "$WS")
|
||||
fi
|
||||
|
||||
sub "2B — worldserver.conf (updater / source / rates / paragon)"
|
||||
if [[ -n "$CONF" && -f "$CONF" ]]; then
|
||||
echo "Using conf: $CONF"
|
||||
grep -E '^SourceDirectory|^Updates\.EnableDatabases|^Updates\.AutoSetup|^[[:space:]]*SourceDirectory|^[[:space:]]*Updates\.EnableDatabases|^[[:space:]]*Updates\.AutoSetup' "$CONF" 2>/dev/null || echo "(no matching lines or unreadable)"
|
||||
echo "--- Rate.RunicPower (if set) ---"
|
||||
grep -iE '^Rate\.RunicPower|^[[:space:]]*Rate\.RunicPower' "$CONF" 2>/dev/null || echo "(not set — server uses default)"
|
||||
echo "--- Paragon.* module options (if any) ---"
|
||||
grep -iE '^Paragon\.|^[[:space:]]*Paragon\.' "$CONF" 2>/dev/null || echo "(no Paragon.* keys in worldserver.conf — check etc/modules/mod_paragon.conf)"
|
||||
else
|
||||
echo "WARN: worldserver.conf not found. Set FRACTURED_WORLDSERVER_CONF=/path/to/worldserver.conf"
|
||||
fi
|
||||
|
||||
if [[ -n "$WS" && -f "$WS" ]]; then
|
||||
ETCGuess=$(readlink -f "$(dirname "$WS")/../etc" 2>/dev/null || true)
|
||||
MPC="$ETCGuess/modules/mod_paragon.conf"
|
||||
if [[ -f "$MPC" ]]; then
|
||||
sub "2B2 — mod_paragon.conf Paragon.* toggles (non-comment)"
|
||||
grep -E '^Paragon\.' "$MPC" 2>/dev/null | head -40 || echo "(no uncommented Paragon.* lines)"
|
||||
fi
|
||||
fi
|
||||
|
||||
sub "2A — path-like strings from binary (candidate source roots)"
|
||||
if [[ -n "$WS" && -f "$WS" ]]; then
|
||||
binary_strings_paths "$WS" || true
|
||||
else
|
||||
echo "(skipped)"
|
||||
fi
|
||||
|
||||
sub "Resolved source root for 2D"
|
||||
RESOLVED=""
|
||||
if [[ -n "$CONF" && -f "$CONF" ]]; then
|
||||
sd=$(awk -F= '/^[[:space:]]*SourceDirectory[[:space:]]*=/ {
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2);
|
||||
gsub(/^["'\'']|["'\'']$/, "", $2);
|
||||
print $2; exit }' "$CONF" 2>/dev/null || true)
|
||||
if [[ -n "${sd:-}" ]]; then
|
||||
RESOLVED="$sd"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "$RESOLVED" ]]; then
|
||||
RESOLVED="$REPO"
|
||||
fi
|
||||
echo "Using RESOLVED=$RESOLVED (from SourceDirectory if set in conf, else FRACTURED_REPO)"
|
||||
|
||||
sub "2D — Paragon SQL dirs under RESOLVED"
|
||||
for subdir in \
|
||||
"$RESOLVED/modules/mod-paragon/data/sql/db-world/updates/" \
|
||||
"$RESOLVED/modules/mod-paragon/data/sql/db-characters/updates/"; do
|
||||
if [[ -d "$subdir" ]]; then
|
||||
echo "Listing: $subdir"
|
||||
ls -la "$subdir" 2>/dev/null | tail -15
|
||||
else
|
||||
echo "MISSING: $subdir"
|
||||
fi
|
||||
done
|
||||
|
||||
sub "CMake build dir hints (common Fractured layouts)"
|
||||
for cand in "$REPO/var/build/obj" "$REPO/build" "$REPO/../build"; do
|
||||
if [[ -f "$cand/CMakeCache.txt" ]]; then
|
||||
echo "Found CMakeCache: $cand/CMakeCache.txt"
|
||||
grep -E '^CMAKE_HOME_DIRECTORY:|^MODULES:|^CMAKE_INSTALL_PREFIX:' "$cand/CMakeCache.txt" 2>/dev/null | head -5
|
||||
fi
|
||||
done
|
||||
|
||||
sub "DATABASE — updates rows (2026_05_10 / paragon)"
|
||||
SQL_WORLD=$(cat <<'EOS'
|
||||
SELECT name, hash, speed FROM updates
|
||||
WHERE name LIKE '2026_05_10%' OR name LIKE '%paragon%'
|
||||
ORDER BY name DESC LIMIT 30;
|
||||
EOS
|
||||
)
|
||||
SQL_CHAR="$SQL_WORLD"
|
||||
|
||||
if [[ -n "${FRACTURED_MYSQL:-}" ]]; then
|
||||
echo "--- acore_world ---"
|
||||
$FRACTURED_MYSQL acore_world -e "$SQL_WORLD" || echo "(mysql failed for acore_world)"
|
||||
echo "--- acore_characters ---"
|
||||
$FRACTURED_MYSQL acore_characters -e "$SQL_CHAR" || echo "(mysql failed for acore_characters)"
|
||||
|
||||
sub "DATABASE — DBC parity for runes / Paragon (acore_world)"
|
||||
# Common DK rune spenders (WotLK). Override: export FRACTURED_SPELL_IDS='45477 45462'
|
||||
SPELL_IDS="${FRACTURED_SPELL_IDS:-45477 45462 49923 55050 56815}"
|
||||
IDS_CSV=$(echo "$SPELL_IDS" | tr ' ' ',')
|
||||
echo "--- spell_dbc table size (world DB overrides; 0 rows = all spells from disk DBC only) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "SELECT COUNT(*) AS spell_dbc_rows FROM spell_dbc;" 2>/dev/null || echo "(spell_dbc missing or no access)"
|
||||
echo "--- acore_world.version (last core revision written by worldserver) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "SELECT * FROM version LIMIT 5;" 2>/dev/null || echo "(version table missing?)"
|
||||
|
||||
echo "--- chrclasses_dbc class 6 + 12 (DisplayPower: 0=mana, 5=POWER_RUNE in AC) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "
|
||||
SELECT ID, DisplayPower, Name_Lang_enUS FROM chrclasses_dbc WHERE ID IN (6,12);
|
||||
" 2>/dev/null || echo "(query failed — chrclasses_dbc missing?)"
|
||||
echo "Note: If only ID=12 appears, class 6 (DK) is not overridden in DB — loaded from disk DBC (normal)."
|
||||
|
||||
echo "--- spell_dbc: are sample DK spells overridden in DB? ---"
|
||||
spell_sample_n=$($FRACTURED_MYSQL acore_world -N -B -e \
|
||||
"SELECT COUNT(*) FROM spell_dbc WHERE ID IN ($IDS_CSV);" 2>/dev/null || echo 0)
|
||||
echo "Row count in spell_dbc for sample IDs ($SPELL_IDS): ${spell_sample_n:-0}"
|
||||
if [[ "${spell_sample_n:-0}" == "0" ]]; then
|
||||
echo "=> 0 means those spells use on-disk Spell.dbc only; the sample block below will be empty (not an error)."
|
||||
fi
|
||||
echo "--- spell_dbc sample (PowerType 5 = POWER_RUNE in AC) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "
|
||||
SELECT ID, PowerType, ManaCost, RuneCostID FROM spell_dbc WHERE ID IN ($IDS_CSV);
|
||||
" 2>/dev/null || echo "(query failed — spell_dbc missing or wrong schema)"
|
||||
echo "--- spellrunecost join for sample IDs (empty if no spell_dbc rows above) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "
|
||||
SELECT s.ID AS spell_id, s.PowerType, s.RuneCostID, r.Blood, r.Unholy, r.Frost, r.RunicPower
|
||||
FROM spell_dbc s
|
||||
LEFT JOIN spellrunecost_dbc r ON r.ID = s.RuneCostID
|
||||
WHERE s.ID IN ($IDS_CSV);
|
||||
" 2>/dev/null || echo "(join failed — check spellrunecost_dbc)"
|
||||
|
||||
echo "--- spell_dbc suspicious overrides: RuneCostID>0 but PowerType!=5 (can break rune checks) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "
|
||||
SELECT ID, PowerType, ManaCost, RuneCostID FROM spell_dbc
|
||||
WHERE RuneCostID > 0 AND PowerType <> 5
|
||||
ORDER BY ID LIMIT 40;
|
||||
" 2>/dev/null || echo "(query failed)"
|
||||
echo "Compare counts/IDs to dev: unexpected rows here warrant a DB diff."
|
||||
|
||||
echo "--- spell_dbc POWER_RUNE (5) spells with RuneCostID (sample) ---"
|
||||
$FRACTURED_MYSQL acore_world -e "
|
||||
SELECT ID, PowerType, RuneCostID FROM spell_dbc
|
||||
WHERE PowerType = 5 AND RuneCostID > 0
|
||||
ORDER BY ID LIMIT 15;
|
||||
" 2>/dev/null || echo "(query failed)"
|
||||
else
|
||||
echo "FRACTURED_MYSQL not set — run manually (example: export FRACTURED_MYSQL='mysql -uUSER -hHOST')"
|
||||
echo "acore_world:"
|
||||
echo "$SQL_WORLD"
|
||||
echo "acore_characters:"
|
||||
echo "$SQL_CHAR"
|
||||
echo ""
|
||||
echo "Optional DBC parity (acore_world) — run after connecting:"
|
||||
echo " SELECT ID, DisplayPower, Name_Lang_enUS FROM chrclasses_dbc WHERE ID IN (6,12);"
|
||||
echo " SELECT ID, PowerType, ManaCost, RuneCostID FROM spell_dbc WHERE ID IN (45477,45462,49923,55050,56815);"
|
||||
echo " SELECT s.ID, s.RuneCostID, r.Blood, r.Unholy, r.Frost, r.RunicPower FROM spell_dbc s"
|
||||
echo " LEFT JOIN spellrunecost_dbc r ON r.ID = s.RuneCostID WHERE s.ID IN (45477,45462,49923,55050,56815);"
|
||||
fi
|
||||
|
||||
sub "mod_paragon.conf vs .dist (install etc)"
|
||||
ETC=""
|
||||
if [[ -n "$WS" ]]; then
|
||||
ETC=$(readlink -f "$(dirname "$WS")/../etc" 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -z "$ETC" || ! -d "$ETC" ]]; then
|
||||
ETC=$(readlink -f "$HOME/azeroth-server/etc" 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -n "$ETC" && -d "$ETC/modules" ]]; then
|
||||
MP="$ETC/modules/mod_paragon.conf"
|
||||
MPD="$ETC/modules/mod_paragon.conf.dist"
|
||||
if [[ -f "$MP" && -f "$MPD" ]]; then
|
||||
diff -u "$MP" "$MPD" 2>/dev/null | head -80 || true
|
||||
else
|
||||
echo "ETC=$ETC — mod_paragon.conf or .dist missing (MP=$MP MPD=$MPD)"
|
||||
fi
|
||||
else
|
||||
echo "Could not find install etc/modules (set paths manually for diff)."
|
||||
fi
|
||||
|
||||
hr
|
||||
echo "DELIVERABLE for maintainer:"
|
||||
echo "1) Paste 1A–1D (binary mtime, git HEAD, strings, sha256 + revision strings)."
|
||||
echo "2) Paste DATABASE blocks: updates + DBC parity (chrclasses 12, spell_dbc, spellrunecost join)."
|
||||
echo "3) Paste 2A path strings + 2D listings (or MISSING lines)."
|
||||
echo "4) From dev: same 1D sha256 of worldserver OR same SQL block — proves binary/data parity."
|
||||
echo "5) ONE sentence: exact in-game symptom."
|
||||
echo "Done."
|
||||
echo ""
|
||||
echo "Full transcript: $DIAG_OUT"
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# Omit Docker-only paths from the working tree (native VPS / production clones).
|
||||
# Repository root is the AzerothCore tree (flat layout).
|
||||
#
|
||||
# Run from repository root (directory that contains acore.sh and apps/).
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/vps-sparse-checkout-no-docker.sh
|
||||
#
|
||||
# Restore full tree: git sparse-checkout disable
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
if [[ ! -d .git ]]; then
|
||||
echo "error: run from a git clone (no .git in $ROOT)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git sparse-checkout init --no-cone
|
||||
|
||||
cat >.git/info/sparse-checkout <<'EOF'
|
||||
/*
|
||||
!/docker-compose.yml
|
||||
!/docker-compose.override.yml
|
||||
!/apps/docker/
|
||||
!/env/docker-focal-build/
|
||||
!/.devcontainer/
|
||||
EOF
|
||||
|
||||
if git sparse-checkout reapply 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
git read-tree -mu HEAD
|
||||
fi
|
||||
|
||||
echo "Sparse checkout applied (Docker-only paths omitted)."
|
||||
echo "To restore full tree locally: git sparse-checkout disable"
|
||||
Executable
+181
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fractured / AzerothCore — native VPS rolling update (git + compile).
|
||||
#
|
||||
# Run from anywhere; resolves the repository root from this script's location.
|
||||
# Typical production layout: sources in ~/src/Fractured, install prefix in ~/azeroth-server
|
||||
# (see docs/DEPLOY_LINUX_VPS.md).
|
||||
#
|
||||
# What this does:
|
||||
# 1. git pull on the current branch (optional; can skip)
|
||||
# 2. ./acore.sh compiler build — or compiler all for a full clean rebuild
|
||||
#
|
||||
# Database migrations from data/sql/updates/ run when you next start worldserver/authserver
|
||||
# (Updates.* / SourceDirectory in *.conf). This script does not start or stop daemons unless
|
||||
# you pass --run-after or set FRACTURED_POST_UPDATE_CMD.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/vps-update-server.sh
|
||||
# bash scripts/vps-update-server.sh --full
|
||||
# bash scripts/vps-update-server.sh --no-pull
|
||||
# bash scripts/vps-update-server.sh --dry-run
|
||||
# FRACTURED_POST_UPDATE_CMD='sudo systemctl restart fractured-world' bash scripts/vps-update-server.sh --run-after
|
||||
# bash scripts/vps-update-server.sh --run-after 'sudo systemctl restart fractured-world'
|
||||
#
|
||||
# Environment:
|
||||
# FRACTURED_GIT_REMOTE — remote name (default: origin)
|
||||
# FRACTURED_POST_UPDATE_CMD — shell command run after a successful compile (if --run-after is passed without an argument, this is used)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
NO_PULL=0
|
||||
FULL_BUILD=0
|
||||
COMPILE_ONLY=0
|
||||
DRY_RUN=0
|
||||
DO_RUN_AFTER=0
|
||||
POST_UPDATE_CMD="${FRACTURED_POST_UPDATE_CMD:-}"
|
||||
GIT_REMOTE="${FRACTURED_GIT_REMOTE:-origin}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Fractured VPS update — git pull + compiler (see header in script for full notes).
|
||||
|
||||
Usage:
|
||||
bash scripts/vps-update-server.sh [options]
|
||||
|
||||
Options:
|
||||
--no-pull Skip git pull (only compile current tree).
|
||||
--full ./acore.sh compiler all (clean + configure + compile).
|
||||
--compile-only ./acore.sh compiler compile (incremental).
|
||||
--dry-run Print commands without running them.
|
||||
--run-after [CMD] Run shell command after successful compile. If CMD is omitted,
|
||||
uses FRACTURED_POST_UPDATE_CMD from the environment.
|
||||
|
||||
Environment:
|
||||
FRACTURED_GIT_REMOTE Git remote (default: origin).
|
||||
FRACTURED_POST_UPDATE_CMD Used with bare --run-after.
|
||||
EOF
|
||||
}
|
||||
|
||||
run() {
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
printf '[dry-run] '
|
||||
printf '%q ' "$@"
|
||||
printf '\n'
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--no-pull)
|
||||
NO_PULL=1
|
||||
shift
|
||||
;;
|
||||
--full)
|
||||
FULL_BUILD=1
|
||||
shift
|
||||
;;
|
||||
--compile-only)
|
||||
COMPILE_ONLY=1
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
--run-after)
|
||||
DO_RUN_AFTER=1
|
||||
shift
|
||||
if [[ $# -gt 0 && "$1" != -* ]]; then
|
||||
POST_UPDATE_CMD="$1"
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "error: unknown option: $1" >&2
|
||||
echo "Try: bash scripts/vps-update-server.sh --help" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$FULL_BUILD" -eq 1 && "$COMPILE_ONLY" -eq 1 ]]; then
|
||||
echo "error: use only one of --full or --compile-only" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ! -d "$ROOT/.git" ]]; then
|
||||
echo "error: not a git clone: $ROOT" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ROOT/acore.sh" ]]; then
|
||||
echo "error: acore.sh not found under $ROOT" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ROOT/conf/config.sh" ]]; then
|
||||
echo "error: missing $ROOT/conf/config.sh — copy conf/dist/config.sh and edit (see DEPLOY_LINUX_VPS.md)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$ROOT"
|
||||
|
||||
if [[ "$DO_RUN_AFTER" -eq 1 && -z "${POST_UPDATE_CMD// }" ]]; then
|
||||
echo "error: --run-after needs a command or FRACTURED_POST_UPDATE_CMD set in the environment." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
current_branch() {
|
||||
git symbolic-ref -q --short HEAD || git rev-parse --short HEAD
|
||||
}
|
||||
|
||||
if [[ "$NO_PULL" -eq 0 ]]; then
|
||||
ref="$(current_branch)"
|
||||
if [[ "$ref" == "HEAD" ]]; then
|
||||
echo "error: detached HEAD; checkout a branch or use --no-pull." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "==> git pull $GIT_REMOTE $ref"
|
||||
run git pull "$GIT_REMOTE" "$ref"
|
||||
else
|
||||
echo "==> skipping git pull (--no-pull)"
|
||||
fi
|
||||
|
||||
echo "==> ensuring acore.sh and JSONPath are executable"
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
run chmod +x acore.sh deps/jsonpath/JSONPath.sh
|
||||
else
|
||||
chmod +x acore.sh deps/jsonpath/JSONPath.sh 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [[ "$FULL_BUILD" -eq 1 ]]; then
|
||||
echo "==> ./acore.sh compiler all (clean, configure, compile)"
|
||||
run ./acore.sh compiler all
|
||||
elif [[ "$COMPILE_ONLY" -eq 1 ]]; then
|
||||
echo "==> ./acore.sh compiler compile (incremental; build dir must exist)"
|
||||
run ./acore.sh compiler compile
|
||||
else
|
||||
echo "==> ./acore.sh compiler build (configure + compile)"
|
||||
run ./acore.sh compiler build
|
||||
fi
|
||||
|
||||
if [[ "$DO_RUN_AFTER" -eq 1 ]]; then
|
||||
echo "==> post-update: $POST_UPDATE_CMD"
|
||||
if [[ "$DRY_RUN" -eq 1 ]]; then
|
||||
printf '[dry-run] eval %q\n' "$POST_UPDATE_CMD"
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
eval "$POST_UPDATE_CMD"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Done. Restart authserver/worldserver (or your service manager) when ready so new binaries and SQL updates apply."
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Rebuild acore_world from data/sql/base/db_world only (AzerothCore "shortcut"):
|
||||
# the shipped base `updates` table already records archived migrations as applied,
|
||||
# so worldserver only needs to run pending files under data/sql/updates/db_world
|
||||
# (and your custom/pending paths if used).
|
||||
#
|
||||
# Usage:
|
||||
# export MYSQL_PWD='...'
|
||||
# ./scripts/world-db-from-base.sh -h 10.0.13.252 -u acore -D acore_world
|
||||
#
|
||||
# Requires: mysql client. Optional: pass --force to skip confirmation.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 -h HOST -u USER -D DATABASE [--port PORT] [--force]" >&2
|
||||
echo " Or set: MYSQL_HOST MYSQL_USER MYSQL_DATABASE [MYSQL_PWD in env]" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
HOST="${MYSQL_HOST:-}"
|
||||
USER="${MYSQL_USER:-}"
|
||||
DBNAME="${MYSQL_DATABASE:-}"
|
||||
PORT="${MYSQL_PORT:-3306}"
|
||||
FORCE=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h) HOST="$2"; shift 2 ;;
|
||||
-u) USER="$2"; shift 2 ;;
|
||||
-D) DBNAME="$2"; shift 2 ;;
|
||||
--port) PORT="$2"; shift 2 ;;
|
||||
--force) FORCE=1; shift ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
: "${HOST:?set -h or MYSQL_HOST}"
|
||||
: "${USER:?set -u or MYSQL_USER}"
|
||||
: "${DBNAME:?set -D or MYSQL_DATABASE}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
BASE_DIR="$REPO_ROOT/data/sql/base/db_world"
|
||||
|
||||
if [[ ! -d "$BASE_DIR" ]]; then
|
||||
echo "Base directory not found: $BASE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FORCE" -ne 1 ]]; then
|
||||
read -r -p "DESTROY database '$DBNAME' on $HOST and rebuild from base? [yes/no]: " ans
|
||||
[[ "$ans" == "yes" ]] || { echo "Aborted."; exit 1; }
|
||||
fi
|
||||
|
||||
MYSQL=(mysql -h "$HOST" -P "$PORT" -u "$USER" --protocol=tcp)
|
||||
"${MYSQL[@]}" -e "DROP DATABASE IF EXISTS \`$DBNAME\`; CREATE DATABASE \`$DBNAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||
|
||||
mapfile -t SQL_FILES < <(find "$BASE_DIR" -maxdepth 1 -name '*.sql' -printf '%f\n' | sort)
|
||||
|
||||
for f in "${SQL_FILES[@]}"; do
|
||||
echo ">> $f"
|
||||
"${MYSQL[@]}" "$DBNAME" <"$BASE_DIR/$f"
|
||||
done
|
||||
|
||||
echo ">> Done. Start worldserver once; it should report World DB up-to-date or only apply updates/db_world."
|
||||
@@ -17,10 +17,16 @@
|
||||
|
||||
#include "ARC4.h"
|
||||
#include "Errors.h"
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
Acore::Crypto::ARC4::ARC4() : _ctx(EVP_CIPHER_CTX_new())
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
_cipher = EVP_CIPHER_fetch(nullptr, "RC4", nullptr);
|
||||
#else
|
||||
_cipher = const_cast<EVP_CIPHER*>(EVP_rc4());
|
||||
#endif
|
||||
ASSERT(_cipher);
|
||||
|
||||
EVP_CIPHER_CTX_init(_ctx);
|
||||
int result = EVP_EncryptInit_ex(_ctx, _cipher, nullptr, nullptr, nullptr);
|
||||
@@ -30,7 +36,9 @@ Acore::Crypto::ARC4::ARC4() : _ctx(EVP_CIPHER_CTX_new())
|
||||
Acore::Crypto::ARC4::~ARC4()
|
||||
{
|
||||
EVP_CIPHER_CTX_free(_ctx);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
EVP_CIPHER_free(_cipher);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Acore::Crypto::ARC4::Init(uint8 const* seed, std::size_t len)
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
#include "OpenSSLCrypto.h"
|
||||
#include <openssl/crypto.h> // NOTE: this import is NEEDED (even though some IDEs report it as unused)
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include <openssl/provider.h>
|
||||
|
||||
OSSL_PROVIDER* LegacyProvider;
|
||||
@@ -53,3 +56,10 @@ void OpenSSLCrypto::threadsCleanup()
|
||||
OSSL_PROVIDER_unload(DefaultProvider);
|
||||
OSSL_PROVIDER_set_default_search_path(nullptr, nullptr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void OpenSSLCrypto::threadsSetup() {}
|
||||
void OpenSSLCrypto::threadsCleanup() {}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,12 @@ MaxPingTime = 30
|
||||
|
||||
#
|
||||
# RealmServerPort
|
||||
# Description: TCP port to reach the auth server.
|
||||
# Description: TCP port the auth server listens on (login handshake).
|
||||
# 3724 is the stock WoW default; clients with `set realmlist <host>`
|
||||
# (no port) connect here. Production deployments that cannot bind
|
||||
# 3724 (NAT, conflicting service, etc.) can set this to e.g. 47497
|
||||
# and have clients use `set realmlist <host>:47497` -- the
|
||||
# Fractured-patched Wow.exe supports the host:port syntax.
|
||||
# Default: 3724
|
||||
|
||||
RealmServerPort = 3724
|
||||
|
||||
@@ -4767,6 +4767,36 @@ Respawn.DynamicEscortNPC = 0
|
||||
|
||||
Respawn.ForceCompatibilityMode = 0
|
||||
|
||||
#
|
||||
# Paragon.WildcardFamilyMatching
|
||||
# Description: Fractured / Paragon class (CLASS_PARAGON, id 12) only.
|
||||
# When enabled, the SpellFamilyName equality check is
|
||||
# wildcarded for Paragon characters in proc evaluation
|
||||
# (SpellMgr::CanSpellTriggerProcOnEvent), talent
|
||||
# SpellMod application (Player::ApplySpellMod /
|
||||
# SpellInfo::IsAffectedBySpellMod), and the
|
||||
# ParagonFamilyMatches() helper used by ad-hoc
|
||||
# `switch (SpellFamilyName)` listener gates in
|
||||
# Unit/SpellEffects/SpellAuraEffects code.
|
||||
# This makes cross-class talent procs and modifiers
|
||||
# (e.g. Predator's Swiftness 69369 making Shaman
|
||||
# Chain Lightning instant cast off a Rogue Eviscerate
|
||||
# finisher) apply to Paragon characters even when the
|
||||
# listener was authored for one specific class family.
|
||||
# SpellFamilyFlags / class-mask flag-bit checks still
|
||||
# run, so listener gates that explicitly opt into a
|
||||
# subset of spells via flag bits are still respected.
|
||||
# Stock classes (Warrior / Paladin / etc.) are NEVER
|
||||
# wildcarded; this only affects players whose class
|
||||
# id is CLASS_PARAGON. Set to 0 to disable the
|
||||
# wildcard at runtime (no rebuild required) if a
|
||||
# regression appears.
|
||||
# Default: 1 - (Enabled, Paragon characters get cross-class procs/mods)
|
||||
# 0 - (Disabled, Paragon characters are gated by stock family equality)
|
||||
#
|
||||
|
||||
Paragon.WildcardFamilyMatching = 1
|
||||
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "SQLOperation.h"
|
||||
#include "Transaction.h"
|
||||
#include "WorldDatabase.h"
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <mysqld_error.h>
|
||||
#include <sstream>
|
||||
@@ -59,10 +60,18 @@ DatabaseWorkerPool<T>::DatabaseWorkerPool() :
|
||||
{
|
||||
WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
|
||||
|
||||
bool isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION;
|
||||
bool isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID;
|
||||
bool isSupportClientDB;
|
||||
bool isSameClientDB;
|
||||
#ifdef MARIADB_VERSION_ID
|
||||
isSupportClientDB = (MARIADB_VERSION_ID >= MIN_MARIADB_CLIENT_VERSION_ID);
|
||||
// MariaDB packages often differ between build host and runtime; strict id match is too brittle.
|
||||
isSameClientDB = true;
|
||||
#else
|
||||
isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION;
|
||||
isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID;
|
||||
#endif
|
||||
|
||||
WPFatal(isSupportClientDB, "AzerothCore does not support MySQL versions below 8.0\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).",
|
||||
WPFatal(isSupportClientDB, "AzerothCore does not support this database client library.\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).",
|
||||
mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
|
||||
WPFatal(isSameClientDB, "Used MySQL library version ({} id {}) does not match the version id used to compile AzerothCore (id {}).\nSearch the wiki for ACE00046 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00046).",
|
||||
mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
|
||||
@@ -386,32 +395,65 @@ void DatabaseWorkerPool<T>::KeepAlive()
|
||||
*/
|
||||
bool DatabaseIncompatibleVersion(std::string const mysqlVersion)
|
||||
{
|
||||
// anon func to turn a version string into an array of uint8
|
||||
// "1.2.3" => [1, 2, 3]
|
||||
auto parse = [](std::string const& input)
|
||||
auto parseTriplet = [](std::string const& input) -> std::array<unsigned, 3>
|
||||
{
|
||||
std::vector<uint8> result;
|
||||
std::istringstream parser(input);
|
||||
result.push_back(parser.get());
|
||||
for (int i = 1; i < 3; i++)
|
||||
std::array<unsigned, 3> v = { 0, 0, 0 };
|
||||
size_t idx = 0;
|
||||
std::string num;
|
||||
for (char ch : input)
|
||||
{
|
||||
// Skip period
|
||||
parser.get();
|
||||
// Append int from parser to output
|
||||
result.push_back(parser.get());
|
||||
if (ch >= '0' && ch <= '9')
|
||||
num.push_back(ch);
|
||||
else if (ch == '.')
|
||||
{
|
||||
if (!num.empty() && idx < 3)
|
||||
{
|
||||
v[idx++] = static_cast<unsigned>(std::stoul(num));
|
||||
num.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
if (!num.empty() && idx < 3)
|
||||
v[idx] = static_cast<unsigned>(std::stoul(num));
|
||||
return v;
|
||||
};
|
||||
|
||||
// default to values for MySQL
|
||||
uint8 offset = 0;
|
||||
auto compareVersion = [](std::array<unsigned, 3> const& a, std::array<unsigned, 3> const& b) -> int
|
||||
{
|
||||
if (a[0] != b[0])
|
||||
return (a[0] < b[0]) ? -1 : 1;
|
||||
if (a[1] != b[1])
|
||||
return (a[1] < b[1]) ? -1 : 1;
|
||||
if (a[2] != b[2])
|
||||
return (a[2] < b[2]) ? -1 : 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
std::string ver = mysqlVersion;
|
||||
std::string minVersion = MIN_MYSQL_SERVER_VERSION;
|
||||
|
||||
auto parsedMySQLVersion = parse(mysqlVersion.substr(offset));
|
||||
auto parsedMinVersion = parse(minVersion);
|
||||
// MariaDB: version string may be:
|
||||
// - "5.5.5-10.6.11-MariaDB-1:10.6.11+maria~..." (MySQL wire compat prefix)
|
||||
// - "10.6.11-MariaDB-1:10.6.11+maria~..." (no 5.5.5- prefix)
|
||||
// parseTriplet() on the full second form stops at the first '-', yielding 10.6.11.
|
||||
// Never take "firstDash..secondDash" — that becomes "MariaDB" and compares as 0.0.0.
|
||||
if (ver.find("MariaDB") != std::string::npos)
|
||||
{
|
||||
minVersion = MIN_MARIADB_SERVER_VERSION;
|
||||
if (ver.compare(0, 6, "5.5.5-") == 0)
|
||||
{
|
||||
size_t const afterPrefix = 6;
|
||||
size_t const nextDash = ver.find('-', afterPrefix);
|
||||
if (nextDash != std::string::npos)
|
||||
ver = ver.substr(afterPrefix, nextDash - afterPrefix);
|
||||
else
|
||||
ver = ver.substr(afterPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
return std::lexicographical_compare(parsedMySQLVersion.begin(), parsedMySQLVersion.end(),
|
||||
parsedMinVersion.begin(), parsedMinVersion.end());
|
||||
return compareVersion(parseTriplet(ver), parseTriplet(minVersion)) < 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -442,7 +484,7 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne
|
||||
}
|
||||
else if (DatabaseIncompatibleVersion(connection->GetServerInfo()))
|
||||
{
|
||||
LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 8.0\n\nFound server version: {}. Server compiled with: {}.",
|
||||
LOG_ERROR("sql.driver", "Database server version is too old.\n\nFound server version: {}. Client library compile id: {}.",
|
||||
connection->GetServerInfo(), MYSQL_VERSION_ID);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,24 @@
|
||||
*/
|
||||
#define MIN_MYSQL_CLIENT_VERSION 80000u
|
||||
|
||||
/**
|
||||
* @def MIN_MARIADB_CLIENT_VERSION_ID
|
||||
* Minimum MariaDB connector MARIADB_VERSION_ID (10.4.0 => 100400)
|
||||
*/
|
||||
#define MIN_MARIADB_CLIENT_VERSION_ID 100400u
|
||||
|
||||
/**
|
||||
* @def MIN_MYSQL_SERVER_VERSION
|
||||
* The minimum MySQL Server Version
|
||||
*/
|
||||
#define MIN_MYSQL_SERVER_VERSION "8.0.0"
|
||||
|
||||
/**
|
||||
* @def MIN_MARIADB_SERVER_VERSION
|
||||
* Minimum MariaDB server (version triplet after the 5.5.5- compatibility prefix)
|
||||
*/
|
||||
#define MIN_MARIADB_SERVER_VERSION "10.4.0"
|
||||
|
||||
template <typename T>
|
||||
class ProducerConsumerQueue;
|
||||
|
||||
|
||||
@@ -129,13 +129,17 @@ uint32 MySQLConnection::Open()
|
||||
|
||||
if (m_connectionInfo.ssl != "")
|
||||
{
|
||||
#ifdef MARIADB_VERSION_ID
|
||||
my_bool const ssl_enforce = (m_connectionInfo.ssl == "ssl") ? 1 : 0;
|
||||
if (ssl_enforce)
|
||||
mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, &ssl_enforce);
|
||||
#else
|
||||
mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
|
||||
if (m_connectionInfo.ssl == "ssl")
|
||||
{
|
||||
opt_use_ssl = SSL_MODE_REQUIRED;
|
||||
}
|
||||
|
||||
mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl);
|
||||
#endif
|
||||
}
|
||||
|
||||
m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
|
||||
@@ -216,7 +220,7 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
|
||||
|
||||
uint32 _s = getMSTime();
|
||||
|
||||
#if MYSQL_VERSION_ID >= 80300
|
||||
#if MYSQL_VERSION_ID >= 80300 && !defined(MARIADB_VERSION_ID)
|
||||
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
|
||||
#else
|
||||
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
|
||||
@@ -268,7 +272,7 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement
|
||||
|
||||
uint32 _s = getMSTime();
|
||||
|
||||
#if MYSQL_VERSION_ID >= 80300
|
||||
#if MYSQL_VERSION_ID >= 80300 && !defined(MARIADB_VERSION_ID)
|
||||
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
|
||||
#else
|
||||
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
|
||||
|
||||
@@ -669,7 +669,12 @@ bool AuctionHouseUsablePlayerInfo::PlayerCanUseItem(ItemTemplate const* proto) c
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((proto->AllowableClass & classMask) == 0 || (proto->AllowableRace & raceMask) == 0)
|
||||
// mod-paragon: class 12 (Paragon) ignores AllowableClass for AH "Usable"
|
||||
// filter. classMask here is the searching player's mask; PARAGON_BIT 0x800
|
||||
// = (1 << (12 - 1)). Race restriction still applies.
|
||||
bool const searcherIsParagon = (classMask & 0x800u) != 0;
|
||||
if ((!searcherIsParagon && (proto->AllowableClass & classMask) == 0)
|
||||
|| (proto->AllowableRace & raceMask) == 0)
|
||||
return false;
|
||||
|
||||
if (proto->RequiredSkill != 0)
|
||||
|
||||
@@ -208,6 +208,46 @@ namespace Trainer
|
||||
|
||||
bool Trainer::IsTrainerValidForPlayer(Player const* player) const
|
||||
{
|
||||
// Paragon (class 12) learns class abilities exclusively through the
|
||||
// Character Advancement panel (mod-paragon). Generic class trainers
|
||||
// refuse interaction. Pet trainers, mount/profession trainers, and
|
||||
// specialized portal/teleport trainers (mage portal NPCs) stay valid:
|
||||
// - Pet trainers: pet-skill purchases for hunter pets aren't covered
|
||||
// by the panel and should remain trainer-driven.
|
||||
// - Portal/teleport trainers: identified at runtime as a Class-type
|
||||
// trainer whose spells are ALL TELEPORT_UNITS or TRANS_DOOR
|
||||
// effects. The big general mage trainer fails this check (it
|
||||
// teaches Fireball, Frostbolt, etc.) and is correctly blocked.
|
||||
if (player && player->getClass() == CLASS_PARAGON
|
||||
&& GetTrainerType() == Type::Class
|
||||
&& !_spells.empty())
|
||||
{
|
||||
bool onlyPortalsAndTeleports = true;
|
||||
for (Spell const& s : _spells)
|
||||
{
|
||||
SpellInfo const* info = sSpellMgr->GetSpellInfo(s.SpellId);
|
||||
if (!info)
|
||||
continue;
|
||||
bool isPortalOrTeleport = false;
|
||||
for (SpellEffectInfo const& eff : info->GetEffects())
|
||||
{
|
||||
if (eff.Effect == SPELL_EFFECT_TELEPORT_UNITS
|
||||
|| eff.Effect == SPELL_EFFECT_TRANS_DOOR)
|
||||
{
|
||||
isPortalOrTeleport = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isPortalOrTeleport)
|
||||
{
|
||||
onlyPortalsAndTeleports = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!onlyPortalsAndTeleports)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetTrainerRequirement())
|
||||
return true;
|
||||
|
||||
|
||||
@@ -7143,6 +7143,16 @@ bool Player::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEf
|
||||
if (spellInfo->EquippedItemClass == -1)
|
||||
return true;
|
||||
|
||||
// Fractured / Paragon: cross-class wildcard relaxes weapon-class subclass
|
||||
// gates on per-swing proc matches. A Paragon's talent list spans every
|
||||
// class so a stock weapon-subclass mask (e.g. Maelstrom Weapon's
|
||||
// axe/mace/staff/fist/dagger restriction) excludes weapons the player
|
||||
// can legitimately wield. Accept any equipped weapon in attackType slot
|
||||
// when listener is a Paragon AND the spell gates on ITEM_CLASS_WEAPON;
|
||||
// ITEM_CLASS_ARMOR (shield) gates still enforce the original mask.
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && IsParagonWildcardCaller(this))
|
||||
return GetWeaponForAttack(attackType, true) != nullptr;
|
||||
|
||||
Item* item = GetWeaponForAttack(attackType, true);
|
||||
if (!item || !item->IsFitToSpellRequirements(spellInfo))
|
||||
return false;
|
||||
@@ -7208,7 +7218,7 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply,
|
||||
return;
|
||||
|
||||
// Cannot be used in this stance/form
|
||||
if (spellInfo->CheckShapeshift(GetShapeshiftForm()) != SPELL_CAST_OK)
|
||||
if (spellInfo->CheckShapeshift(GetShapeshiftForm(), this) != SPELL_CAST_OK)
|
||||
return;
|
||||
|
||||
if (form_change) // check aura active state from other form
|
||||
@@ -7228,7 +7238,7 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply,
|
||||
if (form_change) // check aura compatibility
|
||||
{
|
||||
// Cannot be used in this stance/form
|
||||
if (spellInfo->CheckShapeshift(GetShapeshiftForm()) == SPELL_CAST_OK)
|
||||
if (spellInfo->CheckShapeshift(GetShapeshiftForm(), this) == SPELL_CAST_OK)
|
||||
return; // and remove only not compatible at form change
|
||||
}
|
||||
|
||||
@@ -9773,7 +9783,11 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod
|
||||
if (mod->op == SPELLMOD_DURATION && spellInfo->GetDuration() == -1)
|
||||
return false;
|
||||
|
||||
return spellInfo->IsAffectedBySpellMod(mod);
|
||||
// Fractured / Paragon: pass the player owning the modifier aura so the
|
||||
// SpellFamilyName equality check can be wildcarded for CLASS_PARAGON.
|
||||
// Stock classes hit the same code path with `this` as a non-Paragon
|
||||
// unit, which makes IsAffected behave identically to the 2-arg form.
|
||||
return spellInfo->IsAffectedBySpellMod(mod, this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -10687,7 +10701,12 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(pProto->AllowableClass & getClassMask()) && pProto->Bonding == BIND_WHEN_PICKED_UP && !IsGameMaster())
|
||||
// mod-paragon: class 12 ignores BoP buy-side AllowableClass gate, so
|
||||
// class-restricted vendor items (e.g. class glyphs) can be purchased.
|
||||
if (getClass() != CLASS_PARAGON
|
||||
&& !(pProto->AllowableClass & getClassMask())
|
||||
&& pProto->Bonding == BIND_WHEN_PICKED_UP
|
||||
&& !IsGameMaster())
|
||||
{
|
||||
SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0);
|
||||
return false;
|
||||
@@ -12012,6 +12031,28 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
|
||||
uint32 raceMask = getRaceMask();
|
||||
uint32 classMask = getClassMask();
|
||||
|
||||
// Fractured / Paragon: the Character Advancement panel is the sole
|
||||
// authority over which class abilities a Paragon owns. The skill-line
|
||||
// cascade re-fires from _LoadSkills (every login), UpdateSkillsForLevel
|
||||
// (every level-up), UpdateSkillPro (every weapon-skill tick on a
|
||||
// training dummy), and SetSkill (first time a class skill is granted).
|
||||
// Each of those re-grants every SLA-tagged class ability on the
|
||||
// matching skill line — leaking Blood Presence / Death Coil / Death
|
||||
// Grip / etc. back into the spellbook within seconds even after the
|
||||
// player intentionally refunded them via the panel. Skip the cascade
|
||||
// for class-category skill lines on Paragon characters; mod-paragon
|
||||
// calls Player::learnSpell directly for the abilities the player
|
||||
// actually purchased, including their attached passives. Profession,
|
||||
// weapon, language, and racial skill cascades stay enabled so things
|
||||
// like recipe auto-learn, weapon proficiencies, and racial perks
|
||||
// still work.
|
||||
if (getClass() == CLASS_PARAGON)
|
||||
{
|
||||
if (SkillLineEntry const* sl = sSkillLineStore.LookupEntry(skill_id))
|
||||
if (sl->categoryId == SKILL_CATEGORY_CLASS)
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all abilities for this skill and sort by MinSkillLineRank (lowest to highest)
|
||||
auto abilities = GetSkillLineAbilitiesBySkillLine(skill_id);
|
||||
std::vector<SkillLineAbilityEntry const*> sortedAbilities(abilities.begin(), abilities.end());
|
||||
@@ -12550,6 +12591,27 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons
|
||||
if (spellInfo->EquippedItemClass < 0)
|
||||
return true;
|
||||
|
||||
// Fractured / Paragon: cross-class wildcard relaxes weapon-class subclass
|
||||
// gates so passive talent auras (e.g. Maelstrom Weapon talents 51528-51532)
|
||||
// attach for any equipped weapon, not just the talent's restrictive
|
||||
// subclass mask. Mirrors CheckAttackFitToAuraRequirement so per-swing
|
||||
// proc match agrees with talent-attach time. Still requires *some* weapon
|
||||
// to be equipped (otherwise unarmed Paragons would auto-activate every
|
||||
// weapon-gated talent in the game). ITEM_CLASS_ARMOR (shield) is left
|
||||
// alone -- shield-gated talents still need an actual shield.
|
||||
if (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && IsParagonWildcardCaller(this))
|
||||
{
|
||||
for (uint8 i = EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i)
|
||||
if (Item const* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
if (item != ignoreItem)
|
||||
if (ItemTemplate const* proto = item->GetTemplate())
|
||||
if (proto->Class == ITEM_CLASS_WEAPON)
|
||||
return true;
|
||||
// No weapon equipped at all -- fall through to stock logic, which
|
||||
// returns false for passive talent auras (correct: an unarmed
|
||||
// Paragon shouldn't have weapon talents active).
|
||||
}
|
||||
|
||||
// scan other equipped items for same requirements (mostly 2 daggers/etc)
|
||||
// for optimize check 2 used cases only
|
||||
switch (spellInfo->EquippedItemClass)
|
||||
@@ -14052,7 +14114,10 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank, bool command /*= fa
|
||||
return;
|
||||
|
||||
// xinef: prevent learn talent for different class (cheating)
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
// mod-paragon: Paragon (class 12) can spec into any class's talent tree
|
||||
// via the Character Advancement panel; bypass the class-mask check.
|
||||
if (getClass() != CLASS_PARAGON
|
||||
&& (getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
return;
|
||||
|
||||
// xinef: find current talent rank
|
||||
@@ -14081,7 +14146,12 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank, bool command /*= fa
|
||||
}
|
||||
|
||||
// xinef: check if talent deponds on another talent
|
||||
if (talentInfo->DependsOn > 0)
|
||||
// mod-paragon: Character Advancement gates talents by AE/TE essence cost,
|
||||
// not by the column-arrow prereq from Blizzard's spec UI. For class 12
|
||||
// (Paragon) we skip the DependsOn check so e.g. Deep Wounds, Bloody
|
||||
// Vengeance and Expose Weakness can be picked without first speccing into
|
||||
// their unrelated prereq sibling.
|
||||
if (talentInfo->DependsOn > 0 && getClass() != CLASS_PARAGON)
|
||||
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||
{
|
||||
bool hasEnoughRank = false;
|
||||
|
||||
@@ -2364,7 +2364,16 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
}
|
||||
|
||||
if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
|
||||
// mod-paragon: class 12 (Paragon) ignores AllowableClass entirely, so any
|
||||
// class-restricted item (including class glyphs) can be equipped/used.
|
||||
// Race restriction still applies; proficiency/level/skill checks below
|
||||
// still gate it sensibly via the standard skill cascade.
|
||||
if (getClass() != CLASS_PARAGON
|
||||
&& (proto->AllowableClass & getClassMask()) == 0)
|
||||
{
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
}
|
||||
if ((proto->AllowableRace & getRaceMask()) == 0)
|
||||
{
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
}
|
||||
@@ -2430,7 +2439,11 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje
|
||||
SKILL_FISHING
|
||||
}; //Copy from function Item::GetSkill()
|
||||
|
||||
if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
|
||||
// mod-paragon: class 12 ignores AllowableClass for LFG roll eligibility.
|
||||
if (getClass() != CLASS_PARAGON
|
||||
&& (proto->AllowableClass & getClassMask()) == 0)
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
if ((proto->AllowableRace & getRaceMask()) == 0)
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
|
||||
if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell))
|
||||
|
||||
@@ -385,6 +385,13 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (getClass() == CLASS_PARAGON)
|
||||
{
|
||||
// Fractured class 12: same hybrid curve as requested for Paragon UI
|
||||
// (level*2 + AGI + STR - 20). Implemented in core so we do not rely
|
||||
// on PlayerScript hooks in this hot path.
|
||||
val2 = level * 2.0f + GetStat(STAT_AGILITY) + GetStat(STAT_STRENGTH) - 20.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
val2 = GetStat(STAT_AGILITY) - 10.0f;
|
||||
@@ -481,6 +488,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (getClass() == CLASS_PARAGON)
|
||||
{
|
||||
val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
|
||||
}
|
||||
else if (IsClass(CLASS_MAGE, CLASS_CONTEXT_STATS) || IsClass(CLASS_PRIEST, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARLOCK, CLASS_CONTEXT_STATS))
|
||||
{
|
||||
val2 = GetStat(STAT_STRENGTH) - 10.0f;
|
||||
|
||||
@@ -72,11 +72,37 @@
|
||||
#include "Util.h"
|
||||
#include "Vehicle.h"
|
||||
#include "World.h"
|
||||
#include "WorldConfig.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
// Fractured / Paragon: single source of truth for the runtime "is this
|
||||
// caller eligible for the cross-class wildcard?" question. Centralizing
|
||||
// here keeps every dependent behavior (family-name skip in
|
||||
// SpellInfo::IsAffected, PERIODIC_LEECH disease counting in
|
||||
// GetDiseasesByCaster, instant-cast intercept in Spell::prepare for
|
||||
// Predator's / Nature's Swiftness, Vampiric Embrace CheckProc cross-family
|
||||
// path, etc.) flipping in lockstep when the config flag is toggled.
|
||||
bool IsParagonWildcardCaller(Unit const* listener)
|
||||
{
|
||||
return listener && listener->getClass() == CLASS_PARAGON
|
||||
&& sWorld->getBoolConfig(CONFIG_PARAGON_WILDCARD_FAMILY);
|
||||
}
|
||||
|
||||
// Fractured / Paragon: cross-class wildcard helper used by ad-hoc
|
||||
// `switch (SpellFamilyName)` listener gates in Unit / SpellEffects /
|
||||
// SpellAuraEffects. Returns true when the listener is a CLASS_PARAGON
|
||||
// player and the wildcard config flag is enabled, otherwise falls back
|
||||
// to strict family-name equality.
|
||||
bool ParagonFamilyMatches(Unit const* listener, uint32 expectedFamily, uint32 actualFamily)
|
||||
{
|
||||
if (IsParagonWildcardCaller(listener))
|
||||
return true;
|
||||
return expectedFamily == actualFamily;
|
||||
}
|
||||
|
||||
float baseMoveSpeed[MAX_MOVE_TYPE] =
|
||||
{
|
||||
2.5f, // MOVE_WALK
|
||||
@@ -6122,17 +6148,40 @@ AuraEffect* Unit::IsScriptOverriden(SpellInfo const* spell, int32 script) const
|
||||
|
||||
uint32 Unit::GetDiseasesByCaster(ObjectGuid casterGUID, uint8 mode)
|
||||
{
|
||||
static const AuraType diseaseAuraTypes[] =
|
||||
ObjectGuid drwGUID;
|
||||
|
||||
// Fractured / Paragon: when the caller (the unit whose strike is
|
||||
// counting diseases -- e.g. Death Strike heal, Blood Strike / Heart
|
||||
// Strike / Obliterate per-disease damage, Glyph of Scourge Strike
|
||||
// refresh) is a CLASS_PARAGON player AND Paragon.WildcardFamilyMatching
|
||||
// is on, also walk SPELL_AURA_PERIODIC_LEECH. That picks up Priest
|
||||
// Devouring Plague, which uses ApplyAuraName 53 (PERIODIC_LEECH) instead
|
||||
// of 3 (PERIODIC_DAMAGE) and is therefore invisible to the stock loop
|
||||
// even though its Dispel field is DISPEL_DISEASE. A full Spell.dbc scan
|
||||
// confirms Devouring Plague is the ONLY entry that satisfies both
|
||||
// `Dispel == DISPEL_DISEASE` and a leech periodic effect, so this does
|
||||
// not accidentally drag any other spell into the disease pool. Stock
|
||||
// (non-Paragon) callers fall through to the original 2-entry iteration
|
||||
// and observe identical behavior.
|
||||
bool paragonWildcardLeech = false;
|
||||
if (Player* playerCaster = ObjectAccessor::GetPlayer(*this, casterGUID))
|
||||
{
|
||||
drwGUID = playerCaster->getRuneWeaponGUID();
|
||||
paragonWildcardLeech = IsParagonWildcardCaller(playerCaster);
|
||||
}
|
||||
|
||||
AuraType diseaseAuraTypes[4] =
|
||||
{
|
||||
SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
|
||||
SPELL_AURA_LINKED, // Crypt Fever and Ebon Plague
|
||||
SPELL_AURA_NONE,
|
||||
SPELL_AURA_NONE
|
||||
};
|
||||
|
||||
ObjectGuid drwGUID;
|
||||
|
||||
if (Player* playerCaster = ObjectAccessor::GetPlayer(*this, casterGUID))
|
||||
drwGUID = playerCaster->getRuneWeaponGUID();
|
||||
if (paragonWildcardLeech)
|
||||
{
|
||||
diseaseAuraTypes[2] = SPELL_AURA_PERIODIC_LEECH; // Priest Devouring Plague (Paragon-only)
|
||||
diseaseAuraTypes[3] = SPELL_AURA_NONE;
|
||||
}
|
||||
|
||||
uint32 diseases = 0;
|
||||
for (uint8 index = 0; diseaseAuraTypes[index] != SPELL_AURA_NONE; ++index)
|
||||
@@ -9046,6 +9095,21 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
|
||||
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
|
||||
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellDamageBonus();
|
||||
|
||||
// Fractured class 12 (Paragon) intrinsic spell power:
|
||||
// SP = level*2 + INT + SPI - 20 (clamped at 0)
|
||||
// Read live from current stats so character-sheet refreshes (via
|
||||
// UpdateSpellDamageAndHealingBonus) and live spell casts both see the
|
||||
// up-to-date value with no script hooks or m_baseSpellPower mutation.
|
||||
if (ToPlayer()->getClass() == CLASS_PARAGON)
|
||||
{
|
||||
int32 paragonSP = int32(GetLevel()) * 2
|
||||
+ int32(GetStat(STAT_INTELLECT))
|
||||
+ int32(GetStat(STAT_SPIRIT))
|
||||
- 20;
|
||||
if (paragonSP > 0)
|
||||
DoneAdvertisedBenefit += paragonSP;
|
||||
}
|
||||
|
||||
// Damage bonus from stats
|
||||
AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
|
||||
for (AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i)
|
||||
@@ -9687,7 +9751,7 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u
|
||||
|
||||
// Nourish cast - 20% bonus if target has Rejuvenation, Regrowth, Lifebloom, or Wild Growth from caster
|
||||
// Glyph of Nourish is handled by spell_dru_nourish script
|
||||
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000 && caster)
|
||||
if (ParagonFamilyMatches(caster, SPELLFAMILY_DRUID, spellProto->SpellFamilyName) && spellProto->SpellFamilyFlags[1] & 0x2000000 && caster)
|
||||
{
|
||||
AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
|
||||
for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
|
||||
@@ -9803,6 +9867,20 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
|
||||
AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
|
||||
AdvertisedBenefit += ToPlayer()->GetBaseSpellHealingBonus();
|
||||
|
||||
// Fractured class 12 (Paragon) intrinsic spell power: same level*2 +
|
||||
// INT + SPI - 20 floor as on the damage side (the character sheet
|
||||
// shows a single Spell Power value, so both sides must add the same
|
||||
// bonus).
|
||||
if (ToPlayer()->getClass() == CLASS_PARAGON)
|
||||
{
|
||||
int32 paragonSP = int32(GetLevel()) * 2
|
||||
+ int32(GetStat(STAT_INTELLECT))
|
||||
+ int32(GetStat(STAT_SPIRIT))
|
||||
- 20;
|
||||
if (paragonSP > 0)
|
||||
AdvertisedBenefit += paragonSP;
|
||||
}
|
||||
|
||||
// Healing bonus from stats
|
||||
AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
|
||||
for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
|
||||
@@ -10392,7 +10470,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
|
||||
uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
|
||||
|
||||
// Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
|
||||
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
|
||||
if (ParagonFamilyMatches(attacker, SPELLFAMILY_DRUID, spellProto->SpellFamilyName) && spellProto->SpellFamilyFlags[0] & 0x00008800)
|
||||
mechanicMask |= (1ULL << MECHANIC_BLEED);
|
||||
|
||||
if (mechanicMask)
|
||||
|
||||
@@ -2268,6 +2268,25 @@ private:
|
||||
ValuesUpdateCache _valuesUpdateCache;
|
||||
};
|
||||
|
||||
// Fractured / Paragon: returns true iff `listener` is a CLASS_PARAGON player
|
||||
// AND `Paragon.WildcardFamilyMatching` is enabled. Single source of truth for
|
||||
// the gate that controls every cross-class wildcard path (family-name skip in
|
||||
// SpellInfo::IsAffected, leech-aura disease counting in
|
||||
// Unit::GetDiseasesByCaster, the cross-school instant-cast intercept in
|
||||
// Spell::prepare for Predator's / Nature's Swiftness, the Vampiric Embrace
|
||||
// CheckProc cross-family path, etc.). Centralizing the check means runtime
|
||||
// kill-switching the wildcard config flips every behavior together.
|
||||
[[nodiscard]] bool IsParagonWildcardCaller(Unit const* listener);
|
||||
|
||||
// Fractured / Paragon: helper for ad-hoc `switch (SpellFamilyName)` listener
|
||||
// gates scattered across Unit / SpellEffects / SpellAuraEffects. When the
|
||||
// listener (i.e. the unit holding the gating talent / aura) is a Paragon
|
||||
// AND `Paragon.WildcardFamilyMatching` is enabled, accept any source family
|
||||
// so cross-class procs / bonuses can fire. Stock classes use stock equality.
|
||||
// Defined inline here so call sites do not need an extra include for World.h
|
||||
// beyond what they already include via Unit.h's transitive headers.
|
||||
[[nodiscard]] bool ParagonFamilyMatches(Unit const* listener, uint32 expectedFamily, uint32 actualFamily);
|
||||
|
||||
namespace Acore
|
||||
{
|
||||
// Binary predicate for sorting Units based on percent value of a power
|
||||
|
||||
@@ -908,7 +908,12 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid, uint32 vendorEntry)
|
||||
{
|
||||
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item))
|
||||
{
|
||||
if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->IsGameMaster())
|
||||
// mod-paragon: class 12 sees every BoP class-restricted item
|
||||
// in vendor lists (class glyphs, class tier sets, ...).
|
||||
if (_player->getClass() != CLASS_PARAGON
|
||||
&& !(itemTemplate->AllowableClass & _player->getClassMask())
|
||||
&& itemTemplate->Bonding == BIND_WHEN_PICKED_UP
|
||||
&& !_player->IsGameMaster())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1630,7 +1630,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
|
||||
|
||||
// Xinef: Remove autoattack spells
|
||||
if (Spell* spell = target->GetCurrentSpell(CURRENT_MELEE_SPELL))
|
||||
if (spell->GetSpellInfo()->CheckShapeshift(newAura ? newAura->GetMiscValue() : 0) != SPELL_CAST_OK)
|
||||
if (spell->GetSpellInfo()->CheckShapeshift(newAura ? newAura->GetMiscValue() : 0, target) != SPELL_CAST_OK)
|
||||
spell->cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2175,7 +2175,9 @@ uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo,
|
||||
return 0;
|
||||
|
||||
// do checks against db data
|
||||
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo))
|
||||
// Fractured / Paragon: the unit that owns this aura is the listener;
|
||||
// pass it through so cross-family procs can match for Paragon players.
|
||||
if (!sSpellMgr->CanSpellTriggerProcOnEvent(*procEntry, eventInfo, aurApp->GetTarget()))
|
||||
return 0;
|
||||
|
||||
// check if spell was affected by this aura's spellmod (used by Arcane Potency and similar effects)
|
||||
@@ -2249,8 +2251,26 @@ uint8 Aura::GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo,
|
||||
item = target->ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
||||
}
|
||||
|
||||
if (!item || item->IsBroken() || !item->IsFitToSpellRequirements(GetSpellInfo()))
|
||||
if (!item || item->IsBroken())
|
||||
return 0;
|
||||
if (!item->IsFitToSpellRequirements(GetSpellInfo()))
|
||||
{
|
||||
// Fractured / Paragon: cross-class wildcard relaxes weapon-
|
||||
// class subclass gates on per-event proc evaluation. This
|
||||
// mirrors Player::CheckAttackFitToAuraRequirement and
|
||||
// Player::HasItemFitToSpellRequirements -- without this
|
||||
// third bypass, the talent attaches (HasItemFit lets it),
|
||||
// the per-swing match accepts the weapon (CheckAttackFit
|
||||
// lets it), but IsProcTriggeredOnEvent still kills the
|
||||
// proc here for any weapon outside the talent's stock
|
||||
// subclass mask (e.g. Maelstrom Weapon on a Paragon
|
||||
// wielding a 1H sword or polearm). Restricted to
|
||||
// ITEM_CLASS_WEAPON so shield-gated talents still need
|
||||
// an actual shield.
|
||||
if (!(GetSpellInfo()->EquippedItemClass == ITEM_CLASS_WEAPON
|
||||
&& IsParagonWildcardCaller(target)))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "Vehicle.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
@@ -3540,6 +3541,52 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
|
||||
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_CASTTIME))
|
||||
m_casttime = 0;
|
||||
|
||||
// Fractured / Paragon: cross-class "next Nature spell becomes instant"
|
||||
// intercept for the three buffs that share that semantic in 3.3.5:
|
||||
//
|
||||
// 69369 - Predator's Swiftness (Cataclysm proc payload triggered by
|
||||
// our spell_paragon_predatory_strikes; see Paragon_SC.cpp)
|
||||
// 17116 - Druid Nature's Swiftness
|
||||
// 16188 - Shaman Nature's Swiftness
|
||||
//
|
||||
// All three apply SPELL_AURA_ADD_PCT_MODIFIER on SPELLMOD_CASTING_TIME
|
||||
// gated by a Druid- or Shaman-only SpellClassMask, so a Paragon with the
|
||||
// buff cannot instant-cast a Nature spell from a different family
|
||||
// (e.g. a Druid NS Paragon casting Shaman Chain Lightning, or a Shaman
|
||||
// NS Paragon casting Druid Healing Touch). Tooltip text on all three
|
||||
// promises "next Nature spell with a base cast time below 10 sec becomes
|
||||
// instant"; honor that here for CLASS_PARAGON callers when the wildcard
|
||||
// config is on. The stock SpellMod path is untouched -- real Druids /
|
||||
// Shamans / proc consumers continue to hit the existing class-mask code
|
||||
// path unchanged.
|
||||
if (Player* paragonCaster = m_caster->ToPlayer())
|
||||
{
|
||||
if (m_casttime > 0
|
||||
&& IsParagonWildcardCaller(paragonCaster)
|
||||
&& (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NATURE)
|
||||
&& m_spellInfo->CastTimeEntry
|
||||
&& !m_spellInfo->IsChanneled()
|
||||
&& !HasTriggeredCastFlag(TRIGGERED_FULL_MASK)
|
||||
&& m_spellInfo->CalcCastTime() < 10 * IN_MILLISECONDS)
|
||||
{
|
||||
static constexpr std::array<uint32, 3> kParagonNatureInstantBuffs =
|
||||
{
|
||||
69369u, // Predator's Swiftness (Paragon proc payload)
|
||||
17116u, // Druid Nature's Swiftness
|
||||
16188u // Shaman Nature's Swiftness
|
||||
};
|
||||
for (uint32 buffId : kParagonNatureInstantBuffs)
|
||||
{
|
||||
if (paragonCaster->HasAura(buffId))
|
||||
{
|
||||
m_casttime = 0;
|
||||
paragonCaster->RemoveAurasDueToSpell(buffId);
|
||||
break; // consume only one buff per cast
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow channeled spells / spells with cast time to be casted while moving
|
||||
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
|
||||
if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->IsPlayer() && m_caster->isMoving() && m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT && !IsTriggered())
|
||||
@@ -5722,7 +5769,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* /*param1*/, uint32* /*para
|
||||
if (checkForm)
|
||||
{
|
||||
// Cannot be used in this stance/form
|
||||
SpellCastResult shapeError = m_spellInfo->CheckShapeshift(m_caster->GetShapeshiftForm());
|
||||
SpellCastResult shapeError = m_spellInfo->CheckShapeshift(m_caster->GetShapeshiftForm(), m_caster);
|
||||
if (shapeError != SPELL_CAST_OK)
|
||||
return shapeError;
|
||||
|
||||
@@ -7296,8 +7343,16 @@ SpellCastResult Spell::CheckItems(uint32* param1, uint32* param2)
|
||||
{
|
||||
// Xinef: this is not true in my opinion, in eg bladestorm will not be canceled after disarm
|
||||
//if (!HasTriggeredCastFlag(TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT))
|
||||
if (m_caster->IsPlayer() && !m_caster->ToPlayer()->HasItemFitToSpellRequirements(m_spellInfo))
|
||||
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
|
||||
if (m_caster->IsPlayer())
|
||||
{
|
||||
// Cast-from-glyph: many glyph on-use spells set EquippedItemClass to ITEM_CLASS_GLYPH.
|
||||
// HasItemFitToSpellRequirements only implements weapon/armor, so it would always fail here
|
||||
// even though the glyph item in the bag is the valid spell source.
|
||||
bool const castFromGlyphScroll = m_CastItem && m_CastItem->GetTemplate() &&
|
||||
m_CastItem->GetTemplate()->Class == ITEM_CLASS_GLYPH;
|
||||
if (!castFromGlyphScroll && !m_caster->ToPlayer()->HasItemFitToSpellRequirements(m_spellInfo))
|
||||
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
// do not take reagents for these item casts
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldConfig.h"
|
||||
|
||||
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
|
||||
{
|
||||
@@ -1323,11 +1325,26 @@ bool SpellInfo::HasInitialAggro() const
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const
|
||||
{
|
||||
return IsAffected(familyName, familyFlags, nullptr);
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags,
|
||||
Unit const* listenerOwner) const
|
||||
{
|
||||
if (!familyName)
|
||||
return true;
|
||||
|
||||
if (familyName != SpellFamilyName)
|
||||
// Fractured / Paragon: when the unit that owns the listening proc /
|
||||
// spellmod aura is a Paragon, accept any source family. The class
|
||||
// mask flag-bit check below still runs, so listeners that explicitly
|
||||
// opt into a subset of spells via SpellFamilyFlags / class mask are
|
||||
// still respected; only the family-name equality gate is wildcarded.
|
||||
bool const wildcardFamily = listenerOwner
|
||||
&& listenerOwner->getClass() == CLASS_PARAGON
|
||||
&& sWorld->getBoolConfig(CONFIG_PARAGON_WILDCARD_FAMILY);
|
||||
|
||||
if (!wildcardFamily && familyName != SpellFamilyName)
|
||||
return false;
|
||||
|
||||
if (familyFlags && !(familyFlags & SpellFamilyFlags))
|
||||
@@ -1342,6 +1359,11 @@ bool SpellInfo::IsAffectedBySpellMods() const
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
|
||||
{
|
||||
return IsAffectedBySpellMod(mod, nullptr);
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod, Unit const* listenerOwner) const
|
||||
{
|
||||
// xinef: dont check duration mod
|
||||
if (mod->op != SPELLMOD_DURATION)
|
||||
@@ -1356,7 +1378,42 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
|
||||
if (!sScriptMgr->OnIsAffectedBySpellModCheck(affectSpell, this, mod))
|
||||
return true;
|
||||
|
||||
return IsAffected(affectSpell->SpellFamilyName, mod->mask);
|
||||
if (IsAffected(affectSpell->SpellFamilyName, mod->mask, listenerOwner))
|
||||
return true;
|
||||
|
||||
// Fractured / Paragon: explicit cross-family allowlist for specific
|
||||
// listener auras whose SpellClassMask cannot otherwise bridge classes.
|
||||
// The standard IsAffected wildcard relaxes SpellFamilyName equality but
|
||||
// still requires SpellClassMask & SpellFamilyFlags to overlap; for these
|
||||
// Paragon-only cross-class enablers the source spells live in different
|
||||
// families with non-overlapping class bits, so we whitelist by mod owner
|
||||
// spell ID + target spell first-rank ID. Stock classes never enter here
|
||||
// because IsParagonWildcardCaller short-circuits on non-Paragon owners.
|
||||
if (IsParagonWildcardCaller(listenerOwner))
|
||||
{
|
||||
switch (mod->spellId)
|
||||
{
|
||||
case 53817: // Shaman: Maelstrom Weapon
|
||||
{
|
||||
// Allow any rank of Mage Fireball / Frostbolt / Arcane Blast to
|
||||
// benefit from the cast-time + cost reduction spellmod.
|
||||
if (SpellFamilyName == SPELLFAMILY_MAGE)
|
||||
{
|
||||
SpellInfo const* first = GetFirstRankSpell();
|
||||
uint32 firstId = first ? first->Id : Id;
|
||||
if (firstId == 133 /*Fireball*/
|
||||
|| firstId == 116 /*Frostbolt*/
|
||||
|| firstId == 30451 /*Arcane Blast*/)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpellInfo::CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const
|
||||
@@ -1441,7 +1498,7 @@ bool SpellInfo::IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInf
|
||||
}
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
SpellCastResult SpellInfo::CheckShapeshift(uint32 form, Unit const* caster /*= nullptr*/) const
|
||||
{
|
||||
// talents that learn spells can have stance requirements that need ignore
|
||||
// (this requirement only for client-side stance show in talent description)
|
||||
@@ -1449,6 +1506,38 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
(Effects[0].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[1].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[2].Effect == SPELL_EFFECT_LEARN_SPELL))
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
// Fractured / Paragon: Paragons learn Warrior abilities through Advancement
|
||||
// without picking up Battle/Defensive/Berserker Stance, so stance-gated
|
||||
// Warrior spells (e.g. Whirlwind, Sunder Armor, Shield Slam) would otherwise
|
||||
// be uncastable. Bypass the stance check for Paragon casters on any spell
|
||||
// that has a non-zero Stances bitmask, regardless of SpellFamilyName.
|
||||
//
|
||||
// We previously gated this on SpellFamilyName == SPELLFAMILY_WARRIOR, but a
|
||||
// number of SPELLFAMILY_GENERIC spells (notably the iconic Warrior toolbox
|
||||
// -- Berserker Rage 18499, Sunder Armor 7405 / 11596 / 11597 / 25225 /
|
||||
// 47467, Charge 100 / 6178 / 11578, Pummel 6552 / 6554, Shield Bash 72 /
|
||||
// 1671 / 1672 / 29704, Retaliation 20230, Recklessness 1719, Shield Wall
|
||||
// 871, etc.) carry the Stances bitmask but live under SPELLFAMILY_GENERIC
|
||||
// (family 0). The previous narrower gate let those re-trigger the stance
|
||||
// failure for Paragons. Widening to "any non-zero Stances + Paragon" is
|
||||
// safe because:
|
||||
//
|
||||
// * The bypass returns SPELL_CAST_OK only when IsParagonWildcardCaller
|
||||
// is true -- stock classes never enter this branch.
|
||||
// * Druid form-gated spells (Cat Form / Bear Form / Moonkin / Tree)
|
||||
// still fire the Druid GCD/form rules elsewhere; CheckShapeshift is
|
||||
// about *requiring* a form to cast, which is exactly what we want
|
||||
// to bypass for Paragons (they never picked the form).
|
||||
// * Item enchant scrolls and other shapeshift-marked utility spells
|
||||
// remain unaffected because they aren't in a Paragon's spellbook.
|
||||
if (Stances != 0 && IsParagonWildcardCaller(caster))
|
||||
{
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] CheckShapeshift bypass: spell={} family={} stances=0x{:x} form={}",
|
||||
Id, SpellFamilyName, Stances, form);
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
uint32 stanceMask = (form ? 1 << (form - 1) : 0);
|
||||
|
||||
if (stanceMask & StancesNot) // can explicitly not be casted in this stance
|
||||
|
||||
@@ -494,9 +494,21 @@ public:
|
||||
bool HasInitialAggro() const;
|
||||
|
||||
[[nodiscard]] bool IsAffected(uint32 familyName, flag96 const& familyFlags) const;
|
||||
// Fractured / Paragon overload. When `listenerOwner` is a CLASS_PARAGON
|
||||
// unit and Paragon.WildcardFamilyMatching is enabled, the
|
||||
// SpellFamilyName equality check is skipped (flag-bit check still runs)
|
||||
// so cross-class procs / spellmods can react to the spell. Passing
|
||||
// nullptr (or any non-Paragon unit) reproduces the stock 2-arg
|
||||
// behavior; the 2-arg form forwards to this overload with nullptr.
|
||||
[[nodiscard]] bool IsAffected(uint32 familyName, flag96 const& familyFlags,
|
||||
Unit const* listenerOwner) const;
|
||||
|
||||
bool IsAffectedBySpellMods() const;
|
||||
bool IsAffectedBySpellMod(SpellModifier const* mod) const;
|
||||
// Fractured / Paragon overload: pass the player who owns the modifier
|
||||
// aura so wildcard-family matching can apply when that player is a
|
||||
// Paragon. Stock callers may forward to this with nullptr.
|
||||
bool IsAffectedBySpellMod(SpellModifier const* mod, Unit const* listenerOwner) const;
|
||||
|
||||
bool CanPierceImmuneAura(SpellInfo const* auraSpellInfo) const;
|
||||
bool CanDispelAura(SpellInfo const* auraSpellInfo) const;
|
||||
@@ -509,7 +521,7 @@ public:
|
||||
bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
|
||||
bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
|
||||
|
||||
SpellCastResult CheckShapeshift(uint32 form) const;
|
||||
SpellCastResult CheckShapeshift(uint32 form, Unit const* caster = nullptr) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player = nullptr, bool strict = true) const;
|
||||
SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
|
||||
|
||||
@@ -5368,6 +5368,56 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
LockEntry* key = const_cast<LockEntry*>(sLockStore.LookupEntry(36)); // 3366 Opening, allows to open without proper key
|
||||
key->Type[2] = LOCK_KEY_NONE;
|
||||
|
||||
// Fractured / Paragon: DK weapon-line "passives" Forceful Deflection and
|
||||
// Runic Focus ship in 3.3.5a Spell.dbc without SPELL_ATTR0_PASSIVE set.
|
||||
// SpellInfo::IsPassive() is therefore false, and mod-paragon's panel-learn
|
||||
// diff treats them as castable actives and revokes them — while true
|
||||
// actives (Blood Presence, Death Coil, Death Grip, ...) must stay
|
||||
// stripped. Mark these two passive in-memory so the panel policy matches
|
||||
// the spellbook UX for every class (stock DK benefits too).
|
||||
ApplySpellFix({ 49410, 61455 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
|
||||
});
|
||||
|
||||
// Fractured: strip reagent requirements from every player-class spell at
|
||||
// load time. Filtered by SpellFamilyName != 0 so that profession spells
|
||||
// (cooking, alchemy, enchanting, blacksmithing, jewelcrafting, leatherworking,
|
||||
// tailoring, engineering, inscription, mining, herbalism, skinning, fishing,
|
||||
// first aid — all SpellFamilyName == SPELLFAMILY_GENERIC == 0) keep their
|
||||
// mats and only the class abilities that asked for ankhs / candles / soul
|
||||
// shards / verdant spheres / etc. cast freely. Done here in core spell
|
||||
// data rather than as a runtime bypass in Spell::CheckItems / TakeReagents
|
||||
// so the change is data-driven (the in-memory SpellInfo simply has no
|
||||
// reagents to require). The client-side preflight is mirrored by the
|
||||
// matching Spell.dbc patch shipped via patch-enUS-4.MPQ
|
||||
// (fractured-tooling/_patch_spell_dbc_reagents.py).
|
||||
{
|
||||
uint32 fixedClassSpells = 0;
|
||||
for (uint32 spellId = 1; spellId < sSpellMgr->GetSpellInfoStoreSize(); ++spellId)
|
||||
{
|
||||
SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!info || info->SpellFamilyName == 0)
|
||||
continue;
|
||||
|
||||
bool hadAny = false;
|
||||
for (uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i)
|
||||
if (info->Reagent[i] != 0 || info->ReagentCount[i] != 0)
|
||||
{ hadAny = true; break; }
|
||||
if (!hadAny)
|
||||
continue;
|
||||
|
||||
SpellInfo* mut = const_cast<SpellInfo*>(info);
|
||||
for (uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i)
|
||||
{
|
||||
mut->Reagent[i] = 0;
|
||||
mut->ReagentCount[i] = 0;
|
||||
}
|
||||
++fixedClassSpells;
|
||||
}
|
||||
LOG_INFO("server.loading", ">> Fractured: cleared reagents on {} class spells", fixedClassSpells);
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loading spell dbc data corrections in {} ms", GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
@@ -842,7 +842,8 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const
|
||||
bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo,
|
||||
Unit const* procOwner /*= nullptr*/) const
|
||||
{
|
||||
// proc type doesn't match
|
||||
if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
|
||||
@@ -873,7 +874,10 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
|
||||
// check spell family name/flags (if set) for spells
|
||||
if (eventInfo.GetTypeMask() & SPELL_PROC_FLAG_MASK)
|
||||
if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
|
||||
if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
|
||||
// Fractured / Paragon: thread the proc-aura owner so a Paragon
|
||||
// listener accepts cross-family source spells. See
|
||||
// SpellInfo::IsAffected(family, flags, listenerOwner).
|
||||
if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask, procOwner))
|
||||
return false;
|
||||
|
||||
// check spell type mask (if set)
|
||||
|
||||
@@ -699,7 +699,12 @@ public:
|
||||
|
||||
// Spell proc table
|
||||
[[nodiscard]] SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const;
|
||||
bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
|
||||
// Fractured / Paragon: `procOwner` is the unit that holds the listening
|
||||
// proc aura. Passing it lets SpellInfo::IsAffected wildcard the family
|
||||
// check when the listener is on a CLASS_PARAGON player. Non-Paragon
|
||||
// owners (or nullptr) reproduce stock behavior exactly.
|
||||
bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo,
|
||||
Unit const* procOwner = nullptr) const;
|
||||
|
||||
// Spell bonus data table
|
||||
[[nodiscard]] SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const;
|
||||
|
||||
@@ -684,4 +684,10 @@ void WorldConfig::BuildConfigCache()
|
||||
|
||||
// Achievement
|
||||
SetConfigValue<uint32>(CONFIG_ACHIEVEMENT_REALM_FIRST_KILL_WINDOW, "Achievement.RealmFirstKillWindow", 60);
|
||||
|
||||
// Fractured / Paragon: cross-class wildcard for SpellFamilyName gating.
|
||||
// Default ON because the Paragon class is designed around it; flip to 0
|
||||
// (no rebuild required) if a regression appears and stock family
|
||||
// gating needs to be restored without backing out the code.
|
||||
SetConfigValue<bool>(CONFIG_PARAGON_WILDCARD_FAMILY, "Paragon.WildcardFamilyMatching", true);
|
||||
}
|
||||
|
||||
@@ -495,6 +495,12 @@ enum ServerConfigs
|
||||
CONFIG_NEW_CHAR_STRING,
|
||||
CONFIG_VALIDATE_SKILL_LEARNED_BY_SPELLS,
|
||||
CONFIG_ACHIEVEMENT_REALM_FIRST_KILL_WINDOW,
|
||||
// Fractured / Paragon: when true, CLASS_PARAGON characters bypass the
|
||||
// SpellFamilyName equality check in proc / spellmod / aura listener
|
||||
// gates so cross-class talent procs and modifiers can interact with
|
||||
// spells learned from other classes (e.g. Predator's Swiftness 69369
|
||||
// making Shaman Chain Lightning instant). Stock classes are unaffected.
|
||||
CONFIG_PARAGON_WILDCARD_FAMILY,
|
||||
|
||||
MAX_NUM_SERVER_CONFIGS
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This is where scripts' loading functions should be declared:
|
||||
// void MyExampleScript()
|
||||
|
||||
// The name of this function should match:
|
||||
// void Add${NameOfDirectory}Scripts()
|
||||
void AddCustomScripts()
|
||||
{
|
||||
// MyExampleScript()
|
||||
}
|
||||
@@ -64,10 +64,227 @@ struct npc_pet_mage_mirror_image : CasterAI
|
||||
uint32 dist = urand(1, 5);
|
||||
bool _delayAttack;
|
||||
|
||||
// Fractured / Paragon: when the owner is a Paragon character with the
|
||||
// wildcard config enabled, replace the stock Frostbolt + Fireblast
|
||||
// allowlist (loaded by CombatAI from creature_template_spell for
|
||||
// creature 31216) with a curated list of damaging spells from the
|
||||
// owner's spellbook. UpdateAI's override picks a random spell from
|
||||
// the list per cast so the rotation isn't deterministic.
|
||||
//
|
||||
// The image still casts as itself (not via the owner), so spell
|
||||
// coefficients apply to the image's stats -- spells naturally do less
|
||||
// damage than they would in the owner's hands. We accept that as the
|
||||
// cost of "free cross-class spell variety" rather than try to rebalance
|
||||
// every player spell here.
|
||||
static bool IsDamagingForMirrorImage(SpellInfo const* si)
|
||||
{
|
||||
// Direct damage effect.
|
||||
if (si->HasEffect(SPELL_EFFECT_SCHOOL_DAMAGE))
|
||||
return true;
|
||||
|
||||
// Spells like Arcane Missiles (TRIGGER_MISSILE) and most channeled
|
||||
// multi-tick nukes route their damage through a child spell, so the
|
||||
// parent has no SCHOOL_DAMAGE effect of its own. Accept that here.
|
||||
if (si->HasEffect(SPELL_EFFECT_TRIGGER_MISSILE))
|
||||
return true;
|
||||
|
||||
// DoTs and channels-as-aura (Mind Flay, Curse of Doom, Immolate,
|
||||
// Corruption, Vampiric Touch, Drain Life leech, etc.). Also accept
|
||||
// PERIODIC_TRIGGER_SPELL auras -- that's how Arcane Missiles fires
|
||||
// each individual missile (parent has Aura=23 -> child damaging
|
||||
// spell). Same pattern is used by Hunter Volley, Curse of Doom (in
|
||||
// some ranks), and similar tick-by-trigger spells.
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
uint32 aura = si->Effects[i].ApplyAuraName;
|
||||
if (aura == SPELL_AURA_PERIODIC_DAMAGE
|
||||
|| aura == SPELL_AURA_PERIODIC_DAMAGE_PERCENT
|
||||
|| aura == SPELL_AURA_PERIODIC_LEECH
|
||||
|| aura == SPELL_AURA_PERIODIC_TRIGGER_SPELL)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RebuildSpellsFromOwnerSpellbookForParagon(Player* owner)
|
||||
{
|
||||
SpellVct curated;
|
||||
curated.reserve(8);
|
||||
|
||||
uint32 scanned = 0, kept = 0, rejInactive = 0, rejPassive = 0, rejWeaponStrike = 0,
|
||||
rejNoDmg = 0, rejAoe = 0, rejGate = 0, rejLongCD = 0, rejLowRank = 0;
|
||||
|
||||
// For diagnosis: collect IDs of spells we'd expect to keep (Fireball,
|
||||
// Frostbolt, Lightning Bolt, Mind Blast, Shadow Bolt, etc.) but that
|
||||
// we instead reject. The sample is small so per-spell logging is OK.
|
||||
auto trackProbe = [&](uint32 spellId, char const* phase)
|
||||
{
|
||||
// Only log "interesting" spell IDs to avoid 177-line spam per image.
|
||||
// These are first-rank IDs of common cross-class single-target nukes.
|
||||
static constexpr uint32 probes[] = {
|
||||
133, 116, 30451, // Mage: Fireball, Frostbolt, Arcane Blast
|
||||
5143, // Mage: Arcane Missiles (channel via PERIODIC_TRIGGER_SPELL)
|
||||
403, 529, 8042, // Shaman: Lightning Bolt, Chain Lightning, Earth Shock
|
||||
585, 14914, // Priest: Smite, Holy Fire
|
||||
8092, 15407, // Priest: Mind Blast, Mind Flay
|
||||
686, 348, // Warlock: Shadow Bolt, Immolate (DoT w/ cast time)
|
||||
5176, 2912, // Druid: Wrath, Starfire
|
||||
635, // Paladin: Holy Light
|
||||
};
|
||||
for (uint32 probe : probes)
|
||||
{
|
||||
if (spellId == probe)
|
||||
{
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage probe spell={} phase={}",
|
||||
spellId, phase);
|
||||
return;
|
||||
}
|
||||
// Also walk rank chain: if the spellbook has rank N of probe,
|
||||
// probe matches via GetFirstRankSpell.
|
||||
if (SpellInfo const* si = sSpellMgr->GetSpellInfo(spellId))
|
||||
if (SpellInfo const* first = si->GetFirstRankSpell())
|
||||
if (first->Id == probe)
|
||||
{
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage probe spell={} (rank of {}) phase={}",
|
||||
spellId, probe, phase);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto const& kv : owner->GetSpellMap())
|
||||
{
|
||||
++scanned;
|
||||
uint32 spellId = kv.first;
|
||||
PlayerSpell const* ps = kv.second;
|
||||
if (!ps || ps->State == PLAYERSPELL_REMOVED || !ps->Active)
|
||||
{
|
||||
++rejInactive;
|
||||
trackProbe(spellId, "inactive");
|
||||
continue;
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
// Spec (per user): damaging single-target spells, instant or
|
||||
// cast-time or channeled all OK, no melee/ranged "strike" style
|
||||
// weapon-attack abilities, and no long-cooldown spells (>10s) so
|
||||
// the image cycles through a varied rotation rather than blowing
|
||||
// a 2-min cooldown once.
|
||||
if (spellInfo->IsPassive()) { ++rejPassive; trackProbe(spellId, "passive"); continue; }
|
||||
if (!IsDamagingForMirrorImage(spellInfo)) { ++rejNoDmg; trackProbe(spellId, "noDmg"); continue; }
|
||||
if (spellInfo->IsAffectingArea()) { ++rejAoe; trackProbe(spellId, "aoe"); continue; }
|
||||
if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE
|
||||
|| spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED) { ++rejWeaponStrike; trackProbe(spellId, "weaponStrike"); continue; }
|
||||
// Reject anything with a base cooldown longer than 10s (either
|
||||
// RecoveryTime or CategoryRecoveryTime). A 0/very-short CD is
|
||||
// fine. The mage Mirror Image only lives for 30s, so anything
|
||||
// gated by a long CD would only ever fire once anyway.
|
||||
uint32 cd = std::max(spellInfo->RecoveryTime, spellInfo->CategoryRecoveryTime);
|
||||
if (cd > 10000) { ++rejLongCD; trackProbe(spellId, "longCD"); continue; }
|
||||
|
||||
// Skip spells the image would never realistically be able to
|
||||
// cast successfully or whose side-effects don't make sense on a
|
||||
// pet (totems, summons, item / reagent / focus requirements,
|
||||
// ranged-weapon / shapeshift / stealth gates, profession spells,
|
||||
// teleports, etc.).
|
||||
char const* gateReason = nullptr;
|
||||
if (spellInfo->RequiresSpellFocus) gateReason = "focus";
|
||||
else if (spellInfo->Reagent[0] > 0) gateReason = "reagent";
|
||||
else if (spellInfo->Stances || spellInfo->StancesNot) gateReason = "stance";
|
||||
else if (spellInfo->EquippedItemClass >= 0) gateReason = "equipped";
|
||||
else if (spellInfo->IsCooldownStartedOnEvent()) gateReason = "cdEvent";
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) gateReason = "attrPassive";
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_DO_NOT_DISPLAY)) gateReason = "attrHidden";
|
||||
// SPELL_ATTR0_NOT_SHAPESHIFTED is intentionally NOT a gate -- it
|
||||
// means "cannot be cast while caster IS shapeshifted", not "this
|
||||
// spell requires a shapeshift". The attribute is set on every
|
||||
// standard caster nuke (Fireball, Frostbolt, Lightning Bolt,
|
||||
// Shadow Bolt, etc.) and Mirror Images are never shapeshifted,
|
||||
// so the runtime check trivially passes for them. Filtering on
|
||||
// it here was the bug that left the curated list empty.
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED)) gateReason = "attrStealth";
|
||||
// SPELL_ATTR1_NO_AUTOCAST_AI is intentionally NOT a gate -- it is set
|
||||
// on most player nukes (Fireball / Lightning Bolt / Shadow Bolt) to
|
||||
// stop class pets from auto-casting them. Mirror Images are
|
||||
// server-curated player-spell mimics, so we WANT to auto-cast
|
||||
// those exact spells.
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE)) gateReason = "attrFailImmune";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_SUMMON)) gateReason = "fxSummon";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_SUMMON_PET)) gateReason = "fxSummonPet";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS)) gateReason = "fxTeleport";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_TRANS_DOOR)) gateReason = "fxTransDoor";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_OPEN_LOCK)) gateReason = "fxOpenLock";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_INSTAKILL)) gateReason = "fxInstakill";
|
||||
else if (spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) gateReason = "fxLearn";
|
||||
if (gateReason) { ++rejGate; trackProbe(spellId, gateReason); continue; }
|
||||
|
||||
// Ignore spell ranks below the highest the player owns -- the
|
||||
// spellbook contains all learned ranks; we want only the latest.
|
||||
if (SpellInfo const* nextRank = spellInfo->GetNextRankSpell())
|
||||
if (owner->HasSpell(nextRank->Id))
|
||||
{ ++rejLowRank; trackProbe(spellId, "lowRank"); continue; }
|
||||
|
||||
++kept;
|
||||
curated.push_back(spellId);
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage kept spell={} ({})",
|
||||
spellId,
|
||||
spellInfo->SpellName[0] ? spellInfo->SpellName[0] : "?");
|
||||
}
|
||||
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage rebuild owner={} scanned={} kept={} "
|
||||
"rejInactive={} rejPassive={} rejNoDmg={} rejAoe={} rejWeaponStrike={} rejLongCD={} rejGate={} rejLowRank={}",
|
||||
owner->GetName(), scanned, kept,
|
||||
rejInactive, rejPassive, rejNoDmg, rejAoe, rejWeaponStrike, rejLongCD, rejGate, rejLowRank);
|
||||
|
||||
if (curated.empty())
|
||||
{
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage rebuild for {} produced empty list, keeping stock 59637/59638",
|
||||
owner->GetName());
|
||||
return; // keep stock 59637 / 59638 fallback
|
||||
}
|
||||
|
||||
// Log the first few spell IDs we picked so we can verify the list.
|
||||
std::string sample;
|
||||
for (size_t i = 0; i < curated.size() && i < 8; ++i)
|
||||
{
|
||||
if (!sample.empty())
|
||||
sample += ',';
|
||||
sample += std::to_string(curated[i]);
|
||||
}
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage rebuild swapping spells for {} (sample: {})",
|
||||
owner->GetName(), sample);
|
||||
|
||||
spells.swap(curated);
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
CasterAI::InitializeAI();
|
||||
|
||||
// Fractured / Paragon: do the spellbook rebuild EARLY -- before
|
||||
// owner->CastSpell(CLONE_ME) and before any threat-list inheritance,
|
||||
// because any of those can synchronously fire JustEngagedWith on the
|
||||
// image and cause CasterAI::JustEngagedWith to schedule events from
|
||||
// the stock [59638 Frostbolt, 59637 Fireblast] m_spells[] entries
|
||||
// before our swap takes effect. The override of JustEngagedWith
|
||||
// below also reasserts the swap + flushes events, so even if a later
|
||||
// combat-entry path fires JustEngagedWith again it picks up the
|
||||
// curated list.
|
||||
if (Unit* owner = me->GetOwner())
|
||||
if (Player* playerOwner = owner->ToPlayer())
|
||||
if (IsParagonWildcardCaller(playerOwner))
|
||||
RebuildSpellsFromOwnerSpellbookForParagon(playerOwner);
|
||||
|
||||
_delayAttack = true;
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
@@ -76,11 +293,21 @@ struct npc_pet_mage_mirror_image : CasterAI
|
||||
|
||||
Unit* owner = me->GetOwner();
|
||||
if (!owner)
|
||||
{
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage InitializeAI: no owner, spells.size={} (stock)",
|
||||
spells.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Clone Me!
|
||||
owner->CastSpell(me, SPELL_MAGE_CLONE_ME, true);
|
||||
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage InitializeAI: post-rebuild spells.size={} first={}",
|
||||
spells.size(),
|
||||
spells.empty() ? 0u : spells.front());
|
||||
|
||||
// xinef: Glyph of Mirror Image (4th copy)
|
||||
float angle = 0.0f;
|
||||
switch (me->GetUInt32Value(UNIT_CREATED_BY_SPELL))
|
||||
@@ -139,6 +366,37 @@ struct npc_pet_mage_mirror_image : CasterAI
|
||||
me->m_Events.AddEventAtOffset(new DeathEvent(*me), 29500ms);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
// Fractured / Paragon: re-apply the spellbook rebuild here as well,
|
||||
// because the engagement can fire synchronously from inside
|
||||
// InitializeAI (via owner->CastSpell(CLONE_ME) or summon-side threat
|
||||
// propagation) BEFORE InitializeAI's own rebuild call has run.
|
||||
// Re-running it here is cheap and idempotent: the curated list is
|
||||
// re-derived from the owner's current spellbook, and we wipe any
|
||||
// previously-scheduled events so the stock 59637 / 59638 entries
|
||||
// CasterAI may already have queued get evicted before scheduling.
|
||||
if (Unit* owner = me->GetOwner())
|
||||
if (Player* playerOwner = owner->ToPlayer())
|
||||
if (IsParagonWildcardCaller(playerOwner))
|
||||
{
|
||||
RebuildSpellsFromOwnerSpellbookForParagon(playerOwner);
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
std::string sample;
|
||||
for (size_t i = 0; i < spells.size() && i < 8; ++i)
|
||||
{
|
||||
if (!sample.empty()) sample += ',';
|
||||
sample += std::to_string(spells[i]);
|
||||
}
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage JustEngagedWith: spells.size={} sample=[{}] who={}",
|
||||
spells.size(), sample, who ? who->GetName() : "<null>");
|
||||
|
||||
CasterAI::JustEngagedWith(who);
|
||||
}
|
||||
|
||||
// Do not reload Creature templates on evade mode enter - prevent visual lost
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
@@ -217,10 +475,61 @@ struct npc_pet_mage_mirror_image : CasterAI
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (uint32 spellId = events.ExecuteEvent())
|
||||
if (uint32 queuedId = events.ExecuteEvent())
|
||||
{
|
||||
events.RescheduleEvent(spellId, spellId == 59637 ? 6500ms : 2500ms);
|
||||
me->CastSpell(me->GetVictim(), spellId, false);
|
||||
// Fractured / Paragon: when the curated spellbook list is in
|
||||
// play, pick a random spell from it for THIS cast instead of
|
||||
// using the EventMap-scheduled spellId directly. The events
|
||||
// queue (populated by CasterAI::JustEngagedWith) is otherwise
|
||||
// deterministic for our small list and the image ends up
|
||||
// rotating in lockstep; randomizing here makes each image
|
||||
// (and each cast) feel like a mage ad-libbing from the
|
||||
// player's repertoire.
|
||||
uint32 actualId = queuedId;
|
||||
bool isParagon = false;
|
||||
if (Unit* owner = me->GetOwner())
|
||||
if (Player* playerOwner = owner->ToPlayer())
|
||||
if (IsParagonWildcardCaller(playerOwner) && !spells.empty())
|
||||
{
|
||||
actualId = spells[urand(0, uint32(spells.size()) - 1)];
|
||||
isParagon = true;
|
||||
}
|
||||
|
||||
// Reschedule the queue based on the spell we actually cast,
|
||||
// not the one originally queued. For channeled spells this
|
||||
// matters: Arcane Missiles is a 5s channel, so if we keep
|
||||
// rescheduling every 2.5s the image is always either mid-
|
||||
// channel or immediately re-rolling for another channel,
|
||||
// and over four images you see effectively continuous
|
||||
// Arcane Missiles. Wait for cast/channel to finish + a
|
||||
// small breather before picking again.
|
||||
Milliseconds nextDelay = (queuedId == 59637 ? 6500ms : 2500ms);
|
||||
if (isParagon)
|
||||
{
|
||||
if (SpellInfo const* picked = sSpellMgr->GetSpellInfo(actualId))
|
||||
{
|
||||
uint32 castMs = picked->CalcCastTime();
|
||||
uint32 chanMs = 0;
|
||||
if (picked->IsChanneled())
|
||||
{
|
||||
int32 dur = picked->GetDuration();
|
||||
if (dur > 0)
|
||||
chanMs = uint32(dur);
|
||||
}
|
||||
uint32 minMs = std::max(castMs, chanMs) + 750; // breather
|
||||
if (Milliseconds(minMs) > nextDelay)
|
||||
nextDelay = Milliseconds(minMs);
|
||||
}
|
||||
}
|
||||
events.RescheduleEvent(queuedId, nextDelay);
|
||||
|
||||
SpellCastResult castRes = me->CastSpell(me->GetVictim(), actualId, false);
|
||||
LOG_DEBUG("server.scripts",
|
||||
"[paragon-diag] MirrorImage cast spell={} victim={} result={} nextDelay={}ms",
|
||||
actualId,
|
||||
me->GetVictim() ? me->GetVictim()->GetName() : "<null>",
|
||||
uint32(castRes),
|
||||
uint32(nextDelay.count()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -490,12 +490,22 @@ class spell_mage_cold_snap : public SpellScript
|
||||
{
|
||||
Player* caster = GetCaster()->ToPlayer();
|
||||
// immediately finishes the cooldown on Frost spells
|
||||
|
||||
//
|
||||
// Fractured / Paragon: ParagonFamilyMatches() drops the
|
||||
// SpellFamilyName == SPELLFAMILY_MAGE gate when the caster is a
|
||||
// CLASS_PARAGON player AND Paragon.WildcardFamilyMatching is on,
|
||||
// so any Frost-school spell in the Paragon's spellbook with a real
|
||||
// recovery time (Howling Blast, Frost Shock, Frost Trap, etc.)
|
||||
// also gets its cooldown wiped. Stock Mage callers fall through to
|
||||
// strict family-name equality and observe identical behavior.
|
||||
PlayerSpellMap const& spellMap = caster->GetSpellMap();
|
||||
for (PlayerSpellMap::const_iterator itr = spellMap.begin(); itr != spellMap.end(); ++itr)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first);
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && spellInfo->Id != SPELL_MAGE_COLD_SNAP && spellInfo->GetRecoveryTime() > 0)
|
||||
if (ParagonFamilyMatches(caster, SPELLFAMILY_MAGE, spellInfo->SpellFamilyName)
|
||||
&& (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST)
|
||||
&& spellInfo->Id != SPELL_MAGE_COLD_SNAP
|
||||
&& spellInfo->GetRecoveryTime() > 0)
|
||||
{
|
||||
SpellCooldowns::iterator citr = caster->GetSpellCooldownMap().find(spellInfo->Id);
|
||||
if (citr != caster->GetSpellCooldownMap().end() && citr->second.needSendToClient)
|
||||
@@ -946,6 +956,107 @@ class spell_mage_summon_water_elemental : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 44543, 44545 - Fingers of Frost (talent ranks - the proc-trigger aura, NOT the
|
||||
// 74396 buff aura that is APPLIED when this talent fires).
|
||||
//
|
||||
// Stock spell_proc gates this talent by SpellFamilyName=MAGE plus a
|
||||
// SpellFamilyMask covering the Mage Frost spells that count as "chill-effect
|
||||
// dealers" (Frostbolt / Frost Nova / Cone of Cold / Blizzard / Frostfire Bolt /
|
||||
// Deep Freeze etc.). For Paragon characters with `Paragon.WildcardFamilyMatching`
|
||||
// enabled, we relax the spell_proc row to wildcard family/mask + SchoolMask=
|
||||
// FROST + SpellTypeMask=DAMAGE so that any Frost-school damage spell (DK Howling
|
||||
// Blast / Icy Touch, Hunter Frost Trap / Wing Clip-as-frost, Shaman Frost Shock,
|
||||
// Druid Hibernate damage payload, etc.) reaches this CheckProc; this script
|
||||
// then re-enforces the stock Mage allowlist for non-Paragon owners and lets
|
||||
// Paragons through unconditionally (the FROST + DAMAGE gate already happens at
|
||||
// the spell_proc layer, so any spell reaching us here is safe to accept).
|
||||
class spell_mage_fingers_of_frost_talent : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_mage_fingers_of_frost_talent);
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
|
||||
if (!procSpell)
|
||||
return false;
|
||||
|
||||
// Stock Mage allowlist: re-derive from this talent's own effect-0
|
||||
// SpellClassMask so behavior matches the original auto-generated
|
||||
// proc filter exactly (no risk of mask drift across DBC versions).
|
||||
if (procSpell->SpellFamilyName == SPELLFAMILY_MAGE
|
||||
&& (GetSpellInfo()->Effects[EFFECT_0].SpellClassMask & procSpell->SpellFamilyFlags))
|
||||
return true;
|
||||
|
||||
return IsParagonWildcardCaller(GetUnitOwner());
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_mage_fingers_of_frost_talent::CheckProc);
|
||||
}
|
||||
};
|
||||
|
||||
// 11071, 12496, 12497 - Frostbite (talent ranks - the proc-trigger aura that
|
||||
// chains into 12494 Frostbite freeze).
|
||||
//
|
||||
// Stock spell_proc (auto-generated from DBC) gates this talent by Mage family +
|
||||
// the talent's effect SpellClassMask (Mage Frost slow-applying spells). For
|
||||
// Paragon characters we relax the row to SchoolMask=FROST wildcard so that
|
||||
// chill-applying Frost spells from any class can reach this CheckProc; the
|
||||
// Paragon path additionally requires the proc spell to actually apply a slow
|
||||
// (SPELL_AURA_MOD_DECREASE_SPEED) so that pure damage Frost spells without a
|
||||
// chill component (e.g. raw Ice Lance on a non-frozen target) do NOT freeze.
|
||||
// Stock Mage owners get the original behavior re-enforced here.
|
||||
class spell_mage_frostbite : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_mage_frostbite);
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
|
||||
if (!procSpell)
|
||||
return false;
|
||||
|
||||
// Stock Mage path: re-derive from this talent's own effect-0
|
||||
// SpellClassMask so behavior matches the original auto-generated
|
||||
// proc filter exactly (no risk of mask drift across DBC versions).
|
||||
if (procSpell->SpellFamilyName == SPELLFAMILY_MAGE
|
||||
&& (GetSpellInfo()->Effects[EFFECT_0].SpellClassMask & procSpell->SpellFamilyFlags))
|
||||
return true;
|
||||
|
||||
if (!IsParagonWildcardCaller(GetUnitOwner()))
|
||||
return false;
|
||||
|
||||
// Paragon path: any Frost-school spell that applies a chill effect
|
||||
// (decrease-speed aura). The spell_proc row already gates by
|
||||
// SchoolMask=FROST so we only need to verify chill semantics here.
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (procSpell->Effects[i].ApplyAuraName == SPELL_AURA_MOD_DECREASE_SPEED)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Also accept the Improved-Blizzard-style cross-class case where the
|
||||
// chill is applied by a separate triggered aura: if the proc spell's
|
||||
// damage hit landed and the target already has a chill from us, treat
|
||||
// it as eligible. Cheap and matches player expectations for Paragon.
|
||||
if (Unit* procTarget = eventInfo.GetProcTarget())
|
||||
{
|
||||
Unit::AuraEffectList const& slows = procTarget->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED);
|
||||
for (AuraEffect const* slowEff : slows)
|
||||
if (slowEff->GetCasterGUID() == GetUnitOwner()->GetGUID())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_mage_frostbite::CheckProc);
|
||||
}
|
||||
};
|
||||
|
||||
// 74396 - Fingers of Frost
|
||||
class spell_mage_fingers_of_frost : public AuraScript
|
||||
{
|
||||
@@ -1631,5 +1742,7 @@ void AddSC_mage_spell_scripts()
|
||||
RegisterSpellScript(spell_mage_polymorph_cast_visual);
|
||||
RegisterSpellScript(spell_mage_summon_water_elemental);
|
||||
RegisterSpellScript(spell_mage_fingers_of_frost);
|
||||
RegisterSpellScript(spell_mage_fingers_of_frost_talent);
|
||||
RegisterSpellScript(spell_mage_frostbite);
|
||||
RegisterSpellScript(spell_mage_magic_absorption);
|
||||
}
|
||||
|
||||
@@ -1005,12 +1005,38 @@ class spell_pri_vampiric_embrace : public AuraScript
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
// Not proc from Mind Sear
|
||||
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
|
||||
if (!procSpell)
|
||||
return false;
|
||||
|
||||
return !(procSpell->SpellFamilyFlags[1] & 0x80000);
|
||||
// Stock: filter Mind Sear (the damage-tick spell carries this
|
||||
// SpellFamilyFlags[1] bit; the channel itself is filtered by the
|
||||
// standard data-row mask). Kept as a bit-test so the stock priest
|
||||
// path is byte-identical to before this change.
|
||||
if (procSpell->SpellFamilyFlags[1] & 0x80000)
|
||||
return false;
|
||||
|
||||
// Fractured / Paragon: any single-target Shadow-school damage spell
|
||||
// procs Vampiric Embrace, not just Priest Shadow spells. The
|
||||
// SchoolMask=Shadow gate is enforced by the spell_proc data row
|
||||
// (SchoolMask=32). The data-row family/mask was wildcarded in
|
||||
// mod-paragon's 2026_05_11_01.sql update so this CheckProc fires for
|
||||
// cross-family Shadow spells; here we add the single-target
|
||||
// requirement (Mind Sear was already filtered above; this also
|
||||
// catches AoE Warlock Shadow spells like Seed of Corruption,
|
||||
// Hellfire, etc. that a Paragon could otherwise cast).
|
||||
if (IsParagonWildcardCaller(GetTarget()))
|
||||
return !procSpell->IsAffectingArea();
|
||||
|
||||
// Stock priest path: re-enforce the original Priest Shadow damage
|
||||
// gate that used to live entirely in the data row. Without this,
|
||||
// wildcarding the data row would let item-cast Shadow effects
|
||||
// (consumables, trinkets) accidentally proc VE on stock priests.
|
||||
if (procSpell->SpellFamilyName != SPELLFAMILY_PRIEST)
|
||||
return false;
|
||||
return (procSpell->SpellFamilyFlags[0] & 0x0280A010)
|
||||
|| (procSpell->SpellFamilyFlags[1] & 0x00002402)
|
||||
|| (procSpell->SpellFamilyFlags[2] & 0x00000008);
|
||||
}
|
||||
|
||||
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
|
||||
|
||||
@@ -1790,6 +1790,44 @@ class spell_sha_maelstrom_weapon : public AuraScript
|
||||
});
|
||||
}
|
||||
|
||||
// Fractured / Paragon: spell_proc row 53817 is data-relaxed (wildcard
|
||||
// family/mask) so cross-class spells can reach this CheckProc. We
|
||||
// restore the original Shaman gating here for stock callers and add
|
||||
// the Paragon-only Mage Fireball / Frostbolt / Arcane Blast allowlist
|
||||
// mirroring the IsAffectedBySpellMod hook in SpellInfo.cpp.
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
|
||||
if (!procSpell)
|
||||
return false;
|
||||
|
||||
// Stock allowlist (Shaman): Lightning Bolt, Chain Lightning,
|
||||
// Lesser Healing Wave, Healing Wave, Hex. Encoded as the original
|
||||
// SpellFamilyMask values from the pre-relaxation spell_proc row
|
||||
// (Mask0 = 451, Mask1 = 32768).
|
||||
bool stockMatch = procSpell->SpellFamilyName == SPELLFAMILY_SHAMAN
|
||||
&& ((procSpell->SpellFamilyFlags[0] & 451u)
|
||||
|| (procSpell->SpellFamilyFlags[1] & 32768u));
|
||||
if (stockMatch)
|
||||
return true;
|
||||
|
||||
if (!IsParagonWildcardCaller(GetUnitOwner()))
|
||||
return false;
|
||||
|
||||
// Paragon path: also accept the curated Mage cast-time nukes.
|
||||
if (procSpell->SpellFamilyName == SPELLFAMILY_MAGE)
|
||||
{
|
||||
SpellInfo const* first = procSpell->GetFirstRankSpell();
|
||||
uint32 firstId = first ? first->Id : procSpell->Id;
|
||||
if (firstId == 133 /*Fireball*/
|
||||
|| firstId == 116 /*Frostbolt*/
|
||||
|| firstId == 30451 /*Arcane Blast*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandleBonus(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetStackAmount() < int32(GetSpellInfo()->StackAmount))
|
||||
@@ -1805,6 +1843,7 @@ class spell_sha_maelstrom_weapon : public AuraScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_sha_maelstrom_weapon::CheckProc);
|
||||
OnEffectApply += AuraEffectApplyFn(spell_sha_maelstrom_weapon::HandleBonus, EFFECT_0, SPELL_AURA_ADD_PCT_MODIFIER, AURA_EFFECT_HANDLE_CHANGE_AMOUNT);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -215,6 +215,14 @@ Updates.AllowRehash = 1
|
||||
# -1 - (Enabled - unlimited)
|
||||
|
||||
Updates.CleanDeadRefMaxCount = 3
|
||||
|
||||
#
|
||||
# Updates.ExceptionShutdownDelay
|
||||
# Description: Time (in milliseconds) to wait before shutting down after a fatal exception (e.g. failed SQL update).
|
||||
# Default: 10000 - 10 seconds
|
||||
# 0 - Disabled (immediate shutdown)
|
||||
|
||||
Updates.ExceptionShutdownDelay = 10000
|
||||
###################################################################################################
|
||||
|
||||
###################################################################################################
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
dist/
|
||||
launcher.json
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user