Release Healer Man 0.1.7

This commit is contained in:
phenom committed 2026-08-22 15:53:43 -04:00
1 parent b12fb84859
commit eca6b5db9b
99 files changed
+1931 -150

No files matched your search

+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "healer-man",
"version": "0.1.6",
"version": "0.1.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "healer-man",
"version": "0.1.6",
"version": "0.1.7",
"dependencies": {
"@capacitor/android": "8.4.1",
"@capacitor/core": "8.4.1",
+5 -3
View File
@@ -1,7 +1,7 @@
{
"name": "healer-man",
"private": true,
"version": "0.1.6",
"version": "0.1.7",
"type": "module",
"scripts": {
"dev": "vite --host 0.0.0.0",
@@ -20,7 +20,8 @@
"coa:sync:live": "node scripts/sync-ascension-coa.mjs --tooltips",
"coa:icons": "node scripts/export-spell-icons.mjs",
"ascension:talents": "node scripts/generate-wow335-talents.mjs ../wow335a/Interface/AddOns/PlayerBotManager/PBM/PBM_TalentData.lua ../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc src/game/wow335Talents.generated.ts ../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Talent.dbc",
"ascension:sync": "npm run coa:sync && npm run wow335:abilities && npm run ascension:talents && npm run coa:icons",
"catalogs:shard": "vite-node scripts/generate-catalog-shards.ts",
"ascension:sync": "npm run coa:sync && npm run wow335:abilities && npm run ascension:talents && npm run coa:icons && npm run catalogs:shard",
"manastorm:import": "node scripts/manastorm-import/cli.mjs",
"manastorm:forensics": "node scripts/manastorm-import/forensics-cli.mjs",
"manastorm:sync": "npm run manastorm:import && npm run manastorm:forensics && npm run coa:icons",
@@ -91,7 +92,8 @@
"assets:ktx2:creatures": "node scripts/asset-pipeline/compress-creature-ktx2.mjs",
"assets:ktx2:audit": "node scripts/asset-pipeline/audit-ktx2.mjs --visual-only --require-all",
"assets:ktx2:refresh-metadata": "node scripts/asset-pipeline/refresh-ktx2-metadata.mjs",
"prebuild": "npm run loot:generate && npm run assets:ktx2:audit",
"assets:performance:audit": "node scripts/asset-pipeline/audit-environment-performance.mjs",
"prebuild": "npm run loot:generate && npm run assets:ktx2:audit && npm run assets:performance:audit",
"build": "node --max-old-space-size=8192 node_modules/typescript/bin/tsc -b && node --max-old-space-size=8192 node_modules/vite/bin/vite.js build",
"build:android:web": "npm run prebuild && npm run android:prepare && node --max-old-space-size=8192 node_modules/typescript/bin/tsc -b && node --max-old-space-size=8192 node_modules/vite/bin/vite.js build --mode android",
"android:sync": "npm run build:android:web && cap sync android",
@@ -13,8 +13,8 @@
{
"id": "visual",
"url": "/assets/game/manastorm/230-blackrockdepths/visual.glb",
"checksum": "42d57961c31f54ecc7bc78829751110fc89294e6318336b8f260e132e478d13d",
"byteLength": 10266900,
"checksum": "7e4c7c75a898f5000fcb686dcfc6d3c1c4e675dc3dac5f7a8d48e53372b9f364",
"byteLength": 7068884,
"triangleCount": 248302,
"compression": "meshopt+ktx2"
}
@@ -7,8 +7,8 @@
{
"id": "visual",
"url": "/assets/game/manastorm/230-blackrockdepths/visual.glb",
"checksum": "42d57961c31f54ecc7bc78829751110fc89294e6318336b8f260e132e478d13d",
"byteLength": 10266900,
"checksum": "7e4c7c75a898f5000fcb686dcfc6d3c1c4e675dc3dac5f7a8d48e53372b9f364",
"byteLength": 7068884,
"triangleCount": 248302,
"compression": "meshopt+ktx2"
}
+2 -2
View File
@@ -1,4 +1,4 @@
{
"versionName": "0.1.6",
"versionCode": 1006
"versionName": "0.1.7",
"versionCode": 1007
}
@@ -0,0 +1,121 @@
#!/usr/bin/env node
import { access, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { analyzeGlbFile } from "./glb-performance.mjs";
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const baselineFile = path.join(
projectRoot,
"scripts/asset-pipeline/environment-performance-baseline.json",
);
const defaultRoots = [
path.join(projectRoot, "public/assets/game/manastorm"),
path.join(projectRoot, "src/assets/game/dungeons"),
];
const defaultThresholds = {
maxEstimatedDrawCalls: 1_500,
maxUnbatchedDrawCallSavings: 250,
};
async function exists(file) {
try {
await access(file);
return true;
} catch {
return false;
}
}
async function collectVisualGlbs(root, files = []) {
if (!await exists(root)) return files;
const entry = await stat(root);
if (entry.isFile()) {
if (/(?:^|[-_])visual\.glb$/i.test(path.basename(root))) files.push(root);
return files;
}
for (const child of await readdir(root, { withFileTypes: true })) {
const target = path.join(root, child.name);
if (child.isDirectory()) await collectVisualGlbs(target, files);
else if (/(?:^|[-_])visual\.glb$/i.test(child.name)) files.push(target);
}
return files;
}
function projectPath(file) {
return path.relative(projectRoot, file).split(path.sep).join("/");
}
function exceeds(report, limits) {
return report.estimatedDrawCalls > limits.maxEstimatedDrawCalls
|| report.unbatchedDrawCallSavings > limits.maxUnbatchedDrawCallSavings;
}
const args = process.argv.slice(2);
const writeBaseline = args.includes("--write-baseline");
const roots = args.filter((argument) => argument !== "--write-baseline")
.map((argument) => path.resolve(projectRoot, argument));
const files = [...new Set((await Promise.all(
(roots.length ? roots : defaultRoots).map((root) => collectVisualGlbs(root)),
)).flat())].sort();
const reports = await Promise.all(files.map(async (file) => ({
file: projectPath(file),
byteLength: (await stat(file)).size,
...(await analyzeGlbFile(file)),
})));
if (writeBaseline) {
const baseline = {
schemaVersion: 1,
thresholds: defaultThresholds,
exceptions: Object.fromEntries(
reports
.filter((report) => exceeds(report, defaultThresholds))
.map((report) => [report.file, {
maxEstimatedDrawCalls: Math.max(defaultThresholds.maxEstimatedDrawCalls, report.estimatedDrawCalls),
maxUnbatchedDrawCallSavings: Math.max(
defaultThresholds.maxUnbatchedDrawCallSavings,
report.unbatchedDrawCallSavings,
),
}]),
),
};
await mkdir(path.dirname(baselineFile), { recursive: true });
await writeFile(baselineFile, `${JSON.stringify(baseline, null, 2)}\n`, "utf8");
console.log(`Wrote ${Object.keys(baseline.exceptions).length} performance exceptions to ${projectPath(baselineFile)}.`);
process.exit(0);
}
if (!await exists(baselineFile)) {
throw new Error(`Missing ${projectPath(baselineFile)}. Run this script with --write-baseline.`);
}
const baseline = JSON.parse(await readFile(baselineFile, "utf8"));
const thresholds = { ...defaultThresholds, ...baseline.thresholds };
const regressions = reports.filter((report) => {
const limits = { ...thresholds, ...baseline.exceptions?.[report.file] };
return exceeds(report, limits);
});
const debt = reports.filter((report) => exceeds(report, thresholds));
const top = [...reports]
.sort((left, right) => right.estimatedDrawCalls - left.estimatedDrawCalls)
.slice(0, 12)
.map((report) => ({
asset: report.file,
calls: report.estimatedDrawCalls,
avoidable: report.unbatchedDrawCallSavings,
gpuBatches: report.gpuInstanceBatches,
nodes: report.nodes,
}));
console.table(top);
console.log(JSON.stringify({
status: regressions.length ? "blocked" : "green",
assets: reports.length,
knownBudgetExceptions: debt.length,
regressions: regressions.map((report) => ({
file: report.file,
estimatedDrawCalls: report.estimatedDrawCalls,
unbatchedDrawCallSavings: report.unbatchedDrawCallSavings,
})),
}, null, 2));
if (regressions.length) process.exitCode = 1;
@@ -0,0 +1,249 @@
{
"schemaVersion": 1,
"thresholds": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 250
},
"exceptions": {
"public/assets/game/manastorm/109-sunkentemple/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 320
},
"public/assets/game/manastorm/129-razorfendowns/visual.glb": {
"maxEstimatedDrawCalls": 1507,
"maxUnbatchedDrawCallSavings": 1406
},
"public/assets/game/manastorm/1771-custom-marsh/visual.glb": {
"maxEstimatedDrawCalls": 2493,
"maxUnbatchedDrawCallSavings": 2114
},
"public/assets/game/manastorm/1774-custom-tropical/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 910
},
"public/assets/game/manastorm/1775-custom-tuskarr/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 500
},
"public/assets/game/manastorm/1776-custom-vrykul1/visual.glb": {
"maxEstimatedDrawCalls": 2223,
"maxUnbatchedDrawCallSavings": 1818
},
"public/assets/game/manastorm/1781-forgottenmine/visual.glb": {
"maxEstimatedDrawCalls": 5756,
"maxUnbatchedDrawCallSavings": 3818
},
"public/assets/game/manastorm/1785-valsharaharena/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 392
},
"public/assets/game/manastorm/1787-baradinholdarena/visual.glb": {
"maxEstimatedDrawCalls": 10462,
"maxUnbatchedDrawCallSavings": 9362
},
"public/assets/game/manastorm/1794-twistingnether/visual.glb": {
"maxEstimatedDrawCalls": 3077,
"maxUnbatchedDrawCallSavings": 2557
},
"public/assets/game/manastorm/209-tanarisinstance/visual.glb": {
"maxEstimatedDrawCalls": 4579,
"maxUnbatchedDrawCallSavings": 3547
},
"public/assets/game/manastorm/229-blackrockspire/visual.glb": {
"maxEstimatedDrawCalls": 3972,
"maxUnbatchedDrawCallSavings": 3598
},
"public/assets/game/manastorm/269-cavernsoftime/visual.glb": {
"maxEstimatedDrawCalls": 5446,
"maxUnbatchedDrawCallSavings": 5289
},
"public/assets/game/manastorm/289-schoolofnecromancy/visual.glb": {
"maxEstimatedDrawCalls": 5140,
"maxUnbatchedDrawCallSavings": 4790
},
"public/assets/game/manastorm/309-zul-gurub/visual.glb": {
"maxEstimatedDrawCalls": 17377,
"maxUnbatchedDrawCallSavings": 15605
},
"public/assets/game/manastorm/329-stratholme/visual.glb": {
"maxEstimatedDrawCalls": 2954,
"maxUnbatchedDrawCallSavings": 2725
},
"public/assets/game/manastorm/34-stormwindjail/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 487
},
"public/assets/game/manastorm/349-mauradon/visual.glb": {
"maxEstimatedDrawCalls": 5624,
"maxUnbatchedDrawCallSavings": 5352
},
"public/assets/game/manastorm/36-deadminesinstance/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 309
},
"public/assets/game/manastorm/389-orgrimmarinstance/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 881
},
"public/assets/game/manastorm/429-diremaul/visual.glb": {
"maxEstimatedDrawCalls": 5021,
"maxUnbatchedDrawCallSavings": 4636
},
"public/assets/game/manastorm/469-blackwinglair/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 452
},
"public/assets/game/manastorm/47-razorfenkraulinstance/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 897
},
"public/assets/game/manastorm/48-blackfathom/visual.glb": {
"maxEstimatedDrawCalls": 2164,
"maxUnbatchedDrawCallSavings": 1950
},
"public/assets/game/manastorm/509-ahnqiraj/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 600
},
"public/assets/game/manastorm/531-ahnqirajtemple/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 953
},
"public/assets/game/manastorm/532-karazahn/visual.glb": {
"maxEstimatedDrawCalls": 8540,
"maxUnbatchedDrawCallSavings": 7892
},
"public/assets/game/manastorm/533-stratholme-raid/visual.glb": {
"maxEstimatedDrawCalls": 4165,
"maxUnbatchedDrawCallSavings": 4014
},
"public/assets/game/manastorm/540-hellfiremilitary/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 1150
},
"public/assets/game/manastorm/542-hellfiredemon/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 444
},
"public/assets/game/manastorm/543-hellfirerampart/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 296
},
"public/assets/game/manastorm/545-coilfangpumping/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 674
},
"public/assets/game/manastorm/546-coilfangmarsh/visual.glb": {
"maxEstimatedDrawCalls": 3104,
"maxUnbatchedDrawCallSavings": 3033
},
"public/assets/game/manastorm/547-coilfangdraenei/visual.glb": {
"maxEstimatedDrawCalls": 1535,
"maxUnbatchedDrawCallSavings": 1455
},
"public/assets/game/manastorm/548-coilfangraid/visual.glb": {
"maxEstimatedDrawCalls": 1916,
"maxUnbatchedDrawCallSavings": 1683
},
"public/assets/game/manastorm/550-tempestkeepraid/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 420
},
"public/assets/game/manastorm/552-tempestkeeparcane/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 999
},
"public/assets/game/manastorm/553-tempestkeepatrium/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 1115
},
"public/assets/game/manastorm/554-tempestkeepfactory/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 872
},
"public/assets/game/manastorm/555-auchindounshadow/visual.glb": {
"maxEstimatedDrawCalls": 2624,
"maxUnbatchedDrawCallSavings": 2516
},
"public/assets/game/manastorm/556-auchindoundemon/visual.glb": {
"maxEstimatedDrawCalls": 2095,
"maxUnbatchedDrawCallSavings": 1987
},
"public/assets/game/manastorm/557-auchindounethereal/visual.glb": {
"maxEstimatedDrawCalls": 3164,
"maxUnbatchedDrawCallSavings": 3026
},
"public/assets/game/manastorm/558-auchindoundraenei/visual.glb": {
"maxEstimatedDrawCalls": 2613,
"maxUnbatchedDrawCallSavings": 2523
},
"public/assets/game/manastorm/560-hillsbradpast/visual.glb": {
"maxEstimatedDrawCalls": 28259,
"maxUnbatchedDrawCallSavings": 24733
},
"public/assets/game/manastorm/568-zulaman/visual.glb": {
"maxEstimatedDrawCalls": 4307,
"maxUnbatchedDrawCallSavings": 3850
},
"public/assets/game/manastorm/574-valgarde70/visual.glb": {
"maxEstimatedDrawCalls": 8271,
"maxUnbatchedDrawCallSavings": 7072
},
"public/assets/game/manastorm/575-utgardepinnacle/visual.glb": {
"maxEstimatedDrawCalls": 16277,
"maxUnbatchedDrawCallSavings": 14018
},
"public/assets/game/manastorm/576-nexus70/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 396
},
"public/assets/game/manastorm/578-nexus80/visual.glb": {
"maxEstimatedDrawCalls": 2283,
"maxUnbatchedDrawCallSavings": 1896
},
"public/assets/game/manastorm/585-sunwell5manfix/visual.glb": {
"maxEstimatedDrawCalls": 1810,
"maxUnbatchedDrawCallSavings": 1618
},
"public/assets/game/manastorm/595-stratholmecot/visual.glb": {
"maxEstimatedDrawCalls": 4353,
"maxUnbatchedDrawCallSavings": 3386
},
"public/assets/game/manastorm/600-draktheronkeep/visual.glb": {
"maxEstimatedDrawCalls": 3518,
"maxUnbatchedDrawCallSavings": 2876
},
"public/assets/game/manastorm/602-ulduar80/visual.glb": {
"maxEstimatedDrawCalls": 1973,
"maxUnbatchedDrawCallSavings": 1295
},
"public/assets/game/manastorm/619-azjol-lowercity/visual.glb": {
"maxEstimatedDrawCalls": 1596,
"maxUnbatchedDrawCallSavings": 1243
},
"public/assets/game/manastorm/658-quarryoftears/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 618
},
"public/assets/game/manastorm/668-hallsofreflection/visual.glb": {
"maxEstimatedDrawCalls": 5464,
"maxUnbatchedDrawCallSavings": 4606
},
"public/assets/game/manastorm/70-uldaman/visual.glb": {
"maxEstimatedDrawCalls": 3268,
"maxUnbatchedDrawCallSavings": 3115
},
"public/assets/game/manastorm/821-tinketechshowdown/visual.glb": {
"maxEstimatedDrawCalls": 2585,
"maxUnbatchedDrawCallSavings": 2379
},
"public/assets/game/manastorm/90-gnomeragoninstance/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 1051
},
"public/assets/game/manastorm/908-alvaencounter/visual.glb": {
"maxEstimatedDrawCalls": 1500,
"maxUnbatchedDrawCallSavings": 1096
}
}
}
@@ -0,0 +1,98 @@
import { open } from "node:fs/promises";
const GLB_MAGIC = 0x46546c67;
const JSON_CHUNK_TYPE = 0x4e4f534a;
const GPU_INSTANCING_EXTENSION = "EXT_mesh_gpu_instancing";
function primitiveCount(json, meshIndex) {
return json.meshes?.[meshIndex]?.primitives?.length ?? 0;
}
function gpuInstanceCount(json, node) {
const attributes = node.extensions?.[GPU_INSTANCING_EXTENSION]?.attributes;
if (!attributes || typeof attributes !== "object") return 0;
return Math.max(
0,
...Object.values(attributes).map((accessorIndex) => (
json.accessors?.[accessorIndex]?.count ?? 0
)),
);
}
export function analyzeGlbJson(json) {
const repeatedMeshes = new Map();
let estimatedDrawCalls = 0;
let expandedPrimitiveInstances = 0;
let meshNodes = 0;
let gpuInstanceBatches = 0;
let gpuInstances = 0;
for (const node of json.nodes ?? []) {
if (!Number.isInteger(node.mesh)) continue;
meshNodes += 1;
const primitives = primitiveCount(json, node.mesh);
const instances = gpuInstanceCount(json, node);
estimatedDrawCalls += primitives;
expandedPrimitiveInstances += primitives * Math.max(1, instances);
if (instances > 0) {
gpuInstanceBatches += 1;
gpuInstances += instances;
continue;
}
repeatedMeshes.set(node.mesh, (repeatedMeshes.get(node.mesh) ?? 0) + 1);
}
let eligibleRepeatedMeshes = 0;
let eligibleRepeatedNodes = 0;
let unbatchedDrawCallSavings = 0;
for (const [meshIndex, count] of repeatedMeshes) {
if (count < 3) continue;
eligibleRepeatedMeshes += 1;
eligibleRepeatedNodes += count;
unbatchedDrawCallSavings += (count - 1) * primitiveCount(json, meshIndex);
}
const materials = json.materials ?? [];
return {
nodes: json.nodes?.length ?? 0,
meshNodes,
meshes: json.meshes?.length ?? 0,
materials: materials.length,
textures: json.textures?.length ?? 0,
doubleSidedMaterials: materials.filter((material) => material.doubleSided === true).length,
blendedMaterials: materials.filter((material) => material.alphaMode === "BLEND").length,
estimatedDrawCalls,
expandedPrimitiveInstances,
gpuInstanceBatches,
gpuInstances,
eligibleRepeatedMeshes,
eligibleRepeatedNodes,
unbatchedDrawCallSavings,
usesGpuInstancing: (json.extensionsUsed ?? []).includes(GPU_INSTANCING_EXTENSION),
};
}
export async function readGlbJson(file) {
const handle = await open(file, "r");
try {
const header = Buffer.alloc(20);
const { bytesRead } = await handle.read(header, 0, header.length, 0);
if (bytesRead !== header.length
|| header.readUInt32LE(0) !== GLB_MAGIC
|| header.readUInt32LE(4) !== 2
|| header.readUInt32LE(16) !== JSON_CHUNK_TYPE) {
throw new Error(`${file} is not a supported GLB 2.0 file.`);
}
const jsonLength = header.readUInt32LE(12);
const jsonBuffer = Buffer.alloc(jsonLength);
const jsonRead = await handle.read(jsonBuffer, 0, jsonLength, 20);
if (jsonRead.bytesRead !== jsonLength) throw new Error(`${file} has a truncated JSON chunk.`);
return JSON.parse(jsonBuffer.toString("utf8"));
} finally {
await handle.close();
}
}
export async function analyzeGlbFile(file) {
return analyzeGlbJson(await readGlbJson(file));
}
@@ -0,0 +1,54 @@
import assert from "node:assert/strict";
import test from "node:test";
import { analyzeGlbJson } from "./glb-performance.mjs";
test("counts repeated mesh placements as avoidable draw calls", () => {
const report = analyzeGlbJson({
meshes: [
{ primitives: [{}, {}] },
{ primitives: [{}] },
],
nodes: [
{ mesh: 0 },
{ mesh: 0 },
{ mesh: 0 },
{ mesh: 1 },
],
materials: [
{ doubleSided: true, alphaMode: "BLEND" },
{},
],
textures: [{}, {}],
});
assert.equal(report.estimatedDrawCalls, 7);
assert.equal(report.expandedPrimitiveInstances, 7);
assert.equal(report.eligibleRepeatedMeshes, 1);
assert.equal(report.eligibleRepeatedNodes, 3);
assert.equal(report.unbatchedDrawCallSavings, 4);
assert.equal(report.doubleSidedMaterials, 1);
assert.equal(report.blendedMaterials, 1);
});
test("counts one draw-call set for an EXT_mesh_gpu_instancing batch", () => {
const report = analyzeGlbJson({
extensionsUsed: ["EXT_mesh_gpu_instancing"],
accessors: [{ count: 12 }],
meshes: [{ primitives: [{}, {}, {}] }],
nodes: [{
mesh: 0,
extensions: {
EXT_mesh_gpu_instancing: {
attributes: { TRANSLATION: 0 },
},
},
}],
});
assert.equal(report.estimatedDrawCalls, 3);
assert.equal(report.expandedPrimitiveInstances, 36);
assert.equal(report.gpuInstanceBatches, 1);
assert.equal(report.gpuInstances, 12);
assert.equal(report.unbatchedDrawCallSavings, 0);
assert.equal(report.usesGpuInstancing, true);
});
+106
View File
@@ -0,0 +1,106 @@
import {
mkdirSync,
readFileSync,
readdirSync,
unlinkSync,
writeFileSync,
} from "node:fs";
import { basename, resolve } from "node:path";
import {
CLASSES,
COA_CLASS_IDS,
type ClassId,
type CoaClassId,
} from "../src/app/characterCatalog";
import { TALENT_NODES, TALENT_TREES } from "../src/game/talentCatalog";
const projectRoot = resolve(import.meta.dirname, "..");
const talentOutputDirectory = resolve(projectRoot, "src/game/generated/talentUi");
const coaAbilityOutputDirectory = resolve(projectRoot, "src/game/generated/coaAbilities");
function writeJson(file: string, value: unknown): void {
writeFileSync(file, `${JSON.stringify(value)}\n`, "utf8");
console.log(`Wrote ${file}`);
}
function removeStaleJson(directory: string, expectedNames: ReadonlySet<string>): void {
for (const name of readdirSync(directory)) {
if (!name.endsWith(".json") || expectedNames.has(name)) continue;
unlinkSync(resolve(directory, name));
}
}
mkdirSync(talentOutputDirectory, { recursive: true });
const talentClassIds = new Set<ClassId>(TALENT_TREES.map((tree) => tree.classId));
const talentFileNames = new Set([...talentClassIds].map((classId) => `${classId}.json`));
removeStaleJson(talentOutputDirectory, talentFileNames);
for (const classId of talentClassIds) {
const trees = TALENT_TREES.filter((tree) => tree.classId === classId).map((tree) => ({
id: tree.id,
classId: tree.classId,
name: tree.name,
icon: tree.icon,
background: tree.background,
description: tree.description,
system: tree.system,
}));
const treeIds = new Set(trees.map((tree) => tree.id));
const nodes = TALENT_NODES.filter((node) => treeIds.has(node.treeId)).map((node) => ({
id: node.id,
treeId: node.treeId,
index: node.index,
prerequisiteId: node.prerequisiteId,
prerequisiteRank: node.prerequisiteRank,
prerequisites: node.prerequisites,
column: node.column,
row: node.row,
icon: node.icon,
maxRank: node.maxRank,
name: node.name,
description: node.description,
rankDescriptions: node.rankDescriptions,
system: node.system,
entryType: node.entryType,
abilityEssenceCost: node.abilityEssenceCost,
talentEssenceCost: node.talentEssenceCost,
requiredClassPoints: node.requiredClassPoints,
requiredSpecPoints: node.requiredSpecPoints,
requiredLevel: node.requiredLevel,
isPassive: node.isPassive,
}));
writeJson(resolve(talentOutputDirectory, `${classId}.json`), {
schemaVersion: 1,
classId,
trees,
nodes,
});
}
interface CoaAbilitySnapshot {
readonly schemaVersion: 1;
readonly abilitiesByClass: Readonly<Record<CoaClassId, readonly unknown[]>>;
readonly resourcesByClass: Readonly<Record<CoaClassId, unknown>>;
readonly triggeredAbilitiesBySpellId: Readonly<Record<string, { readonly classId?: ClassId }>>;
}
const coaAbilityInput = resolve(projectRoot, "src/game/generated/coaAbilityRuntimeCatalog.json");
const coaSnapshot = JSON.parse(readFileSync(coaAbilityInput, "utf8")) as CoaAbilitySnapshot;
mkdirSync(coaAbilityOutputDirectory, { recursive: true });
const coaAbilityFileNames = new Set(COA_CLASS_IDS.map((classId) => `${classId}.json`));
removeStaleJson(coaAbilityOutputDirectory, coaAbilityFileNames);
for (const classId of COA_CLASS_IDS) {
const triggeredAbilitiesBySpellId = Object.fromEntries(Object.entries(
coaSnapshot.triggeredAbilitiesBySpellId,
).filter(([, ability]) => ability.classId === classId));
writeJson(resolve(coaAbilityOutputDirectory, `${classId}.json`), {
schemaVersion: 1,
classId,
abilities: coaSnapshot.abilitiesByClass[classId] ?? [],
resource: coaSnapshot.resourcesByClass[classId],
triggeredAbilitiesBySpellId,
});
}
console.log(`Generated ${talentFileNames.size} talent UI shards and ${coaAbilityFileNames.size} Conquest ability shards from ${basename(coaAbilityInput)}.`);
+25 -8
View File
@@ -404,15 +404,23 @@ async function optimizeStage(slug) {
const source = path.join(staging, entry.path);
const outputName = optimizedChunkName(role, index, entries.length);
const output = path.join(staging, outputName);
await run(process.execPath, [
cli,
"meshopt",
source,
output,
"--level",
"high",
]);
if (role === "visual") {
await run(process.execPath, [
cli,
"optimize",
source,
output,
"--compress",
"meshopt",
"--meshopt-level",
"high",
"--instance",
"true",
"--instance-min",
"3",
"--texture-size",
"2048",
]);
await run(process.execPath, [
path.join(projectRoot, "scripts/asset-pipeline/compress-ktx2.mjs"),
output,
@@ -421,6 +429,15 @@ async function optimizeStage(slug) {
"--jobs",
"2",
]);
} else {
await run(process.execPath, [
cli,
"meshopt",
source,
output,
"--level",
"high",
]);
}
const geometry = await inspectGlb(output);
const descriptor = {
+38 -2
View File
@@ -1,5 +1,7 @@
import { lazy, Suspense, useEffect } from "react";
import { lazy, Suspense, useEffect, useMemo, useState, type ReactNode } from "react";
import { BASE_CLASS_IDS, classById } from "./app/characterCatalog";
import { useShellStore } from "./app/shellStore";
import { preloadAbilityCatalogsForClasses } from "./game/abilityCatalog";
import { useManastormAdminStore } from "./game/manastormAdminStore";
import { useAuthoritativeDualScreenSync, useForcedThorDisplays } from "./platform/useThorDualScreen";
import { LoginScreen } from "./ui/LoginScreen";
@@ -18,6 +20,39 @@ function ShellTransition() {
return <div className="world-transition"><span>HM</span><strong>Opening expedition</strong><small>Preparing the next screen...</small></div>;
}
function RuntimeCatalogGate({ children }: { readonly children: ReactNode }) {
const character = useShellStore((state) => (
state.characters.find((candidate) => candidate.id === state.selectedCharacterId) ?? null
));
const classIds = useMemo(() => {
if (!character) return [];
const definition = classById(character.classId);
if (definition.mode === "conquest") return [...BASE_CLASS_IDS, character.classId];
return [character.classId, ...(character.secondaryClassId ? [character.secondaryClassId] : [])];
}, [character]);
const requestKey = classIds.join(":");
const [loadedKey, setLoadedKey] = useState("");
const [failedKey, setFailedKey] = useState("");
useEffect(() => {
if (!requestKey) return;
let active = true;
setFailedKey("");
void preloadAbilityCatalogsForClasses(classIds).then(() => {
if (active) setLoadedKey(requestKey);
}).catch(() => {
if (active) setFailedKey(requestKey);
});
return () => { active = false; };
}, [classIds, requestKey]);
if (!requestKey || loadedKey === requestKey) return children;
if (failedKey === requestKey) {
return <div className="world-transition"><span>!</span><strong>Catalog unavailable</strong><small>Reload the app to retry loading combat data.</small></div>;
}
return <ShellTransition />;
}
export default function App() {
useForcedThorDisplays();
useAuthoritativeDualScreenSync();
@@ -39,5 +74,6 @@ export default function App() {
else if (phase === "manastorms") screen = <Suspense fallback={<ShellTransition />}><ManastormSelectScreen /></Suspense>;
else if (phase === "gm-admin") screen = <Suspense fallback={<ShellTransition />}><GmAdminScreen /></Suspense>;
else if (phase === "game") screen = <Suspense fallback={<ShellTransition />}><GameRuntime /></Suspense>;
return <><OnlineGroupCoordinator />{screen}</>;
const requiresRuntimeCatalog = !["login", "characters", "create-character"].includes(phase);
return <><OnlineGroupCoordinator />{requiresRuntimeCatalog ? <RuntimeCatalogGate>{screen}</RuntimeCatalogGate> : screen}</>;
}
+141 -41
View File
@@ -1,13 +1,18 @@
import type { ClassId } from "../app/characterCatalog";
import {
COA_RUNTIME_ABILITIES_BY_CLASS as COA_ABILITIES_BY_CLASS,
COA_RUNTIME_CLASS_RESOURCES as COA_CLASS_RESOURCES,
} from "./coaAbilityRuntimeCatalog";
import { WOW335_ABILITIES_BY_CLASS } from "./wow335AbilityCatalog";
import { ROM_ALL_ABILITIES, ROM_ELITE_ABILITIES, ROM_ORDINARY_ABILITIES_BY_CLASS, type RomSkillGroup } from "./romAbilityCatalog";
BASE_CLASS_IDS,
COA_CLASS_IDS,
ROM_CLASS_IDS,
type BaseClassId,
type ClassId,
type CoaClassId,
type RomClassId,
} from "../app/characterCatalog";
import { loadCoaAbilityCatalogShard } from "./coaAbilityCatalogLoader";
import { registerAbilityAnimationLookup } from "./abilityAnimationLookup";
import type { AuraDefinition, DamageSchool, DispelCategory } from "./combatAuras";
export type RomSkillGroup = "primary" | "general" | "elite" | "passive";
export type ResourceType =
| "mana"
| "rage"
@@ -301,7 +306,7 @@ function defineAbility(definition: AbilityDefinitionInput): AbilityDefinition {
};
}
export const CLASS_RESOURCES: Readonly<Record<ClassId, ClassResourceProfile>> = {
const classResources: Partial<Record<ClassId, ClassResourceProfile>> = {
// The prototype has no auto-attack swing timer yet, so a small passive Rage
// gain stands in for white-hit generation and keeps the full kit usable.
warrior: { type: "rage", name: "Rage", color: "#b74439", maximum: 100, initial: 0, regenerationPerSecond: 5 },
@@ -314,7 +319,6 @@ export const CLASS_RESOURCES: Readonly<Record<ClassId, ClassResourceProfile>> =
mage: { type: "mana", name: "Mana", color: "#397dcc", maximum: 100, initial: 100, regenerationPerSecond: 4 },
warlock: { type: "mana", name: "Mana", color: "#397dcc", maximum: 100, initial: 100, regenerationPerSecond: 4 },
druid: { type: "mana", name: "Mana", color: "#397dcc", maximum: 100, initial: 100, regenerationPerSecond: 4 },
...COA_CLASS_RESOURCES,
"rom-warrior": { type: "rage", name: "Rage", color: "#b74439", maximum: 100, initial: 0, regenerationPerSecond: 0 },
"rom-scout": { type: "focus", name: "Focus", color: "#55b995", maximum: 100, initial: 100, regenerationPerSecond: 6 },
"rom-rogue": { type: "energy", name: "Energy", color: "#d8c43f", maximum: 100, initial: 100, regenerationPerSecond: 10 },
@@ -327,6 +331,9 @@ export const CLASS_RESOURCES: Readonly<Record<ClassId, ClassResourceProfile>> =
"rom-champion": { type: "rage", name: "Rage", color: "#bb604c", maximum: 100, initial: 0, regenerationPerSecond: 0 },
};
/** Populated per mode/class by preloadAbilityCatalogsForClasses before gameplay mounts. */
export const CLASS_RESOURCES = classResources as Readonly<Record<ClassId, ClassResourceProfile>>;
const WARRIOR = [
defineAbility({
id: "warrior-heroic-strike", classId: "warrior", dbcSpellId: 78, name: "Heroic Strike",
@@ -789,48 +796,131 @@ function mergeWow335ClassicAbilities(
];
}
export const ABILITIES_BY_CLASS: Readonly<Record<ClassId, readonly AbilityDefinition[]>> = {
warrior: mergeWow335ClassicAbilities(WARRIOR, WOW335_ABILITIES_BY_CLASS.warrior),
paladin: mergeWow335ClassicAbilities(PALADIN, WOW335_ABILITIES_BY_CLASS.paladin),
hunter: mergeWow335ClassicAbilities(HUNTER, WOW335_ABILITIES_BY_CLASS.hunter),
rogue: mergeWow335ClassicAbilities(ROGUE, WOW335_ABILITIES_BY_CLASS.rogue),
priest: mergeWow335ClassicAbilities(PRIEST, WOW335_ABILITIES_BY_CLASS.priest),
"death-knight": mergeWow335ClassicAbilities(DEATH_KNIGHT, WOW335_ABILITIES_BY_CLASS["death-knight"]),
shaman: mergeWow335ClassicAbilities(SHAMAN, WOW335_ABILITIES_BY_CLASS.shaman),
mage: mergeWow335ClassicAbilities(MAGE, WOW335_ABILITIES_BY_CLASS.mage),
warlock: mergeWow335ClassicAbilities(WARLOCK, WOW335_ABILITIES_BY_CLASS.warlock),
druid: mergeWow335ClassicAbilities(DRUID, WOW335_ABILITIES_BY_CLASS.druid),
...COA_ABILITIES_BY_CLASS,
"rom-warrior": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-warrior"],
"rom-scout": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-scout"],
"rom-rogue": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-rogue"],
"rom-mage": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-mage"],
"rom-priest": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-priest"],
"rom-knight": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-knight"],
"rom-warden": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-warden"],
"rom-druid": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-druid"],
"rom-warlock": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-warlock"],
"rom-champion": ROM_ORDINARY_ABILITIES_BY_CLASS["rom-champion"],
const CLASSIC_CORE_ABILITIES: Readonly<Record<BaseClassId, readonly AbilityDefinition[]>> = {
warrior: WARRIOR,
paladin: PALADIN,
hunter: HUNTER,
rogue: ROGUE,
priest: PRIEST,
"death-knight": DEATH_KNIGHT,
shaman: SHAMAN,
mage: MAGE,
warlock: WARLOCK,
druid: DRUID,
};
const abilitiesByClass: Partial<Record<ClassId, readonly AbilityDefinition[]>> = {
...CLASSIC_CORE_ABILITIES,
};
const abilityCatalog: Record<string, AbilityDefinition> = {};
let romEliteAbilities: readonly AbilityDefinition[] = [];
let romTriggeredAbilityResolver: ((spellId: number) => AbilityDefinition | null) | null = null;
const coaTriggeredAbilities = new Map<number, AbilityDefinition>();
let classicLoad: Promise<void> | null = null;
let romLoad: Promise<void> | null = null;
const coaLoads = new Map<CoaClassId, Promise<void>>();
export const ABILITY_CATALOG: Readonly<Record<string, AbilityDefinition>> = Object.freeze(
Object.fromEntries([...Object.values(ABILITIES_BY_CLASS).flat(), ...ROM_ALL_ABILITIES].map((ability) => [ability.id, ability])),
);
/** Live read-only views retained for catalog consumers and validation tests. */
export const ABILITIES_BY_CLASS = abilitiesByClass as Readonly<Record<ClassId, readonly AbilityDefinition[]>>;
export const ABILITY_CATALOG = abilityCatalog as Readonly<Record<string, AbilityDefinition>>;
function registerClassAbilities(classId: ClassId, abilities: readonly AbilityDefinition[]): void {
for (const previous of abilitiesByClass[classId] ?? []) delete abilityCatalog[previous.id];
abilitiesByClass[classId] = abilities;
for (const ability of abilities) abilityCatalog[ability.id] = ability;
}
for (const classId of BASE_CLASS_IDS) {
registerClassAbilities(classId, CLASSIC_CORE_ABILITIES[classId]);
}
async function preloadClassicAbilityCatalog(): Promise<void> {
if (classicLoad) return classicLoad;
classicLoad = import("./wow335AbilityCatalog").then(({ WOW335_ABILITIES_BY_CLASS }) => {
for (const classId of BASE_CLASS_IDS) {
registerClassAbilities(
classId,
mergeWow335ClassicAbilities(CLASSIC_CORE_ABILITIES[classId], WOW335_ABILITIES_BY_CLASS[classId]),
);
}
}).catch((error: unknown) => {
classicLoad = null;
throw error;
});
return classicLoad;
}
async function preloadRomAbilityCatalog(): Promise<void> {
if (romLoad) return romLoad;
romLoad = import("./romAbilityCatalog").then((catalog) => {
for (const classId of ROM_CLASS_IDS) {
registerClassAbilities(classId, catalog.ROM_ORDINARY_ABILITIES_BY_CLASS[classId]);
}
romEliteAbilities = catalog.ROM_ELITE_ABILITIES;
romTriggeredAbilityResolver = catalog.romTriggeredAbilityBySpellId;
for (const ability of catalog.ROM_ALL_ABILITIES) abilityCatalog[ability.id] = ability;
}).catch((error: unknown) => {
romLoad = null;
throw error;
});
return romLoad;
}
async function preloadCoaAbilityCatalog(classId: CoaClassId): Promise<void> {
const cached = coaLoads.get(classId);
if (cached) return cached;
const pending = loadCoaAbilityCatalogShard(classId).then((shard) => {
registerClassAbilities(classId, shard.abilities);
classResources[classId] = shard.resource;
for (const [spellId, ability] of Object.entries(shard.triggeredAbilitiesBySpellId)) {
coaTriggeredAbilities.set(Number(spellId), ability);
}
}).catch((error: unknown) => {
coaLoads.delete(classId);
throw error;
});
coaLoads.set(classId, pending);
return pending;
}
/**
* Loads only the executable catalogs needed by the selected character and its
* party mode. Callers gate gameplay mounting on this promise so combat APIs can
* stay synchronous inside the simulation loop.
*/
export async function preloadAbilityCatalogsForClasses(classIds: readonly ClassId[]): Promise<void> {
const requested = new Set(classIds);
const loads: Promise<void>[] = [];
if (BASE_CLASS_IDS.some((classId) => requested.has(classId))) loads.push(preloadClassicAbilityCatalog());
if (ROM_CLASS_IDS.some((classId) => requested.has(classId))) loads.push(preloadRomAbilityCatalog());
for (const classId of COA_CLASS_IDS) {
if (requested.has(classId)) loads.push(preloadCoaAbilityCatalog(classId));
}
await Promise.all(loads);
}
export function triggeredAbilityBySpellId(
spellId: number,
includeCoa = true,
): AbilityDefinition | null {
return romTriggeredAbilityResolver?.(spellId)
?? (includeCoa ? coaTriggeredAbilities.get(spellId) : undefined)
?? null;
}
export function abilitiesForClass(classId: ClassId): readonly AbilityDefinition[] {
return ABILITIES_BY_CLASS[classId];
return abilitiesByClass[classId] ?? [];
}
export function abilitiesForCharacter(
classId: ClassId,
secondaryClassId: ClassId | null | undefined,
): readonly AbilityDefinition[] {
if (!classId.startsWith("rom-") || !secondaryClassId?.startsWith("rom-")) return ABILITIES_BY_CLASS[classId];
const primary = ABILITIES_BY_CLASS[classId];
const secondaryGeneral = ABILITIES_BY_CLASS[secondaryClassId].filter((ability) => (
if (!classId.startsWith("rom-") || !secondaryClassId?.startsWith("rom-")) return abilitiesForClass(classId);
const primary = abilitiesForClass(classId);
const secondaryGeneral = abilitiesForClass(secondaryClassId).filter((ability) => (
ability.romSkillGroup === "general" || (ability.romSkillGroup === "passive" && ability.id.includes("-general-"))
));
const elites = ROM_ELITE_ABILITIES.filter((ability) => ability.classId === classId && ability.secondaryClassId === secondaryClassId);
const elites = romEliteAbilities.filter((ability) => ability.classId === classId && ability.secondaryClassId === secondaryClassId);
return [...primary, ...secondaryGeneral, ...elites];
}
@@ -885,7 +975,7 @@ export function abilitiesUnlockedBetweenLevels(
previousLevel: number,
currentLevel: number,
): readonly AbilityDefinition[] {
return ABILITIES_BY_CLASS[classId].filter((ability) => (
return abilitiesForClass(classId).filter((ability) => (
ability.unlockLevel > previousLevel && ability.unlockLevel <= currentLevel
));
}
@@ -920,7 +1010,7 @@ export function defaultActionBarForClass(classId: ClassId): readonly string[] {
|| effect.kind === "rune"
|| effect.kind === "trigger-spell"
)) ? 0 : 1;
const ordered = ABILITIES_BY_CLASS[classId]
const ordered = abilitiesForClass(classId)
.map((ability, index) => ({ ability, index }))
.sort((left, right) => (
left.ability.unlockLevel - right.ability.unlockLevel
@@ -962,5 +1052,15 @@ export function defaultActionBarForCharacter(classId: ClassId, secondaryClassId?
}
export function resourceProfileForClass(classId: ClassId): ClassResourceProfile {
return CLASS_RESOURCES[classId];
const profile = classResources[classId];
if (!profile) throw new Error(`Ability catalog for ${classId} was used before it was loaded.`);
return profile;
}
if (import.meta.env.MODE === "test") {
await preloadAbilityCatalogsForClasses([
...BASE_CLASS_IDS,
...COA_CLASS_IDS,
...ROM_CLASS_IDS,
]);
}
+18
View File
@@ -0,0 +1,18 @@
import { describe, expect, it } from "vitest";
import { loadCoaAbilityCatalogShard } from "./coaAbilityCatalogLoader";
import {
COA_RUNTIME_ABILITIES_BY_CLASS,
COA_RUNTIME_CLASS_RESOURCES,
} from "./coaAbilityRuntimeCatalog";
describe("Conquest ability catalog shards", () => {
it.each(["barbarian", "runemaster"] as const)("loads only the %s executable catalog", async (classId) => {
const shard = await loadCoaAbilityCatalogShard(classId);
expect(shard.classId).toBe(classId);
expect(shard.abilities).toEqual(COA_RUNTIME_ABILITIES_BY_CLASS[classId]);
expect(shard.resource).toEqual(COA_RUNTIME_CLASS_RESOURCES[classId]);
expect(Object.values(shard.triggeredAbilitiesBySpellId).every((ability) => (
ability.classId === classId
))).toBe(true);
});
});
+36
View File
@@ -0,0 +1,36 @@
import type { CoaClassId } from "../app/characterCatalog";
import type { AbilityDefinition, ClassResourceProfile } from "./abilityCatalog";
export interface CoaAbilityCatalogShard {
readonly schemaVersion: 1;
readonly classId: CoaClassId;
readonly abilities: readonly AbilityDefinition[];
readonly resource: ClassResourceProfile;
readonly triggeredAbilitiesBySpellId: Readonly<Record<number, AbilityDefinition>>;
}
interface CoaAbilityCatalogShardModule {
readonly default: CoaAbilityCatalogShard;
}
const shardLoaders = import.meta.glob<CoaAbilityCatalogShardModule>("./generated/coaAbilities/*.json");
const loadCache = new Map<CoaClassId, Promise<CoaAbilityCatalogShard>>();
export function loadCoaAbilityCatalogShard(classId: CoaClassId): Promise<CoaAbilityCatalogShard> {
const cached = loadCache.get(classId);
if (cached) return cached;
const key = `./generated/coaAbilities/${classId}.json`;
const loader = shardLoaders[key];
if (!loader) return Promise.reject(new Error(`No Conquest ability catalog exists for ${classId}.`));
const pending = loader().then((module) => {
if (module.default.schemaVersion !== 1 || module.default.classId !== classId) {
throw new Error(`Conquest ability catalog ${classId} has incompatible metadata.`);
}
return module.default;
}).catch((error: unknown) => {
loadCache.delete(classId);
throw error;
});
loadCache.set(classId, pending);
return pending;
}
+2 -3
View File
@@ -16,6 +16,7 @@ import {
defaultActionBarForCharacter,
isAbilityUnlocked,
resourceProfileForClass,
triggeredAbilityBySpellId,
type AbilityAmountScaling,
type AbilityDefinition,
type AbilityEffect,
@@ -57,8 +58,6 @@ import {
spendDeathKnightRunes,
} from "./combatResources";
import { resolveHealing, type HealingResolution } from "./combatHealing";
import { romTriggeredAbilityBySpellId } from "./romAbilityCatalog";
import { coaTriggeredAbilityBySpellId } from "./coaAbilityRuntimeCatalog";
import {
awardExperience,
healerManExperienceAward,
@@ -2578,7 +2577,7 @@ function executeTriggeredSpellInWork(
const catalogAbility = work.abilities.find((candidate) => (
candidate.dbcSpellId === spellId
|| candidate.ranks?.some((rank) => rank.spellId === spellId)
)) ?? romTriggeredAbilityBySpellId(spellId) ?? (allowCoaHidden ? coaTriggeredAbilityBySpellId(spellId) : null);
)) ?? triggeredAbilityBySpellId(spellId, allowCoaHidden);
if (!catalogAbility) return;
const ability = abilityAtLevel(catalogAbility, work.progression.level);
const source = playerThreatSource({ talentModifiers: work.talentModifiers }, ability.id, true);
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"barbarian","abilities":[{"id":"coa-tree-30762","classId":"barbarian","dbcSpellId":500918,"name":"Ancestral Roar","unlockLevel":1,"icon":"/assets/ui/spells/_d3threateningshout.png","sigil":"AR","description":"Ancestral RoarRank 1Instant cast25 sec cooldownRequires Enraged Roar with ancestral fervor, healing you for 100+0+AP*0.5.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":25000,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"heal","coefficient":1.6580645243326824,"basePoints":100,"dieSides":7,"pointsPerLevel":3.200000047683716,"bonusPowerCoefficient":0,"sourceLevel":16,"maxScalingLevel":22},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":3,"triggerSpellId":0,"durationMs":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":500918,"level":1,"description":"Ancestral RoarRank 1Instant cast25 sec cooldownRequires Enraged Roar with ancestral fervor, healing you for 100+0+AP*0.5.","castMode":"instant","castTimeMs":0,"cooldownMs":25000,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"heal","coefficient":1.6580645243326824,"basePoints":100,"dieSides":7,"pointsPerLevel":3.200000047683716,"bonusPowerCoefficient":0,"sourceLevel":16,"maxScalingLevel":22},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":3,"triggerSpellId":0,"durationMs":0}]}],"talentEntryId":30762},{"id":"coa-12-ancestral-spirit-47-705153","classId":"barbarian","dbcSpellId":705153,"name":"Ancestral Spirit","unlockLevel":1,"icon":"/assets/ui/spells/inv_misc_questionmark.png","sigil":"AS","description":"Ancestral SpiritRank 1Reduces the Energy cost of your Spirit spells and increases the duration of your Shouts by 50%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705153:effect:0:aura:108","name":"Ancestral Spirit (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.5}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":14,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705153:effect:1:aura:108","name":"Ancestral Spirit (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.5}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":1,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":705153,"level":1,"description":"Ancestral SpiritRank 1Reduces the Energy cost of your Spirit spells and increases the duration of your Shouts by 50%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705153:effect:0:aura:108","name":"Ancestral Spirit (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.5}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":14,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705153:effect:1:aura:108","name":"Ancestral Spirit (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.5}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":1,"triggerSpellId":0}]},{"rank":2,"spellId":705154,"level":1,"description":"Ancestral SpiritRank 2Reduces the Energy cost of your Spirit spells and increases the duration of your Shouts by 100%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705154:effect:0:aura:108","name":"Ancestral Spirit (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":14,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705154:effect:1:aura:108","name":"Ancestral Spirit (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":1,"triggerSpellId":0}]}]},{"id":"coa-tree-34279","classId":"barbarian","dbcSpellId":560456,"name":"Athleticism","unlockLevel":1,"icon":"/assets/ui/spells/5_run_border.png","sigil":"AT","descriptiLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"bloodmage","abilities":[{"id":"coa-tree-29871","classId":"bloodmage","dbcSpellId":504285,"name":"Alacrity","unlockLevel":1,"icon":"/assets/ui/spells/5_run_border.png","sigil":"AL","description":"Increases all primary stats by 4%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:504285:effect:0:aura:137","name":"Alacrity (Aura 137)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"all-primary","operation":"percent","value":0.04}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":137,"miscValue":-1,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":504285,"level":1,"description":"Increases all primary stats by 4%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:504285:effect:0:aura:137","name":"Alacrity (Aura 137)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"all-primary","operation":"percent","value":0.04}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":137,"miscValue":-1,"triggerSpellId":0}]},{"rank":2,"spellId":504893,"level":1,"description":"Increases all primary stats by 8%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:504893:effect:0:aura:137","name":"Alacrity (Aura 137)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"all-primary","operation":"percent","value":0.08}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":137,"miscValue":-1,"triggerSpellId":0}]}],"talentEntryId":29871},{"id":"coa-20-atheranns-wickedness-73-704642","classId":"bloodmage","dbcSpellId":704642,"name":"Atherann's Wickedness","unlockLevel":1,"icon":"/assets/ui/spells/spell_shadow_destructivesoul.png","sigil":"AS","description":"Atherann's WickednessRank 1Increases your Shadow damage dealt by 4% and increases your hit chance by 3%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704642:effect:0:aura:79","name":"Atherann's Wickedness (Aura 79)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"dealt","school":"shadow","operation":"percent","value":0.04}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":79,"miscValue":32,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:704642:effect:1:aura:333","name":"Atherann's Wickedness (Aura 333)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":333,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":704642,"level":1,"description":"Atherann's WickednessRank 1Increases your Shadow damage dealt by 4% and increases your hit chance by 3%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704642:effect:0:aura:79","name":"Atherann's Wickedness (Aura 79)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"dealt","school":"shadow","operation":"percent","value":0.04}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":79,"miscValue":32,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:704642:effect:1:aura:333","name":"Atherann's Wickedness (Aura 333)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":333,"miscValue":0,"triggerSpellId":0}]},{"rank":2,"spellId":704643,"level":1,"description":"Atherann's WickednessRank 2Increases the damage of Atherann's Anguish by 20%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704643:effect:0:aura:108","name":"Atherann's Wickedness (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.2}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0}]}]},{"id":"coa-tree-8215","classId":"bloodmage","dbcSpellId":504627,"name":"Blood Bond","unlockLevel":1,"icon":"/assets/ui/spells/nhi_bloodsacrifice_border.png","sigil":"BB","description":"Bond yourself to an ally for 30 minutes, causing direct damage taken by tLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"chronomancer","abilities":[{"id":"coa-tree-30277","classId":"chronomancer","dbcSpellId":800857,"name":"Accelerated Recovery","unlockLevel":1,"icon":"/assets/ui/spells/spell_holy_healingfocus.png","sigil":"AR","description":"Accelerated RecoveryRank 118% of base mana Instant castAccelerates the bodies natural healing process, healing the target for (15*1000/3)*(12+0+Heal*0.23) over 15 sec. Periodic healing done by this scales with your spell haste.","target":"friendly","range":{"min":0,"max":40},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":18,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:800857:effect:0:aura:8","name":"Accelerated Recovery (Aura 8)","disposition":"buff","hideFromAuraStrip":true,"durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"sourceEffectType":6,"sourceAuraType":8,"miscValue":0,"triggerSpellId":0},{"kind":"hot","coefficient":0.24070173263549804,"basePoints":12,"dieSides":1,"pointsPerLevel":0.6052629947662354,"bonusPowerCoefficient":0,"sourceLevel":10,"maxScalingLevel":16,"ticks":5,"intervalMs":3000},{"kind":"apply-aura","aura":{"id":"coa:800857:effect:1:aura:283","name":"Accelerated Recovery (Aura 283)","disposition":"buff","durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"sourceEffectType":3,"sourceAuraType":283,"miscValue":0,"triggerSpellId":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":800857,"level":1,"description":"Accelerated RecoveryRank 118% of base mana Instant castAccelerates the bodies natural healing process, healing the target for (15*1000/3)*(12+0+Heal*0.23) over 15 sec. Periodic healing done by this scales with your spell haste.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":18,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:800857:effect:0:aura:8","name":"Accelerated Recovery (Aura 8)","disposition":"buff","hideFromAuraStrip":true,"durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"sourceEffectType":6,"sourceAuraType":8,"miscValue":0,"triggerSpellId":0},{"kind":"hot","coefficient":0.24070173263549804,"basePoints":12,"dieSides":1,"pointsPerLevel":0.6052629947662354,"bonusPowerCoefficient":0,"sourceLevel":10,"maxScalingLevel":16,"ticks":5,"intervalMs":3000},{"kind":"apply-aura","aura":{"id":"coa:800857:effect:1:aura:283","name":"Accelerated Recovery (Aura 283)","disposition":"buff","durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"sourceEffectType":3,"sourceAuraType":283,"miscValue":0,"triggerSpellId":0}]}],"talentEntryId":30277},{"id":"coa-tree-4032","classId":"chronomancer","dbcSpellId":92119,"name":"Aeon of Resilience","unlockLevel":1,"icon":"/assets/ui/spells/inv_trinket_80_kultiras02a.png","sigil":"AO","description":"Level 10 Passive Teaches you Aeon of Resilience.Aeon of ResilienceReduces Epoch's cast time by -25% and it's mana cost by -10%, and healing done by it now reduces the target's damage taken by -5% for 6 seconds.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:92119:effect:0:aura:4","name":"Aeon of Resilience (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":92119,"level":1,"description":"Level 10 Passive Teaches you Aeon of Resilience.Aeon of ResilienceReduces Epoch's cast time by -25% and it's mana cost by -10%, and healing done by it now reduces the target's damage taken by -5% for 6 seconds.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:92119:effect:0:aura:4","name":"Aeon of Resilience (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":0,"triggerSpellId":0}]}],"talentEntryId":4032},{"id":"coa-tree-6214","classId":"chronomancer","dbcSpellId":560948,"name":"Ahead of the Game","unlockLevel":1,"icon":"/assets/ui/spells/achievement_bg_win_av_x_times.png","sigil":"AO","description":"Every 10th instance of your damage dealt or healing now gives you 60 increased spell power for 10 seconds.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:560948:effect:0:aura:42","name":"AheadLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"cultist","abilities":[{"id":"coa-25-abyssal-decay-89-500705","classId":"cultist","dbcSpellId":500705,"name":"Abyssal Decay","unlockLevel":1,"icon":"/assets/ui/spells/spell_priest_void_blast.png","sigil":"AD","description":"Abyssal DecayRank 19% of base mana Instant castApplies an Eldritch curse to an enemy, causing 9+(PL*0.6) Shadow damage every 3 sec for 18 sec. Generates 5 Insanity.","target":"hostile","range":{"min":0,"max":30},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":9,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:500705:effect:0:aura:3","name":"Abyssal Decay (Aura 3)","disposition":"debuff","hideFromAuraStrip":true,"durationMs":18000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse"},"sourceEffectType":6,"sourceAuraType":3,"miscValue":0,"triggerSpellId":0},{"kind":"dot","coefficient":0.24166666716337204,"basePoints":9,"dieSides":5,"pointsPerLevel":0.6000000238418579,"bonusPowerCoefficient":0,"sourceLevel":1,"maxScalingLevel":9,"ticks":6,"intervalMs":3000,"tag":"spell-500705"},{"kind":"utility","action":"class-script","effectType":168,"auraType":0,"miscValue":120640,"triggerSpellId":0,"durationMs":18000}],"passive":false,"source":"coa-progression","ranks":[{"rank":1,"spellId":500705,"level":1,"description":"Abyssal DecayRank 19% of base mana Instant castApplies an Eldritch curse to an enemy, causing 9+(PL*0.6) Shadow damage every 3 sec for 18 sec. Generates 5 Insanity.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":9,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:500705:effect:0:aura:3","name":"Abyssal Decay (Aura 3)","disposition":"debuff","hideFromAuraStrip":true,"durationMs":18000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse"},"sourceEffectType":6,"sourceAuraType":3,"miscValue":0,"triggerSpellId":0},{"kind":"dot","coefficient":0.24166666716337204,"basePoints":9,"dieSides":5,"pointsPerLevel":0.6000000238418579,"bonusPowerCoefficient":0,"sourceLevel":1,"maxScalingLevel":9,"ticks":6,"intervalMs":3000,"tag":"spell-500705"},{"kind":"utility","action":"class-script","effectType":168,"auraType":0,"miscValue":120640,"triggerSpellId":0,"durationMs":18000}]},{"rank":2,"spellId":502144,"level":10,"description":"Abyssal DecayRank 29% of base mana Instant castApplies an Eldritch curse to an enemy, causing 17+(PL*1-10*1) Shadow damage every 3 sec for 18 sec. Generates 5 Insanity.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":9,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:502144:effect:0:aura:3","name":"Abyssal Decay (Aura 3)","disposition":"debuff","hideFromAuraStrip":true,"durationMs":18000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse"},"sourceEffectType":6,"sourceAuraType":3,"miscValue":0,"triggerSpellId":0},{"kind":"dot","coefficient":0.36066666603088376,"basePoints":17,"dieSides":1,"pointsPerLevel":1.0049999952316284,"bonusPowerCoefficient":0,"sourceLevel":10,"maxScalingLevel":18,"ticks":6,"intervalMs":3000,"tag":"spell-502144"},{"kind":"utility","action":"class-script","effectType":168,"auraType":0,"miscValue":120640,"triggerSpellId":0,"durationMs":18000}]},{"rank":3,"spellId":502145,"level":19,"description":"Abyssal DecayRank 39% of base mana Instant castApplies an Eldritch curse to an enemy, causing 31+(PL*1.4-19*1.4) Shadow damage every 3 sec for 18 sec. Generates 5 Insanity.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":9,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:502145:effect:0:aura:3","name":"Abyssal Decay (Aura 3)","disposition":"debuff","hideFromAuraStrip":true,"durationMs":18000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse"},"sourceEffectType":6,"sourceAuraType":3,"miscValue":0,"triggerSpellId":0},{"kind":"dot","coefficient":0.5590245174426659,"basePoints":31,"dieSides":1,"pointsPerLevel":1.3695000410079956,"bonusPowerCoefficient":0,"sourceLevel":19,"maxScalingLevel":27,"ticks":6,"intervalMs":3000,"tag":"spell-502145"},{"kind":"utility","action":"class-script","effectType":168,"auraType":0,"miscValue":120640,"triggerSpellId":0,"durationMs":18000}]},{"rank":4,"spellId":502146,"level":28,"description":"Abyssal DecayRank 49% of base mana Instant castApplies an Eldritch curse to an enemy, causing 55+(PL*1.7-28*1.7) Shadow damage every 3 sec for18 sec. Generates 5 Insanity.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":9,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:502146:effect:0:aura:3","name":"Abyssal Decay (Aura 3)","disposition":"debuff","hideFromAuraStrip":true,"durationMs":18000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse"},"sourceEffectType":6,"sourceAuraType":3,"miscValue":0,"triggerSpellIdLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"felsworn","abilities":[{"id":"coa-tree-29686","classId":"felsworn","dbcSpellId":803904,"name":"Annihilation","unlockLevel":1,"icon":"/assets/ui/spells/ability_boss_lordanthricystgreen.png","sigil":"AN","description":"Gorge on fel energy, guaranteeing your next direct instance of damage to critically strike, but causing it to consume 5% of your maximum health. Lasts for 5 attacks or 12 seconds.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":60000,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:803904:effect:0:aura:290","name":"Annihilation (Aura 290)","disposition":"buff","durationMs":12000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:803904:effect:1:aura:42","name":"Annihilation (Aura 42)","disposition":"buff","durationMs":12000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:803904:proc:1:807961","triggers":["crit","hit"],"chance":1,"charges":5,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":807961}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":807961}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":803904,"level":1,"description":"Gorge on fel energy, guaranteeing your next direct instance of damage to critically strike, but causing it to consume 5% of your maximum health. Lasts for 5 attacks or 12 seconds.","castMode":"instant","castTimeMs":0,"cooldownMs":60000,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:803904:effect:0:aura:290","name":"Annihilation (Aura 290)","disposition":"buff","durationMs":12000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:803904:effect:1:aura:42","name":"Annihilation (Aura 42)","disposition":"buff","durationMs":12000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:803904:proc:1:807961","triggers":["crit","hit"],"chance":1,"charges":5,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":807961}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":807961}]}],"talentEntryId":29686},{"id":"coa-tree-30301","classId":"felsworn","dbcSpellId":560822,"name":"Anti-Magic","unlockLevel":1,"icon":"/assets/ui/spells/spell_shadow_antimagicshell.png","sigil":"AM","description":"When Hateforged Barrier is removed from you, you now reduce -10% of all Magic damage taken for 8 seconds. In addition, Hateforged Barrier now heals for an additional 2% of your maximum health each tick.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:560822:effect:0:aura:4","name":"Anti-Magic (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:560822:effect:1:aura:107","name":"Anti-Magic (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.02}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":3,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":560822,"level":1,"description":"When Hateforged Barrier is removed from you, you now reduce -10% of all Magic damage taken for 8 seconds. In addition, Hateforged Barrier now heals for an additional 2% of your maximum health each tick.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:560822:effect:0:aura:4","name":"Anti-Magic (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:560822:effect:1:aura:107","name":"Anti-Magic (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.02}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":3,"triggerSpellId":0}]}],"talentEntryId":30301},{"id":"coa-tree-33671","classId":"felsworn","dbcSpellId":706266,"namLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"guardian","abilities":[{"id":"coa-18-banner-boy-68-705358","classId":"guardian","dbcSpellId":705358,"name":"Banner Boy","unlockLevel":1,"icon":"/assets/ui/spells/achievement_bg_captureflag_wsg.png","sigil":"BB","description":"Banner BoyRank 1Reduces the Energy cost of Banners by 10.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705358:effect:0:aura:107","name":"Banner Boy (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":-0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":14,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705358:effect:1:aura:4","name":"Banner Boy (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705358:effect:2:aura:4","name":"Banner Boy (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":3,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":705358,"level":1,"description":"Banner BoyRank 1Reduces the Energy cost of Banners by 10.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705358:effect:0:aura:107","name":"Banner Boy (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":-0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":14,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705358:effect:1:aura:4","name":"Banner Boy (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705358:effect:2:aura:4","name":"Banner Boy (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":3,"triggerSpellId":0}]}]},{"id":"coa-tree-11797","classId":"guardian","dbcSpellId":803683,"name":"Battle Drums","unlockLevel":1,"icon":"/assets/ui/spells/inv_archaeology_70_tauren_drum.png","sigil":"BD","description":"Place down 3 Battle Drums around you for 1 minute. Allies may click on the drums to increase their critical strike chance, haste, damage, and healing done by 10% and causes their damage dealt to trigger a Sound of War for their next 5 instances of damage or 30 seconds.","target":"hostile","range":{"min":0,"max":0},"radius":3,"castMode":"instant","castTimeMs":0,"cooldownMs":180000,"gcdMs":1500,"cost":{"resource":"energy","amount":50},"effects":[{"kind":"damage","coefficient":1},{"kind":"heal","coefficient":1},{"kind":"utility","action":"portal","effectType":50,"auraType":0,"miscValue":9000117,"triggerSpellId":0,"durationMs":60000},{"kind":"utility","action":"portal","effectType":50,"auraType":0,"miscValue":9000117,"triggerSpellId":0,"durationMs":60000},{"kind":"utility","action":"portal","effectType":50,"auraType":0,"miscValue":9000117,"triggerSpellId":0,"durationMs":60000}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":803683,"level":1,"description":"Place down 3 Battle Drums around you for 1 minute. Allies may click on the drums to increase their critical strike chance, haste, damage, and healing done by 10% and causes their damage dealt to trigger a Sound of War for their next 5 instances of damage or 30 seconds.","castMode":"instant","castTimeMs":0,"cooldownMs":180000,"gcdMs":1500,"cost":{"resource":"energy","amount":50},"effects":[{"kind":"damage","coefficient":1},{"kind":"heal","coefficient":1},{"kind":"utility","action":"portal","effectType":50,"auraType":0,"miscValue":9000117,"triggerSpellId":0,"durationMs":60000},{"kind":"utility","action":"portal","effectType":50,"auraType":0,"miscValue":9000117,"triggerSpellId":0,"durationMs":60000},{"kind":"utility","action":"portal","effectType":50,"auraType":0,"miscValue":9000117,"triggerSpellId":0,"durationMs":60000}]}],"talentEntryId":11797},{"id":"guardian-battle-rush","classId":"guardian","dbcSpellId":802197,"name":"Battle Rush","unlockLevel":1,"icon":"/assets/ui/spells/warrior_talent_icon_skirmisher.png","sigil":"BR","description":"Battle RushRank 1Instant cast30 sec cooldownCharge an enemy, dealing 16+0+AP*0.09996 Physical damage and stunnLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"knight-of-xoroth","abilities":[{"id":"coa-tree-30701","classId":"knight-of-xoroth","dbcSpellId":805679,"name":"Black Shield","unlockLevel":1,"icon":"/assets/ui/spells/spell_warlock_soulburn_haunt.png","sigil":"BS","description":"Consume all of your Demon's Blood stacks to create a demonic shield that absorbs 860 damage, increased by 20% per Demon's Blood stack, for 30 seconds.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":120000,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"shield","coefficient":1,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":0,"triggerSpellId":0,"durationMs":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":805679,"level":1,"description":"Consume all of your Demon's Blood stacks to create a demonic shield that absorbs 860 damage, increased by 20% per Demon's Blood stack, for 30 seconds.","castMode":"instant","castTimeMs":0,"cooldownMs":120000,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"shield","coefficient":1,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":0,"triggerSpellId":0,"durationMs":0}]}],"talentEntryId":30701},{"id":"coa-tree-34064","classId":"knight-of-xoroth","dbcSpellId":300395,"name":"Boiling Blood","unlockLevel":1,"icon":"/assets/ui/spells/nhi_bloodboil_border.png","sigil":"BB","description":"Casting Suffuse now increases your healing received by 25% for the first 6 seconds of it's duration.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:300395:effect:0:aura:42","name":"Boiling Blood (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:300395:proc:0:300394","triggers":["cast","heal"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":300394}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":300394}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":300395,"level":1,"description":"Casting Suffuse now increases your healing received by 25% for the first 6 seconds of it's duration.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:300395:effect:0:aura:42","name":"Boiling Blood (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:300395:proc:0:300394","triggers":["cast","heal"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":300394}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":300394}]}],"talentEntryId":34064},{"id":"coa-tree-4018","classId":"knight-of-xoroth","dbcSpellId":92104,"name":"Brimstone Buckler","unlockLevel":1,"icon":"/assets/ui/spells/ability_warlock_improveddemonictactics.png","sigil":"BB","description":"Level 10 Passive Successful blocks now have a 30% chance to summon 1 Hellfire Imp to aid you in battle for 12 seconds. Can only occur once every 3 sec.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:92104:effect:0:aura:23","name":"Brimstone Buckler (Aura 23)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:92104:proc:0:562029","triggers":["periodic"],"chance":0.3,"internalCooldownMs":3000,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":562029}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":23,"miscValue":0,"triggerSpellId":562029},{"kind":"apply-aura","aura":{"id":"coa:92104:effect:1:aura:42","name":"Brimstone Buckler (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:92104:proc:1:805966","triggers":["block"],"chance":0.3,"internalCooldownMs":3000,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":805966}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":805966}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":92104,"level":1,"description":"Level 10 Passive Successful blocks now have a 30% chance to summon 1 Hellfire Imp to aid you in battle for 12 seconds. Can only occur once every 3 sec.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:92104:effect:0:aura:23","name":"Brimstone Buckler (Aura 23)","disposition":"buff","durationMs":null,"maxSLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"necromancer","abilities":[{"id":"coa-tree-30600","classId":"necromancer","dbcSpellId":805428,"name":"Animate: Frost Wyrm","unlockLevel":1,"icon":"/assets/ui/spells/5_dragoncoldbreath_border.png","sigil":"AF","description":"Animate a Frost Wyrm that flies behind the Necromancer that blasts nearby enemies every 2 sec for 30 seconds, dealing 1500 + 14.88% frost SP + 14.88% Intellect Frost damage.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":120000,"gcdMs":1500,"cost":{"resource":"mana","amount":31,"percentage":true},"effects":[{"kind":"summon","creatureId":50177,"coefficient":0.08,"durationMs":30000}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":805428,"level":1,"description":"Animate a Frost Wyrm that flies behind the Necromancer that blasts nearby enemies every 2 sec for 30 seconds, dealing 1500 + 14.88% frost SP + 14.88% Intellect Frost damage.","castMode":"instant","castTimeMs":0,"cooldownMs":120000,"gcdMs":1500,"cost":{"resource":"mana","amount":31,"percentage":true},"effects":[{"kind":"summon","creatureId":50177,"coefficient":0.08,"durationMs":30000}]}],"talentEntryId":30600},{"id":"coa-23-animate-zombies-84-504315","classId":"necromancer","dbcSpellId":504315,"name":"Animate: Zombies","unlockLevel":1,"icon":"/assets/ui/spells/zombiewc3.png","sigil":"AZ","description":"Animate: ZombiesRank 121% of base mana 3 sec cast15 sec cooldownAnimate 2 Zombies to aid you in combat for 15 sec. Every 3 sec, Zombies emit Zombie Plague, dealing 79+1.0 Points Per Level+SP*0.1 Plague Damage to nearby enemies.","target":"hostile","range":{"min":0,"max":0},"radius":3,"castMode":"cast","castTimeMs":3000,"cooldownMs":15000,"gcdMs":1000,"cost":{"resource":"mana","amount":21,"percentage":true},"effects":[{"kind":"trigger-spell","spellId":525379,"withValue":2},{"kind":"damage","coefficient":1},{"kind":"summon","creatureId":503031,"coefficient":0.08,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":524287,"triggerSpellId":500991,"durationMs":100}],"passive":false,"source":"coa-progression","ranks":[{"rank":1,"spellId":504315,"level":1,"description":"Animate: ZombiesRank 121% of base mana 3 sec cast15 sec cooldownAnimate 2 Zombies to aid you in combat for 15 sec. Every 3 sec, Zombies emit Zombie Plague, dealing 79+1.0 Points Per Level+SP*0.1 Plague Damage to nearby enemies.","castMode":"cast","castTimeMs":3000,"cooldownMs":15000,"gcdMs":1000,"cost":{"resource":"mana","amount":21,"percentage":true},"effects":[{"kind":"trigger-spell","spellId":525379,"withValue":2},{"kind":"damage","coefficient":1},{"kind":"summon","creatureId":503031,"coefficient":0.08,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":524287,"triggerSpellId":500991,"durationMs":100}]},{"rank":2,"spellId":525378,"level":30,"description":"Animate: ZombiesRank 223% of base mana 3 sec cast15 sec cooldownAnimate 3 Zombies to aid you in combat for 15 sec. Every 3 sec, Zombies emit Zombie Plague, dealing 79+1.0 Points Per Level+SP*0.1 Plague Damage to nearby enemies.","castMode":"cast","castTimeMs":3000,"cooldownMs":15000,"gcdMs":1000,"cost":{"resource":"mana","amount":23,"percentage":true},"effects":[{"kind":"trigger-spell","spellId":525379,"withValue":3},{"kind":"damage","coefficient":1},{"kind":"summon","creatureId":503031,"coefficient":0.08,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":524287,"triggerSpellId":500991,"durationMs":100}]},{"rank":3,"spellId":525381,"level":51,"description":"Animate: ZombiesRank 324% of base mana 3 sec cast15 sec cooldownAnimate 4 Zombies to aid you in combat for 10 sec. Every 3 sec, Zombies emit Zombie Plague, dealing 79+1.0 Points Per Level+SP*0.1 Plague Damage to nearby enemies.","castMode":"cast","castTimeMs":3000,"cooldownMs":15000,"gcdMs":1000,"cost":{"resource":"mana","amount":24,"percentage":true},"effects":[{"kind":"trigger-spell","spellId":525379,"withValue":4},{"kind":"damage","coefficient":1},{"kind":"summon","creatureId":503031,"coefficient":0.08,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":3,"auraType":0,"miscValue":524287,"triggerSpellId":500991,"durationMs":100}]}]},{"id":"coa-tree-29774","classId":"necromancer","dbcSpellId":802121,"name":"Bone Tithe","unlockLevel":1,"icon":"/assets/ui/spells/ossuary_bond.png","sigil":"BT","description":"Siphon life from your undead minions, sacrificing 40% of their health to grant yourself an absorb shield equal to half of the health stolen for 20 seconds. Usable while stunned.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":120000,"gcdMs":1500,"cost":{"resource":"mana","amount":25,"percentage":true},"effects":[{"kind":"shield","coefficient":1,"durationMs":15000},{"kind":"utility","action":"class-script","effectType":77,"auraType":0,"miscValue":0,"triggerSpellId"Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"primalist","abilities":[{"id":"coa-tree-29362","classId":"primalist","dbcSpellId":800094,"name":"Bearskin","unlockLevel":1,"icon":"/assets/ui/spells/spell_druid_primaltenacity.png","sigil":"BE","description":"Reduces all damage taken by -60% and reduces the duration of root, stun, and incapacitate effects on you by -30% for 10 seconds.","target":"hostile","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":300000,"gcdMs":1500,"cost":{"resource":"mana","amount":24,"percentage":true},"effects":[{"kind":"status","status":"sleep","durationMs":10000},{"kind":"apply-aura","aura":{"id":"coa:800094:effect:0:aura:87","name":"Bearskin (Aura 87)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":-0.6}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:800094:effect:1:aura:232","name":"Bearskin (Aura 232)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":232,"miscValue":5,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:800094:effect:2:aura:232","name":"Bearskin (Aura 232)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":232,"miscValue":12,"triggerSpellId":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":800094,"level":1,"description":"Reduces all damage taken by -60% and reduces the duration of root, stun, and incapacitate effects on you by -30% for 10 seconds.","castMode":"instant","castTimeMs":0,"cooldownMs":300000,"gcdMs":1500,"cost":{"resource":"mana","amount":24,"percentage":true},"effects":[{"kind":"status","status":"sleep","durationMs":10000},{"kind":"apply-aura","aura":{"id":"coa:800094:effect:0:aura:87","name":"Bearskin (Aura 87)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":-0.6}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:800094:effect:1:aura:232","name":"Bearskin (Aura 232)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":232,"miscValue":5,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:800094:effect:2:aura:232","name":"Bearskin (Aura 232)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":232,"miscValue":12,"triggerSpellId":0}]}],"talentEntryId":29362},{"id":"coa-tree-29252","classId":"primalist","dbcSpellId":500692,"name":"Boulder Dash","unlockLevel":1,"icon":"/assets/ui/spells/custom_elementl(earth)_b_01_border.png","sigil":"BD","description":"Raise a boulder out of the ground and encase yourself within it, preventing you from attacking or casting spells. For 10 seconds, you roll forward at 70% increased movement speed, dealing 1 + 50% AP + 100% SP Physical damage to enemies you roll over, and you are immune to crowd control effects.","target":"hostile","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":180000,"gcdMs":1250,"cost":{"resource":"mana","amount":35,"percentage":true},"effects":[{"kind":"damage","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:500692:effect:0:aura:23","name":"Boulder Dash (Aura 23)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:500692:proc:0:500693","triggers":["periodic"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":500693}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":23,"miscValue":0,"triggerSpellId":500693},{"kind":"apply-aura","aura":{"id":"coa:500692:effect:1:aura:31","name":"Boulder Dash (Aura 31)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"stat","stat":"movement-speed","operation":"percent","value":0.7}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":31,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:500692:effect:2:aura:241","name":"Boulder Dash (Aura 241)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":241,"miscValue":0,"triggerSpellId":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":500692,"level":1,"description":"Raise a boulder out of the ground aLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"pyromancer","abilities":[{"id":"coa-tree-33843","classId":"pyromancer","dbcSpellId":300921,"name":"Al Dente","unlockLevel":1,"icon":"/assets/ui/spells/achievement_cooking_masteroftheoven.png","sigil":"AD","description":"Targets affected by Gaze of Ysera now take 15% increased Fire damage.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:300921:effect:0:aura:107","name":"Al Dente (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.15}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":23,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":300921,"level":1,"description":"Targets affected by Gaze of Ysera now take 15% increased Fire damage.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:300921:effect:0:aura:107","name":"Al Dente (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.15}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":23,"triggerSpellId":0}]}],"talentEntryId":33843},{"id":"coa-tree-33882","classId":"pyromancer","dbcSpellId":504397,"name":"Blessing of the Firelands","unlockLevel":1,"icon":"/assets/ui/spells/nhi_fire_soul_border.png","sigil":"BO","description":"Each stack of Heat now increases the damage dealt by Dragon Leap by 6%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:504397:effect:0:aura:107","name":"Blessing of the Firelands (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.06}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":12,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:504397:effect:1:aura:107","name":"Blessing of the Firelands (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":23,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":504397,"level":1,"description":"Each stack of Heat now increases the damage dealt by Dragon Leap by 6%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:504397:effect:0:aura:107","name":"Blessing of the Firelands (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.06}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":12,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:504397:effect:1:aura:107","name":"Blessing of the Firelands (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":23,"triggerSpellId":0}]}],"talentEntryId":33882},{"id":"coa-tree-32499","classId":"pyromancer","dbcSpellId":300759,"name":"Bright Flames","unlockLevel":1,"icon":"/assets/ui/spells/spell_frost_fireresistancetotem.png","sigil":"BF","description":"Increases the amount absorbed by Inferno Barrier by 10% and the damage it deals by 15%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:300759:effect:0:aura:317","name":"Bright Flames (Aura 317)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":317,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:300759:effect:1:aura:108","name":"Bright Flames (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.15}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":300759,"level":1,"description":"Increases the amount absorbed by Inferno Barrier by 10% and the damage it dLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"ranger","abilities":[{"id":"coa-21-agile-none-560796","classId":"ranger","dbcSpellId":560796,"name":"Agile","unlockLevel":1,"icon":"/assets/ui/spells/inv_sword_38.png","sigil":"AG","description":"AgileRank 2Increases the damage of Wild Strike, Whipvine Arrow, and Ravage by 10%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:560796:effect:0:aura:108","name":"Agile (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:560796:effect:1:aura:108","name":"Agile (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":22,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":2,"spellId":560796,"level":1,"description":"AgileRank 2Increases the damage of Wild Strike, Whipvine Arrow, and Ravage by 10%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:560796:effect:0:aura:108","name":"Agile (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:560796:effect:1:aura:108","name":"Agile (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":22,"triggerSpellId":0}]}]},{"id":"coa-21-archery-training-76-705036","classId":"ranger","dbcSpellId":705036,"name":"Archery Training","unlockLevel":1,"icon":"/assets/ui/spells/inv_bow_1h_draenorcrafted_d_01_a_horde.png","sigil":"AT","description":"Archery TrainingRank 1Increases the damage of Skullpiercer by 3% and your critical strike chance by 1%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705036:effect:0:aura:290","name":"Archery Training (Aura 290)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705036:effect:1:aura:108","name":"Archery Training (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.03}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":705036,"level":1,"description":"Archery TrainingRank 1Increases the damage of Skullpiercer by 3% and your critical strike chance by 1%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705036:effect:0:aura:290","name":"Archery Training (Aura 290)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705036:effect:1:aura:108","name":"Archery Training (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.03}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0}]},{"rank":2,"spellId":705037,"level":1,"description":"Archery TrainingRank 2Increases the damage of Skullpiercer by 6% and your critical strike chance by 2%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705037:effect:0:aura:290","name":"Archery Training (Aura 290)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705037:effect:1:aura:108","name":"Archery Training (Aura 108)","disposition":"buff","dLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"reaper","abilities":[{"id":"coa-tree-6708","classId":"reaper","dbcSpellId":706790,"name":"Backswing","unlockLevel":1,"icon":"/assets/ui/spells/novart_magicspell_(32)_border.png","sigil":"BA","description":"Increases the Runic Power generated by Reap by 5.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:706790:effect:0:aura:107","name":"Backswing (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.5}]},"sourceEffectType":6,"sourceAuraType":107,"miscValue":3,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":706790,"level":1,"description":"Increases the Runic Power generated by Reap by 5.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:706790:effect:0:aura:107","name":"Backswing (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.5}]},"sourceEffectType":6,"sourceAuraType":107,"miscValue":3,"triggerSpellId":0}]}],"talentEntryId":6708},{"id":"coa-tree-34500","classId":"reaper","dbcSpellId":560412,"name":"Between Shadows","unlockLevel":1,"icon":"/assets/ui/spells/5_shadowworld_border.png","sigil":"BS","description":"Casting Spectre Stride now generates 1 Reaped Soul.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:560412:effect:0:aura:42","name":"Between Shadows (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:560412:proc:0:504390","triggers":["cast"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":504390}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":504390}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":560412,"level":1,"description":"Casting Spectre Stride now generates 1 Reaped Soul.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:560412:effect:0:aura:42","name":"Between Shadows (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:560412:proc:0:504390","triggers":["cast"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":504390}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":504390}]}],"talentEntryId":34500},{"id":"coa-tree-31289","classId":"reaper","dbcSpellId":680337,"name":"Bolstered Form","unlockLevel":1,"icon":"/assets/ui/spells/achievement_raid_torghast_shadowscourge_prisonofnerzhul.png","sigil":"BF","description":"Assume a bolstered form for 15 seconds, generating 30 Runic Power, increasing your Armor and your parry chance by 30%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":60000,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:680337:effect:0:aura:101","name":"Bolstered Form (Aura 101)","disposition":"buff","durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"stat","stat":"resistance:physical","operation":"percent","value":0.25}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":101,"miscValue":1,"triggerSpellId":0},{"kind":"trigger-spell","spellId":359505},{"kind":"resource","amount":300},{"kind":"apply-aura","aura":{"id":"coa:680337:effect:2:aura:47","name":"Bolstered Form (Aura 47)","disposition":"buff","durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"stat","stat":"parry","operation":"percent","value":0.25}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":47,"miscValue":127,"triggerSpellId":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":680337,"level":1,"description":"Assume a bolstered form for 15 seconds, generating 30 Runic Power, increasing your Armor and your parry chance by 30%.","castMode":"instant","castTimeMs":0,"cooldownMs":60000,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:680337:effect:0:aura:101","name":"Bolstered Form (Aura 101)","disposition":"buff","durationMs":15000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"stat","stat":"resistance:physical","operation":"percent","value":0.25}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":1Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"runemaster","abilities":[{"id":"coa-32-ancient-carvings-117-705616","classId":"runemaster","dbcSpellId":705616,"name":"Ancient Carvings","unlockLevel":1,"icon":"/assets/ui/spells/inv_relics_6orunestone_ogremissive.png","sigil":"AC","description":"Ancient CarvingsRank 2InstantReduces the cooldown of Words by 20%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705616:effect:0:aura:108","name":"Ancient Carvings (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.2}]},"recipient":"caster","sourceEffectType":3,"sourceAuraType":108,"miscValue":11,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705616:effect:1:aura:4","name":"Ancient Carvings (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705616:effect:2:aura:4","name":"Ancient Carvings (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":34,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":2,"spellId":705616,"level":1,"description":"Ancient CarvingsRank 2InstantReduces the cooldown of Words by 20%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705616:effect:0:aura:108","name":"Ancient Carvings (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.2}]},"recipient":"caster","sourceEffectType":3,"sourceAuraType":108,"miscValue":11,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705616:effect:1:aura:4","name":"Ancient Carvings (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705616:effect:2:aura:4","name":"Ancient Carvings (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":34,"triggerSpellId":0}]}]},{"id":"coa-tree-29226","classId":"runemaster","dbcSpellId":806797,"name":"Ancient Teachings","unlockLevel":1,"icon":"/assets/ui/spells/ability_mage_potentspirit.png","sigil":"AT","description":"Increases the effectiveness of Etching of the Dextrous by 20%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:806797:effect:0:aura:216","name":"Ancient Teachings (Aura 216)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":216,"miscValue":126,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:806797:effect:1:aura:192","name":"Ancient Teachings (Aura 192)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":192,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:806797:effect:2:aura:108","name":"Ancient Teachings (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.2}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":8,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":806797,"level":1,"description":"Increases the effectiveness of Etching of the Dextrous by 20%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:806797:effect:0:aura:216","name":"Ancient Teachings (Aura 216)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":216,"miscValue":126,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:806797:effect:1:aura:192","name":"Ancient Teachings (Aura 192)","disposition":Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"starcaller","abilities":[{"id":"coa-26-arrows-of-starlight-93-704733","classId":"starcaller","dbcSpellId":704733,"name":"Arrows of Starlight","unlockLevel":1,"icon":"/assets/ui/spells/ability_ironmaidens_ironshot.png","sigil":"AO","description":"Arrows of StarlightRank 1Increases the damage of Moon Arrow by 20%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704733:effect:0:aura:108","name":"Arrows of Starlight (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.2}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":704733,"level":1,"description":"Arrows of StarlightRank 1Increases the damage of Moon Arrow by 20%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704733:effect:0:aura:108","name":"Arrows of Starlight (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0.2}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":0,"triggerSpellId":0}]}]},{"id":"coa-tree-30838","classId":"starcaller","dbcSpellId":806155,"name":"Astral Aegis","unlockLevel":1,"icon":"/assets/ui/spells/ability_bastion_monk.png","sigil":"AA","description":"Drains 30% Maximum Mana For 10 seconds, direct Magic damage taken will silence the attacker for 1 seconds and deal 57 + 18% arcane SP Arcane damage to them.","target":"hostile","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":30000,"gcdMs":1500,"cost":{"resource":"mana","amount":19,"percentage":true},"effects":[{"kind":"damage","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:806155:effect:0:aura:87","name":"Astral Aegis (Aura 87)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:806155:effect:1:aura:42","name":"Astral Aegis (Aura 42)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:806155:proc:1:806453","triggers":["damage-taken","hit"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":806453}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":806453}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":806155,"level":1,"description":"Drains 30% Maximum Mana For 10 seconds, direct Magic damage taken will silence the attacker for 1 seconds and deal 57 + 18% arcane SP Arcane damage to them.","castMode":"instant","castTimeMs":0,"cooldownMs":30000,"gcdMs":1500,"cost":{"resource":"mana","amount":19,"percentage":true},"effects":[{"kind":"damage","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:806155:effect:0:aura:87","name":"Astral Aegis (Aura 87)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:806155:effect:1:aura:42","name":"Astral Aegis (Aura 42)","disposition":"buff","durationMs":10000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:806155:proc:1:806453","triggers":["damage-taken","hit"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":806453}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":806453}]}],"talentEntryId":30838},{"id":"starcaller-astral-flare","classId":"starcaller","dbcSpellId":800499,"name":"Astral Flare","unlockLevel":1,"icon":"/assets/ui/spells/spell_shadow_manaburn.png","sigil":"AF","description":"Astral FlareRank 12 sec castYou call an Astral Flare down from the sky, dealing 1 Arcane Damage to an enemy and regenerating 5% of your Maximum Mana.","target":"hostile","range":{"min":0,"max":40},"castMode":"cast","castTimeMs":2000,"cooldownMs":0,"gcdMs":1250,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"trigger-spell","spellId":800507,"withValue":10},{"kind":"damage","coefficient":0.08,"basePoints":1,"dieSides":1,"pointsPerLevel":0,"bonusPowerCoefficient":0,"sourceLevel":6},{"kind":"trigger-spell","spellId":804096,"withValLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"stormbringer","abilities":[{"id":"coa-tree-34916","classId":"stormbringer","dbcSpellId":807462,"name":"Aether Mastery","unlockLevel":1,"icon":"/assets/ui/spells/achievement_zone_netherstorm_01.png","sigil":"AM","description":"Allows 30% of your mana regeneration to continue while casting and increases your critical strike chance by 2%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:807462:effect:0:aura:134","name":"Aether Mastery (Aura 134)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"resource","resource":"mana","property":"regeneration","operation":"percent","value":0.3}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":134,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:807462:effect:1:aura:290","name":"Aether Mastery (Aura 290)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":807462,"level":1,"description":"Allows 30% of your mana regeneration to continue while casting and increases your critical strike chance by 2%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:807462:effect:0:aura:134","name":"Aether Mastery (Aura 134)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"resource","resource":"mana","property":"regeneration","operation":"percent","value":0.3}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":134,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:807462:effect:1:aura:290","name":"Aether Mastery (Aura 290)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0}]},{"rank":2,"spellId":807887,"level":1,"description":"Allows 60% of your mana regeneration to continue while casting and increases your critical strike chance by 4%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:807887:effect:0:aura:134","name":"Aether Mastery (Aura 134)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"resource","resource":"mana","property":"regeneration","operation":"percent","value":0.6}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":134,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:807887:effect:1:aura:290","name":"Aether Mastery (Aura 290)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh"},"recipient":"caster","sourceEffectType":6,"sourceAuraType":290,"miscValue":0,"triggerSpellId":0}]}],"talentEntryId":34916},{"id":"coa-16-aethermancy-62-705690","classId":"stormbringer","dbcSpellId":705690,"name":"Aethermancy","unlockLevel":1,"icon":"/assets/ui/spells/spell_shaman_improvedreincarnation.png","sigil":"AE","description":"AethermancyRank 1Increases the critical strike chance of your Invigorating Surge by 20%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705690:effect:0:aura:107","name":"Aethermancy (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.2}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":7,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705690:effect:1:aura:107","name":"Aethermancy (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":1}]},"recipient":"caster","sourceEffectType":3,"sourceAuraType":107,"miscValue":7,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":705690,"level":1,"description":"AethermancyRank 1Increases the critical strike chance of your Invigorating Surge by 20%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705690:effect:0:aura:107","name":"Aethermancy (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.2}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":7,"triggerSpellId":0},{"kinLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"sun-cleric","abilities":[{"id":"coa-tree-4048","classId":"sun-cleric","dbcSpellId":92137,"name":"Angelic Presence","unlockLevel":1,"icon":"/assets/ui/spells/ability_paladin_conviction.png","sigil":"AP","description":"Level 10 Passive Avoiding an attack now has a 20% chance to grant you Angelic Presence.Angelic PresenceYour next Illumination within 15 seconds is instant cast and free of cost.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:92137:effect:0:aura:42","name":"Angelic Presence (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:92137:proc:0:800722","triggers":["cast","hit"],"chance":0.2,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":800722}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":800722},{"kind":"apply-aura","aura":{"id":"coa:92137:effect:1:aura:79","name":"Angelic Presence (Aura 79)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"dealt","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":79,"miscValue":127,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":92137,"level":1,"description":"Level 10 Passive Avoiding an attack now has a 20% chance to grant you Angelic Presence.Angelic PresenceYour next Illumination within 15 seconds is instant cast and free of cost.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:92137:effect:0:aura:42","name":"Angelic Presence (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:92137:proc:0:800722","triggers":["cast","hit"],"chance":0.2,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":800722}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":800722},{"kind":"apply-aura","aura":{"id":"coa:92137:effect:1:aura:79","name":"Angelic Presence (Aura 79)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"dealt","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":79,"miscValue":127,"triggerSpellId":0}]}],"talentEntryId":4048},{"id":"coa-27-bastion-of-vengeance-97-704925","classId":"sun-cleric","dbcSpellId":704925,"name":"Bastion of Vengeance","unlockLevel":1,"icon":"/assets/ui/spells/inv_shield_1h_artifactnorgannon_d_06.png","sigil":"BO","description":"Bastion of VengeanceRank 1Increases your block chance by 2% and gives successful blocks a 50% chance to reduce the remaining cooldown of Vengeful Slam by 0.01 sec.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704925:effect:0:aura:42","name":"Bastion of Vengeance (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:704925:proc:0:704926","triggers":["block"],"chance":0.5,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":704926}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":704926},{"kind":"apply-aura","aura":{"id":"coa:704925:effect:1:aura:51","name":"Bastion of Vengeance (Aura 51)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"block","operation":"percent","value":0.02}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":51,"miscValue":0,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":704925,"level":1,"description":"Bastion of VengeanceRank 1Increases your block chance by 2% and gives successful blocks a 50% chance to reduce the remaining cooldown of Vengeful Slam by 0.01 sec.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:704925:effect:0:aura:42","name":"Bastion of Vengeance (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:704925:proc:0:704926","triggers":["block"],"chance":0.5,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":704926}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":704926},{"kind":"apply-aura","aura":{"id":"coa:704925:effect:1:aura:51","name":"Bastion of Vengeance (Aura 51)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","statLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"templar","abilities":[{"id":"coa-19-alertness-71-706321","classId":"templar","dbcSpellId":706321,"name":"Alertness","unlockLevel":1,"icon":"/assets/ui/spells/spell_holy_powerinfusion.png","sigil":"AL","description":"AlertnessRank 1Reduces damage taken by 5%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:706321:effect:0:aura:87","name":"Alertness (Aura 87)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":-0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:706321:effect:1:aura:107","name":"Alertness (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":5,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":706321,"level":1,"description":"AlertnessRank 1Reduces damage taken by 5%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:706321:effect:0:aura:87","name":"Alertness (Aura 87)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":-0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:706321:effect:1:aura:107","name":"Alertness (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":5,"triggerSpellId":0}]},{"rank":2,"spellId":706322,"level":1,"description":"AlertnessRank 2Reduces Physical Damage taken by 4% and increases the range of Benediction by 10 yds.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:706322:effect:0:aura:87","name":"Alertness (Aura 87)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"damage","direction":"taken","operation":"percent","value":-0.04}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":87,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:706322:effect:1:aura:107","name":"Alertness (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":5,"triggerSpellId":0}]}]},{"id":"coa-tree-34375","classId":"templar","dbcSpellId":801457,"name":"Binding Scripture","unlockLevel":1,"icon":"/assets/ui/spells/_d3breathofheaven.png","sigil":"BS","description":"Healing an ally now redirects 10% of their damage taken to you and reduces your damage taken by -5% for 10 seconds, stacking 3 times.","target":"hostile","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"damage","coefficient":1},{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:801457:effect:0:aura:42","name":"Binding Scripture (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:801457:proc:0:705309","triggers":["heal","damage-taken"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":705309}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":705309}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":801457,"level":1,"description":"Healing an ally now redirects 10% of their damage taken to you and reduces your damage taken by -5% for 10 seconds, stacking 3 times.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"damage","coefficient":1},{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:801457:effect:0:aura:42","name":"Binding Scripture (Aura 42)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","procs":[{"id":"coa:801457:proc:0:705309","triggers":["heal","damage-taken"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":705309}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":705309}]}],"taleLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"tinker","abilities":[{"id":"coa-tree-29440","classId":"tinker","dbcSpellId":801744,"name":"Air Strike","unlockLevel":1,"icon":"/assets/ui/spells/ability_mount_gyrocoptor.png","sigil":"AS","description":"Mark the target location for an Air Strike. After 7 seconds, it deals 1250 Fire damage to up to 12 enemies caught within the blast. This ability always critically strikes.","target":"hostile","range":{"min":0,"max":60},"radius":20,"castMode":"instant","castTimeMs":0,"cooldownMs":60000,"gcdMs":1500,"cost":{"resource":"mana","amount":25,"percentage":true},"effects":[{"kind":"damage","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:801744:effect:0:aura:23","name":"Air Strike (Aura 23)","disposition":"debuff","durationMs":7000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:801744:proc:0:801745","triggers":["periodic"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":801745}}}]},"sourceEffectType":27,"sourceAuraType":23,"miscValue":0,"triggerSpellId":801745}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":801744,"level":1,"description":"Mark the target location for an Air Strike. After 7 seconds, it deals 1250 Fire damage to up to 12 enemies caught within the blast. This ability always critically strikes.","castMode":"instant","castTimeMs":0,"cooldownMs":60000,"gcdMs":1500,"cost":{"resource":"mana","amount":25,"percentage":true},"effects":[{"kind":"damage","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:801744:effect:0:aura:23","name":"Air Strike (Aura 23)","disposition":"debuff","durationMs":7000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","procs":[{"id":"coa:801744:proc:0:801745","triggers":["periodic"],"chance":1,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":801745}}}]},"sourceEffectType":27,"sourceAuraType":23,"miscValue":0,"triggerSpellId":801745}]}],"talentEntryId":29440},{"id":"coa-tree-5997","classId":"tinker","dbcSpellId":520445,"name":"Auto Resuscitation Device","unlockLevel":1,"icon":"/assets/ui/spells/inv_misc_enggizmos_15.png","sigil":"AR","description":"Attach a resuscitation device to your target ally for 20 seconds. When the target would otherwise die, they are instead healed for 50% of their maximum health.","target":"friendly","range":{"min":0,"max":20},"castMode":"cast","castTimeMs":1500,"cooldownMs":180000,"gcdMs":1500,"cost":{"resource":"mana","amount":40,"percentage":true},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:520445:effect:0:aura:69","name":"Auto Resuscitation Device (Aura 69)","disposition":"buff","durationMs":20000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","absorbs":[{"id":"coa:520445:absorb:0","amount":20,"perStack":false}]},"sourceEffectType":6,"sourceAuraType":69,"miscValue":127,"triggerSpellId":524780}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":520445,"level":1,"description":"Attach a resuscitation device to your target ally for 20 seconds. When the target would otherwise die, they are instead healed for 50% of their maximum health.","castMode":"cast","castTimeMs":1500,"cooldownMs":180000,"gcdMs":1500,"cost":{"resource":"mana","amount":40,"percentage":true},"effects":[{"kind":"heal","coefficient":1},{"kind":"apply-aura","aura":{"id":"coa:520445:effect:0:aura:69","name":"Auto Resuscitation Device (Aura 69)","disposition":"buff","durationMs":20000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"magic","absorbs":[{"id":"coa:520445:absorb:0","amount":20,"perStack":false}]},"sourceEffectType":6,"sourceAuraType":69,"miscValue":127,"triggerSpellId":524780}]}],"talentEntryId":5997},{"id":"coa-28-blasting-barrels-99-705835","classId":"tinker","dbcSpellId":705835,"name":"Blasting Barrels","unlockLevel":1,"icon":"/assets/ui/spells/5_gunshot_(3)_border.png","sigil":"BB","description":"Blasting BarrelsRank 1InstantIncreases critical strike damage by 0% and increases damage dealt by Rounds by 0%.","target":"hostile","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"damage","coefficient":1}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":705835,"level":1,"description":"Blasting BarrelsRank 1InstantIncreases critical strike damage by 0% and increases damage dealt by Rounds by 0%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"damage","coefficient":1}]}]},{"id":"coa-tree-30583","classId":"tinker","dbcSpellId":560754,"name":"Build: Alarm Beacon","unlockLevel":1,"icon":"/assets/ui/spells/inv_lightforgedmechsuit.png","sigil":"BA","description":"3 Charges, 15 sec recharge Throw down an alarm beacon for 10 seconds, removing fear, charm and sleep effects from up to 1 ally within 20 yds every 1 sec.","target":"hostile","range":{"min":0,Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"venomancer","abilities":[{"id":"coa-29-acceleration-103-705960","classId":"venomancer","dbcSpellId":705960,"name":"Acceleration","unlockLevel":1,"icon":"/assets/ui/spells/_meat_rotten.png","sigil":"AC","description":"AccelerationRank 2Increases the tick rate of Wilt and Shadra's Vigil by 10%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705960:effect:0:aura:108","name":"Acceleration (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":19,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705960:effect:1:aura:108","name":"Acceleration (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":19,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":2,"spellId":705960,"level":1,"description":"AccelerationRank 2Increases the tick rate of Wilt and Shadra's Vigil by 10%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705960:effect:0:aura:108","name":"Acceleration (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":19,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705960:effect:1:aura:108","name":"Acceleration (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.1}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":19,"triggerSpellId":0}]}]},{"id":"coa-tree-6086","classId":"venomancer","dbcSpellId":805775,"name":"Adrenal Venom","unlockLevel":1,"icon":"/assets/ui/spells/trade_alchemy_dpotion_a26.png","sigil":"AV","description":"Activate Adrenal Venom for 120 minutes, giving your casts a 25% chance to increase your haste by 6% for 6 seconds, stacking 3 times. You can have a maximum of 2 unique Venoms active at a time.","target":"self","range":{"min":0,"max":0},"castMode":"cast","castTimeMs":1000,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":20,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:805775:effect:0:aura:42","name":"Adrenal Venom (Aura 42)","disposition":"buff","durationMs":7200000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"poison","procs":[{"id":"coa:805775:proc:0:805894","triggers":["cast"],"chance":0.25,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":805894}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":805894},{"kind":"apply-aura","aura":{"id":"coa:805775:effect:1:aura:107","name":"Adrenal Venom (Aura 107)","disposition":"buff","durationMs":7200000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"poison","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":17,"triggerSpellId":0}],"passive":false,"source":"coa-tree","ranks":[{"rank":1,"spellId":805775,"level":1,"description":"Activate Adrenal Venom for 120 minutes, giving your casts a 25% chance to increase your haste by 6% for 6 seconds, stacking 3 times. You can have a maximum of 2 unique Venoms active at a time.","castMode":"cast","castTimeMs":1000,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":20,"percentage":true},"effects":[{"kind":"apply-aura","aura":{"id":"coa:805775:effect:0:aura:42","name":"Adrenal Venom (Aura 42)","disposition":"buff","durationMs":7200000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"poison","procs":[{"id":"coa:805775:proc:0:805894","triggers":["cast"],"chance":0.25,"action":{"kind":"custom","id":"wow335-trigger-spell","data":{"spellId":805894}}}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":42,"miscValue":0,"triggerSpellId":805894},{"kind":"apply-aura","aura":{"id":"coa:805775:effect:1:aura:107","name":"Adrenal Venom (Aura 107)","disposition":"buff","durationMs":7200000,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"poison","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":17,"triggerSpellId":0}]}],"talentEntryId":6086},{"id":"coa-tree-29574"Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"witch-doctor","abilities":[{"id":"coa-tree-30147","classId":"witch-doctor","dbcSpellId":705921,"name":"Alchemical Enhancement","unlockLevel":1,"icon":"/assets/ui/spells/inv_alchemy_71_potion4.png","sigil":"AE","description":"Increases your haste by 5%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705921:effect:0:aura:216","name":"Alchemical Enhancement (Aura 216)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":216,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705921:effect:1:aura:192","name":"Alchemical Enhancement (Aura 192)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":192,"miscValue":127,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":705921,"level":1,"description":"Increases your haste by 5%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"energy","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705921:effect:0:aura:216","name":"Alchemical Enhancement (Aura 216)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":216,"miscValue":0,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705921:effect:1:aura:192","name":"Alchemical Enhancement (Aura 192)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"haste","operation":"percent","value":0.05}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":192,"miscValue":127,"triggerSpellId":0}]}],"talentEntryId":30147},{"id":"coa-tree-11323","classId":"witch-doctor","dbcSpellId":301297,"name":"Blatant Curse","unlockLevel":1,"icon":"/assets/ui/spells/spell_nature_removecurse.png","sigil":"BC","description":"Reduces the mana cost of your Jinxes by -25%.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:301297:effect:0:aura:108","name":"Blatant Curse (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":8,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:301297:effect:1:aura:108","name":"Blatant Curse (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.25}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":14,"triggerSpellId":0}],"passive":true,"source":"coa-tree","ranks":[{"rank":1,"spellId":301297,"level":1,"description":"Reduces the mana cost of your Jinxes by -25%.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:301297:effect:0:aura:108","name":"Blatant Curse (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":0}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":8,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:301297:effect:1:aura:108","name":"Blatant Curse (Aura 108)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","dispelCategory":"curse","modifiers":[{"kind":"stat","stat":"ranged-attack-power","operation":"percent","value":-0.25}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":108,"miscValue":14,"triggerSpellId":0}]}],"talentEntryId":11323},{"id":"coa-tree-12048","classId":"witch-doctor","dbcSpellId":572870,"name":"Blessing of Hir'eek","unlockLevel":1,"icon":"/assets/ui/spells/trade_archaeology_trollbatidol.png","sigil":"BO","description":"Your Hexbreak now removes an additional curse effect.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"mana","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:572870:effect:0:aura:107","name":"Blessing of Hir'eek (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"sLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"witch-hunter","abilities":[{"id":"coa-15-agile-steps-58-705521","classId":"witch-hunter","dbcSpellId":705521,"name":"Agile Steps","unlockLevel":1,"icon":"/assets/ui/spells/inv_boot_cloth_nzothraidmythic_d_01.png","sigil":"AS","description":"Agile StepsRank 1Reduces the cooldown of Vault by 2 sec.","target":"self","range":{"min":0,"max":0},"castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705521:effect:0:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705521:effect:1:aura:107","name":"Agile Steps (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":-20}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":11,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705521:effect:2:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":1,"triggerSpellId":0}],"passive":true,"source":"coa-progression","ranks":[{"rank":1,"spellId":705521,"level":1,"description":"Agile StepsRank 1Reduces the cooldown of Vault by 2 sec.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705521:effect:0:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705521:effect:1:aura:107","name":"Agile Steps (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":-20}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":11,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705521:effect:2:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":1,"triggerSpellId":0}]},{"rank":2,"spellId":705522,"level":1,"description":"Agile StepsRank 2Reduces the cooldown of Vault by 4 sec.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705522:effect:0:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705522:effect:1:aura:107","name":"Agile Steps (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":-40}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":11,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705522:effect:2:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":1,"triggerSpellId":0}]},{"rank":3,"spellId":705523,"level":1,"description":"Agile StepsRank 3InstantReduces the cooldown of Vault by 3 sec.","castMode":"instant","castTimeMs":0,"cooldownMs":0,"gcdMs":1500,"cost":{"resource":"rage","amount":0},"effects":[{"kind":"apply-aura","aura":{"id":"coa:705523:effect:0:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":4,"miscValue":127,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705523:effect:1:aura:107","name":"Agile Steps (Aura 107)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","modifiers":[{"kind":"stat","stat":"attack-power","operation":"percent","value":-30}]},"recipient":"caster","sourceEffectType":6,"sourceAuraType":107,"miscValue":11,"triggerSpellId":0},{"kind":"apply-aura","aura":{"id":"coa:705523:effect:2:aura:4","name":"Agile Steps (Aura 4)","disposition":"buff","durationMs":null,"maxStacks":1,"stackBehavior":"refresh","utilityTags":["coa-aura:4"]},"recipient":"caster","sourceEffectType":6,"sourceALine truncated
@@ -1,2 +1,2 @@
// Generated by npm run dungeon:catalog. Do not edit.
export default "H4sIAAAAAAACCuy9a48jx7Eg+lcI7gJ7Di6Zk5GRzwH2gx72se5ax7oar42FMTgokslmuUlWb7E4o5Ew//0ist4PksXuVk9Pu/VBUjNZjMyoeEdkxG/Tw3Ljd9HffHqIk/30Lcymh+SYLv307W/TZbS7i+Kb/Y/RPl77QzZ9O10d9zc+2c/v4ju/jff+TflB+V32z0Oyn86mfv8hTpP9zu+zn6LlbXTjD9O3/5ge0uWbm2jn39z4vU+jzK/erOMP/qdt9Mmn3+e/9cPuLkmzQ/lLA4/son10yJJ0983h4KvfDw9M/i3z9HyUfpqso+12ES1v/336nja0TI77zKffRVm0TW6mb8/+8s/HfRbvfPHlci/Rrz5Nss13Seq/S3a7mFAiV24FK7lQRqC34JZqiY6v9TICMEZYXC3WC+ux/fi7gOU/J8vb4Y0MfrVCyZ3fbqtz/DaNDku/z1/glLE3f45W8e3hx5/+vz+s4ixJ3yy3sd9n8+UxTf0+exOlPpor8eYuypab+fdvvv/2j/HWH74L33rzjn6brRZLeol3yXKT/+affLT16Y/Rfv4uS9Loxr8pSWD+MUlvSzo4vAnPzHOQJ3/68+fZdJl88PRD07f/+K2kqx9WhI1NtEo+rqP9zfzW+7vpbLqL7mgFsfEaD9O3hv7M4iwm2kIi3SzK4uW7u+jj/jB9C9zNpmkS7eL9DdHIYfpWyJq+y7exTFI//Tzr7IFo4GO8X80PWbK8jVa+sQ3Z3oZqbgN623DY3QUfuYmVj1a7eO8PDdj6DAqE6KHA9FGAI6F/jOJtvL+ZL6MPPt039iA7r8G29sC7exBKdPdgRm4hjX5N0rXfz2/T6Lht7MCcIwQ7AgsgRm5hsY2Wt+so2yS7+cr7uyYebHsXuoUH08MDh94uxlLCcbuKdtG+hm34VRhALu6NgZt9svOpv2mCdx3w8jwnoukdHWEsJx73t34/J6m+bTBhYO7TW8Ae9qXqbkFeS4Wr5GOTD0C4cwSgemToZO8ljGXGwzJKtz6b7xLSTz791NiGdWfkEfboEInqOtvQI7fx63G7jtI0uq3BC34OvIAR4gDkNcyYJsvb+eEuThvUILqvAlq7MD2GUFr3BKO4ehcrf5dtGhQhsMMXgM1t6AEVJfsvQ42miU2yTXbRftnERJca7AXJIPS9qeGQpSQYt7umcuy+CdeEr3raQWJPNNAvjIK/i9LouEr2TdV89vQ9qaBETyoIPlos3Ph1nPr5chMddo092HOSqW8fAKmK+0mmFYHftVVjjxNEixN6UsmoHgGosS/gsImyzKd+Nd9E222DEZTsMEKLD7Bvpzh7b9G42CbJar4+pvuoyQhKijNbgJ5YBHT33sLGb7eBFFLygtKshYmOtdR6HdDDhFX3VtSHzEe7D9FxmzXBq+uw0CdGGGutHfcrny6SmyZ0fYYVBsxVDfc2Vw/b6IOf3/l9C/nmzOnFACv2dBOOxX6ULqMsjX5tQFfi3Ond5Vc/lg8XSRbt42XUhI3ntLLrY97dWw/t/HIT7aO0CV1eRXVW3tskyJ3F+TZafErjfbZpbkJdR3z2/gLg4LONv73tiUGlzzG/HjAH7u2xUuRiniW7RQv+OfoPOG7Dh/tTQXRcbvw+iufL9NNdSwIqew4J8rK/jGY0Dm5iso4P88ynaVsd2LOCsO8z9v0Fe419ON8laXRo2obandnAgDq6t1XgD8vozs/XKbmsx3S/SbbN8IXS53RzXzRg33vGsag4ZjdRuvKdOI4y58TDAGeCuL9SKnZwF+/30bLpQSpzTj6MEVJjX0i28fO9/+XYZAqjz/mOPckg8P4iksAny+O2Dd+eO/yYVzBWMS6P2xBHStbzIYdBubNiuh9OgnvH04J0zveR7FtbcFdRgjH3tlJWaXSbbaI02Xd4QnN+lbZy7t5uW/TrP5PtfO/T46IJH87Jx57nZPh96aF6C9v4ZpPt4/1NcxfiKmIYIsuxgaWb437VimRofi6w2wduzb3jeR/ihKI5JJmb8O2ZV9Bz3Nx92SDa7G+jjc/myXY1v433N6uk4b5qOBvP6dsMiPe2GdZJeuMDQybHpt2kUZwzGXrEKOG+ujpL42hLOyAhudxEu7u4GU/Qip9BRu+VqPu+krs4C2ggwdCEfo4gsM8N2t7beay4MvXrrV9mbTTosyZcfyP3FtFZvL/1aeaXm/lhk3ykiGu9DSs6Mgqa2+hTpj63i7s0WfrVMY228zJP2KfPNPnV7+epj5abZvDbPvE2kvQmyTK/n1M2qBH5Nfb3Rsj72XTl1/E+JoI4hFRdP2McD2ftsjjb0g+/q1Ym/6uXz9uub8q074p+31Kq9pe7qExnLrfR4RAv2xnlH5MV/fDNNllE2/nHXTKdTVfxeh0vj9vs09+iNI72Wb7bsLd9ku6ibetLzU8PhJ8fo8NtOM3Wf/Dbn6N9yEyCnSF/X6CBQivfV7/wQ+uXow9RvI0W8TYOv138GezNu9Qf/J7eBJ3ot+k2WRb/P4CabON3dLYf9oeMIrurSUEJtM/jbhel9PN/JNU5yTZpcrzZTDq/Mpus/NpH2STODpOKOiZpQq7RbBLtVxN6Q5Ns4ycUrfo0ibbxB8+ms+k2iVbx/uZHfziEzOz0p9TfRWm8v+kCYYy+f9wvN1Ga+dU3qY/+Mwo7/9/lZ5P+6YiobtLkuCfc/Tdu+YrTq13naexlsk3SsBCBAD6dTfc+SvOk55r+R2j+eTaNdgtKJ/+ZcNB6LLIL6cimifcZ5cPpTXAmxOfZdON38eFu41NfPXa4/fRd+aQ1bmkpfJJvrvqcO77grvuLWn6ehdhrEJPRtr+TlVgat2o/B7Npsl4ffEZkJWaCz+bm/WdihsyTFjqEXzhmyTH7KYRVA79N/+tb+O9Uv5CvEI7p4/ez6WLr96v2N0X4ZlhofDFareKMiixa35Xhu+Va9fWwoTvaysd4lW0oQM8JffkRkazUO3pof5MbA8tknyXHNPzoj0JOBFeT76yeANgJSDER0kwEtxMwMHmHKCcGJpLrCQg9nU1/RDsR6CbfAXcTsDgBIyZC24mQPDz2DqWcOD1BZybGTN9T4UBERR8BWx/iwzHa1nxe/D2bruOtL8gx/4zdbIkwjul2+nb6Jv+FvOSiqvh4gzivhdib1nPLjV/eHo676dupWi64MxxVtBSOc+usXgm+WBq06zVfKiGlAb8Gv/bWI4/WC+O5c3qhELSNJPFx/KufvnVac9IkZILsb7b+O+JTEtLoHAmcZbLdxrkULM9Xf9Q6YvXx9afsPto4KEaSL4SQK2fWOlLOKL4U67VZ+tUaECNYqGgpI5TerNZrzdd87bhZRmvw6JfKVwcVylinhw4qFR10H32IbyrpmAvs+qPWSevPrz9q79nGWa1SyyVfLCV4sTILh8h5tFhEK7OMnFqsl1IZw1EuuUKwq6WRbuH0EhYislZ4Xp1VCmP6RxVWcqLcLI32h3WS7uigd8khzg/9Dz7jM/6elHOpJaqPDsuIlCjMyBjZ/T35GBz61Pt/+2X2afbrv//Pf5t/TD6yX2b071/Dvz/9+/TzbLogQRa4ZBfTD84FKmbJzZtzZrWD2dxIBujwPbH8L9O3/zCOSWfsDMAxJ1DNhLRMWB7ElN/T7vPCsH3+NjryffKH8isk0ZPsp/qAc7RMGidmAhgnD34OijkeYK+T9GOUruhbnCnOrURrjFJaUviez2i3SqHRUqBEa418P5t+ij5O39L3hVQGpVHWSGnBkXhIfdTQ/b7e1OVtLz2pygsbTqNVfCQDXJGhFufBfx/NU59t4u1NkjZg/Vx99j8Okz+UurgFCRRTAsVMKIYAszkwZ1pwpGjDWYTwwSHefvDpNsotwgLct7Q0eVcvnYJqmBHGzgRnqO0MjGBCc3MG6DLZ7SJK8MwPd2QPfIi2DbjflauTd9XqyQNLxbgQYiY1c4arGaBkqM5CT1ZJ8NAW23i/+kh1a+E3C+h/WSXBmPm2sXoSOnLmuBYzKZmQROOcOXcW+Nrv0+MhwF/5D8kxbcL+Y1gM4L8vFk+/aRSMcyVmRjAHXM0kMmXOwv6YbNfzXSj5mO+j/So51KD/nmzXkx/D2uQ/w9ppyFIza52YOcesQzVDzZw8CzlKl5tddOPnUXq8CUq1APtNsTD5Jiychul4Lm9cKU0MQ9GF+b7psfwWuPXTHK2GShc0PppNb+NgOu6SRYPotz66nfw9SSmQtEx2iygYY8GOz+M2Gx9ts82Px20W321j2h7MplRRdeM7H+6SD/7dnffknTCtDFAOb+ujw6bwCOjvKMty96mUMYvoEC/n+cdNZjzEy8k35acrT1Z2MN93fuuJe7IovSF7cHqXxsGyn4WijoR02t3m0yFe5r7FPt6VHkMFJM33I5miQydbcpV/DHEqstEGDle93lA9OjcgTIOWqMiPzPy/x9ttWWEaCs1CRrix97s0+ScZvttLB8hVb2f7y+iQ1ZsXtr13Kezw3hmIz6SESoPvtxJgZalLVAtFejhaEgl+V/sEK7OAaaVIOXOGdMRy47NPd3T0zXEX7ZM4BOKSlQ+/PmBWVAWuHUf3zTL1UXZM/eHNKj7cbaNPc8thnh/arwpbo9Ts/2f6dg6B6Z1GoY2T1lEpUu53/KXwD/hsuo0WfvunwuwGYlZFajq99enPBfcAE/bz50I1E4eoPtOoU0zTUIJ/38QZ5Yy2d0P8Q+HAV/7p8w8IJWVDD5B7Pfkm3SVpk33Ct+7HP2v6xavYB/ipvY/gHy+XetXnn4Vb2LWo+QcYp/Du78tARrjHZSDBjDbYZSDOtNFNDnLCdDnIBSlZcNAiOZzVv42gVxHUmnybP7KJDn9Okmz6NkuPfkhLwSCXMRSu+Y899XZHcB5lbL5yztsk20/zwzG9aZief0q2nybvis8aOyUjprlRCiUtPs1DwKu5W/rN81wm2ttUjnLk/W1yZkVt2gB/JIUFjCokf19+AwDzyBwnGQ/5rK7K4oC Line truncated
export default "H4sIAAAAAAACCuy9a48jx7Eg+lcI7gJ7Di6Zk5GRzwH2gx72se5ax7oar42FMTgokslmuUlWb7E4o5Ew//0ist4PksXuVk9Pu/VBUjNZjMyoeEdkxG/Tw3Ljd9HffHqIk/30Lcymh+SYLv307W/TZbS7i+Kb/Y/RPl77QzZ9O10d9zc+2c/v4ju/jff+TflB+V32z0Oyn86mfv8hTpP9zu+zn6LlbXTjD9O3/5ge0uWbm2jn39z4vU+jzK/erOMP/qdt9Mmn3+e/9cPuLkmzQ/lLA4/son10yJJ0983h4KvfDw9M/i3z9HyUfpqso+12ES1v/336nja0TI77zKffRVm0TW6mb8/+8s/HfRbvfPHlci/Rrz5Nss13Seq/S3a7mFAiV24FK7lQRqC34JZqiY6v9TICMEZYXC3WC+ux/fi7gOU/J8vb4Y0MfrVCyZ3fbqtz/DaNDku/z1/glLE3f45W8e3hx5/+vz+s4ixJ3yy3sd9n8+UxTf0+exOlPpor8eYuypab+fdvvv/2j/HWH74L33rzjn6brRZLeol3yXKT/+affLT16Y/Rfv4uS9Loxr8pSWD+MUlvSzo4vAnPzHOQJ3/68+fZdJl88PRD07f/+K2kqx9WhI1NtEo+rqP9zfzW+7vpbLqL7mgFsfEaD9O3hv7M4iwm2kIi3SzK4uW7u+jj/jB9C9zNpmkS7eL9DdHIYfpWyJq+y7exTFI//Tzr7IFo4GO8X80PWbK8jVa+sQ3Z3oZqbgN623DY3QUfuYmVj1a7eO8PDdj6DAqE6KHA9FGAI6F/jOJtvL+ZL6MPPt039iA7r8G29sC7exBKdPdgRm4hjX5N0rXfz2/T6Lht7MCcIwQ7AgsgRm5hsY2Wt+so2yS7+cr7uyYebHsXuoUH08MDh94uxlLCcbuKdtG+hm34VRhALu6NgZt9svOpv2mCdx3w8jwnoukdHWEsJx73t34/J6m+bTBhYO7TW8Ae9qXqbkFeS4Wr5GOTD0C4cwSgemToZO8ljGXGwzJKtz6b7xLSTz791NiGdWfkEfboEInqOtvQI7fx63G7jtI0uq3BC34OvIAR4gDkNcyYJsvb+eEuThvUILqvAlq7MD2GUFr3BKO4ehcrf5dtGhQhsMMXgM1t6AEVJfsvQ42miU2yTXbRftnERJca7AXJIPS9qeGQpSQYt7umcuy+CdeEr3raQWJPNNAvjIK/i9LouEr2TdV89vQ9qaBETyoIPlos3Ph1nPr5chMddo092HOSqW8fAKmK+0mmFYHftVVjjxNEixN6UsmoHgGosS/gsImyzKd+Nd9E222DEZTsMEKLD7Bvpzh7b9G42CbJar4+pvuoyQhKijNbgJ5YBHT33sLGb7eBFFLygtKshYmOtdR6HdDDhFX3VtSHzEe7D9FxmzXBq+uw0CdGGGutHfcrny6SmyZ0fYYVBsxVDfc2Vw/b6IOf3/l9C/nmzOnFACv2dBOOxX6ULqMsjX5tQFfi3Ond5Vc/lg8XSRbt42XUhI3ntLLrY97dWw/t/HIT7aO0CV1eRXVW3tskyJ3F+TZafErjfbZpbkJdR3z2/gLg4LONv73tiUGlzzG/HjAH7u2xUuRiniW7RQv+OfoPOG7Dh/tTQXRcbvw+iufL9NNdSwIqew4J8rK/jGY0Dm5iso4P88ynaVsd2LOCsO8z9v0Fe419ON8laXRo2obandnAgDq6t1XgD8vozs/XKbmsx3S/SbbN8IXS53RzXzRg33vGsag4ZjdRuvKdOI4y58TDAGeCuL9SKnZwF+/30bLpQSpzTj6MEVJjX0i28fO9/+XYZAqjz/mOPckg8P4iksAny+O2Dd+eO/yYVzBWMS6P2xBHStbzIYdBubNiuh9OgnvH04J0zveR7FtbcFdRgjH3tlJWaXSbbaI02Xd4QnN+lbZy7t5uW/TrP5PtfO/T46IJH87Jx57nZPh96aF6C9v4ZpPt4/1NcxfiKmIYIsuxgaWb437VimRofi6w2wduzb3jeR/ihKI5JJmb8O2ZV9Bz3Nx92SDa7G+jjc/myXY1v433N6uk4b5qOBvP6dsMiPe2GdZJeuMDQybHpt2kUZwzGXrEKOG+ujpL42hLOyAhudxEu7u4GU/Qip9BRu+VqPu+krs4C2ggwdCEfo4gsM8N2t7beay4MvXrrV9mbTTosyZcfyP3FtFZvL/1aeaXm/lhk3ykiGu9DSs6Mgqa2+hTpj63i7s0WfrVMY228zJP2KfPNPnV7+epj5abZvDbPvE2kvQmyTK/n1M2qBH5Nfb3Rsj72XTl1/E+JoI4hFRdP2McD2ftsjjb0g+/q1Ym/6uXz9uub8q074p+31Kq9pe7qExnLrfR4RAv2xnlH5MV/fDNNllE2/nHXTKdTVfxeh0vj9vs09+iNI72Wb7bsLd9ku6ibetLzU8PhJ8fo8NtOM3Wf/Dbn6N9yEyCnSF/X6CBQivfV7/wQ+uXow9RvI0W8TYOv138GezNu9Qf/J7eBJ3ot+k2WRb/P4CabON3dLYf9oeMIrurSUEJtM/jbhel9PN/JNU5yTZpcrzZTDq/Mpus/NpH2STODpOKOiZpQq7RbBLtVxN6Q5Ns4ycUrfo0ibbxB8+ms+k2iVbx/uZHfziEzOz0p9TfRWm8v+kCYYy+f9wvN1Ga+dU3qY/+Mwo7/9/lZ5P+6YiobtLkuCfc/Tdu+YrTq13naexlsk3SsBCBAD6dTfc+SvOk55r+R2j+eTaNdgtKJ/+ZcNB6LLIL6cimifcZ5cPpTXAmxOfZdON38eFu41NfPXa4/fRd+aQ1bmkpfJJvrvqcO77grvuLWn6ehdhrEJPRtr+TlVgat2o/B7Npsl4ffEZkJWaCz+bm/WdihsyTFjqEXzhmyTH7KYRVA79N/+tb+O9Uv5CvEI7p4/ez6WLr96v2N0X4ZlhofDFareKMiixa35Xhu+Va9fWwoTvaysd4lW0oQM8JffkRkazUO3pof5MbA8tknyXHNPzoj0JOBFeT76yeANgJSDER0kwEtxMwMHmHKCcGJpLrCQg9nU1/RDsR6CbfAXcTsDgBIyZC24mQPDz2DqWcOD1BZybGTN9T4UBERR8BWx/iwzHa1nxe/D2bruOtL8gx/4zdbIkwjul2+nb6Jv+FvOSiqvh4gzivhdib1nPLjV/eHo676dupWi64MxxVtBSOc+usXgm+WBq06zVfKiGlAb8Gv/bWI4/WC+O5c3qhELSNJPFx/KufvnVac9IkZILsb7b+O+JTEtLoHAmcZbLdxrkULM9Xf9Q6YvXx9afsPto4KEaSL4SQK2fWOlLOKL4U67VZ+tUaECNYqGgpI5TerNZrzdd87bhZRmvw6JfKVwcVylinhw4qFR10H32IbyrpmAvs+qPWSevPrz9q79nGWa1SyyVfLCV4sTILh8h5tFhEK7OMnFqsl1IZw1EuuUKwq6WRbuH0EhYislZ4Xp1VCmP6RxVWcqLcLI32h3WS7uigd8khzg/9Dz7jM/6elHOpJaqPDsuIlCjMyBjZ/T35GBz61Pt/+2X2afbrv//Pf5t/TD6yX2b071/Dvz/9+/TzbLogQRa4ZBfTD84FKmbJzZtzZrWD2dxIBujwPbH8L9O3/zCOSWfsDMAxJ1DNhLRMWB7ElN/T7vPCsH3+NjryffKH8isk0ZPsp/qAc7RMGidmAhgnD34OijkeYK+T9GOUruhbnCnOrURrjFJaUviez2i3SqHRUqBEa418P5t+ij5O39L3hVQGpVHWSGnBkXhIfdTQ/b7e1OVtLz2pygsbTqNVfCQDXJGhFufBfx/NU59t4u1NkjZg/Vx99j8Okz+UurgFCRRTAsVMKIYAszkwZ1pwpGjDWYTwwSHefvDpNsotwgLct7Q0eVcvnYJqmBHGzgRnqO0MjGBCc3MG6DLZ7SJK8MwPd2QPfIi2DbjflauTd9XqyQNLxbgQYiY1c4arGaBkqM5CT1ZJ8NAW23i/+kh1a+E3C+h/WSXBmPm2sXoSOnLmuBYzKZmQROOcOXcW+Nrv0+MhwF/5D8kxbcL+Y1gM4L8vFk+/aRSMcyVmRjAHXM0kMmXOwv6YbNfzXSj5mO+j/So51KD/nmzXkx/D2uQ/w9ppyFIza52YOcesQzVDzZw8CzlKl5tddOPnUXq8CUq1APtNsTD5Jiychul4Lm9cKU0MQ9GF+b7psfwWuPXTHK2GShc0PppNb+NgOu6SRYPotz66nfw9SSmQtEx2iygYY8GOz+M2Gx9ts82Px20W321j2h7MplRRdeM7H+6SD/7dnffknTCtDFAOb+ujw6bwCOjvKMty96mUMYvoEC/n+cdNZjzEy8k35acrT1Z2MN93fuuJe7IovSF7cHqXxsGyn4WijoR02t3m0yFe5r7FPt6VHkMFJM33I5miQydbcpV/DHEqstEGDle93lA9OjcgTIOWqMiPzPy/x9ttWWEaCs1CRrix97s0+ScZvttLB8hVb2f7y+iQ1ZsXtr13Kezw3hmIz6SESoPvtxJgZalLVAtFejhaEgl+V/sEK7OAaaVIOXOGdMRy47NPd3T0zXEX7ZM4BOKSlQ+/PmBWVAWuHUf3zTL1UXZM/eHNKj7cbaNPc8thnh/arwpbo9Ts/2f6dg6B6Z1GoY2T1lEpUu53/KXwD/hsuo0WfvunwuwGYlZFajq99enPBfcAE/bz50I1E4eoPtOoU0zTUIJ/38QZ5Yy2d0P8Q+HAV/7p8w8IJWVDD5B7Pfkm3SVpk33Ct+7HP2v6xavYB/ipvY/gHy+XetXnn4Vb2LWo+QcYp/Du78tARrjHZSDBjDbYZSDOtNFNDnLCdDnIBSlZcNAiOZzVv42gVxHUmnybP7KJDn9Okmz6NkuPfkhLwSCXMRSu+Y899XZHcB5lbL5yztsk20/zwzG9aZief0q2nybvis8aOyUjprlRCiUtPs1DwKu5W/rN81wm2ttUjnLk/W1yZkVt2gB/JIUFjCokf19+AwDzyBwnGQ/5rK7K4oC Line truncated
@@ -1 +1 @@
{"schemaVersion":1,"source":{"campaignManifest":"dungeon-pipeline/dungeon-campaign.json","environmentPackages":["src/game/generated/fivePlayerDungeonImports.json","src/game/generated/manastormAssetPackages.json (temporary fallback)"],"encounterCatalog":"src/game/generated/manastormRuntimeCatalog.json","azerothCoreCommit":"4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3","azerothCoreSourceLock":"src/game/generated/azerothCoreSourceLock.json","spellCatalog":{"ascension":"../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc","epoch":"../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc"}},"coverage":[{"dungeonId":"shadowfang-keep","mapId":33,"encounters":7,"entities":31,"staticSpawns":109,"roamingPacks":24,"source":"azerothcore"},{"dungeonId":"stormwind-stockade","mapId":34,"encounters":5,"entities":11,"staticSpawns":93,"roamingPacks":0,"source":"azerothcore"},{"dungeonId":"deadmines","mapId":36,"encounters":7,"entities":22,"staticSpawns":179,"roamingPacks":23,"source":"azerothcore"},{"dungeonId":"wailing-caverns","mapId":43,"encounters":8,"entities":20,"staticSpawns":252,"roamingPacks":7,"source":"azerothcore"},{"dungeonId":"razorfen-kraul","mapId":47,"encounters":7,"entities":38,"staticSpawns":179,"roamingPacks":12,"source":"azerothcore"},{"dungeonId":"blackfathom-deeps","mapId":48,"encounters":6,"entities":27,"staticSpawns":201,"roamingPacks":10,"source":"azerothcore"},{"dungeonId":"uldaman","mapId":70,"encounters":7,"entities":38,"staticSpawns":302,"roamingPacks":12,"source":"azerothcore"},{"dungeonId":"gnomeregan","mapId":90,"encounters":4,"entities":31,"staticSpawns":371,"roamingPacks":31,"source":"azerothcore"},{"dungeonId":"sunken-temple","mapId":109,"encounters":4,"entities":33,"staticSpawns":245,"roamingPacks":4,"source":"azerothcore"},{"dungeonId":"razorfen-downs","mapId":129,"encounters":6,"entities":25,"staticSpawns":194,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"scarlet-monastery","mapId":189,"encounters":5,"entities":37,"staticSpawns":310,"roamingPacks":16,"source":"azerothcore"},{"dungeonId":"zulfarrak","mapId":209,"encounters":5,"entities":21,"staticSpawns":252,"roamingPacks":14,"source":"azerothcore"},{"dungeonId":"blackrock-spire","mapId":229,"encounters":15,"entities":78,"staticSpawns":566,"roamingPacks":22,"source":"azerothcore"},{"dungeonId":"blackrock-depths","mapId":230,"encounters":13,"entities":61,"staticSpawns":1040,"roamingPacks":15,"source":"azerothcore"},{"dungeonId":"scholomance","mapId":289,"encounters":8,"entities":38,"staticSpawns":326,"roamingPacks":16,"source":"azerothcore"},{"dungeonId":"stratholme","mapId":329,"encounters":9,"entities":50,"staticSpawns":431,"roamingPacks":29,"source":"azerothcore"},{"dungeonId":"maraudon","mapId":349,"encounters":8,"entities":33,"staticSpawns":525,"roamingPacks":20,"source":"azerothcore"},{"dungeonId":"ragefire-chasm","mapId":389,"encounters":4,"entities":11,"staticSpawns":127,"roamingPacks":4,"source":"azerothcore"},{"dungeonId":"dire-maul","mapId":429,"encounters":12,"entities":75,"staticSpawns":756,"roamingPacks":59,"source":"azerothcore"},{"dungeonId":"shattered-halls","mapId":540,"encounters":3,"entities":32,"staticSpawns":198,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"blood-furnace","mapId":542,"encounters":3,"entities":17,"staticSpawns":139,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"hellfire-ramparts","mapId":543,"encounters":2,"entities":12,"staticSpawns":85,"roamingPacks":12,"source":"azerothcore"},{"dungeonId":"steamvault","mapId":545,"encounters":3,"entities":17,"staticSpawns":127,"roamingPacks":17,"source":"azerothcore"},{"dungeonId":"underbog","mapId":546,"encounters":4,"entities":22,"staticSpawns":161,"roamingPacks":23,"source":"azerothcore"},{"dungeonId":"slave-pens","mapId":547,"encounters":3,"entities":21,"staticSpawns":122,"roamingPacks":32,"source":"azerothcore"},{"dungeonId":"arcatraz","mapId":552,"encounters":4,"entities":29,"staticSpawns":85,"roamingPacks":9,"source":"azerothcore"},{"dungeonId":"botanica","mapId":553,"encounters":5,"entities":29,"staticSpawns":169,"roamingPacks":15,"source":"azerothcore"},{"dungeonId":"mechanar","mapId":554,"encounters":3,"entities":17,"staticSpawns":84,"roamingPacks":14,"source":"azerothcore"},{"dungeonId":"shadow-labyrinth","mapId":555,"encounters":4,"entities":22,"staticSpawns":189,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"sethekk-halls","mapId":556,"encounters":2,"entities":16,"staticSpawns":104,"roamingPacks":24,"source":"azerothcore"},{"dungeonId":"mana-tombs","mapId":557,"encounters":3,"entities":14,"staticSpawns":119,"roamingPacks":15,"source":"azerothcore"},{"dungeonId":"auchenai-crypts","mapId":558,"encounters":2,"entities":14,"staticSpawns":93,"roamingPacks":37,"source":"azerothcore"},{"dungeonId":"magisters-terrace","mapId":585,"encounters":3,"entities":18,"staticSpawns":145,"roamingPacks":8,"source":"azerothcore"},{"dungeonId":"black-morass","mapId":269,"encounters":3,"entitiesLine truncated
{"schemaVersion":1,"source":{"campaignManifest":"dungeon-pipeline/dungeon-campaign.json","environmentPackages":["src/game/generated/fivePlayerDungeonImports.json","src/game/generated/manastormAssetPackages.json (temporary fallback)"],"encounterCatalog":"src/game/generated/manastormRuntimeCatalog.json","azerothCoreCommit":"4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3","azerothCoreSourceLock":"src/game/generated/azerothCoreSourceLock.json","spellCatalog":{"ascension":"../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc","epoch":"../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc"}},"coverage":[{"dungeonId":"shadowfang-keep","mapId":33,"encounters":7,"entities":31,"staticSpawns":109,"roamingPacks":24,"source":"azerothcore"},{"dungeonId":"stormwind-stockade","mapId":34,"encounters":5,"entities":11,"staticSpawns":93,"roamingPacks":0,"source":"azerothcore"},{"dungeonId":"deadmines","mapId":36,"encounters":7,"entities":22,"staticSpawns":179,"roamingPacks":23,"source":"azerothcore"},{"dungeonId":"wailing-caverns","mapId":43,"encounters":8,"entities":20,"staticSpawns":252,"roamingPacks":7,"source":"azerothcore"},{"dungeonId":"razorfen-kraul","mapId":47,"encounters":7,"entities":38,"staticSpawns":179,"roamingPacks":12,"source":"azerothcore"},{"dungeonId":"blackfathom-deeps","mapId":48,"encounters":6,"entities":27,"staticSpawns":201,"roamingPacks":10,"source":"azerothcore"},{"dungeonId":"uldaman","mapId":70,"encounters":7,"entities":38,"staticSpawns":302,"roamingPacks":12,"source":"azerothcore"},{"dungeonId":"gnomeregan","mapId":90,"encounters":4,"entities":31,"staticSpawns":371,"roamingPacks":31,"source":"azerothcore"},{"dungeonId":"sunken-temple","mapId":109,"encounters":4,"entities":33,"staticSpawns":245,"roamingPacks":4,"source":"azerothcore"},{"dungeonId":"razorfen-downs","mapId":129,"encounters":6,"entities":25,"staticSpawns":194,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"scarlet-monastery","mapId":189,"encounters":5,"entities":37,"staticSpawns":310,"roamingPacks":16,"source":"azerothcore"},{"dungeonId":"zulfarrak","mapId":209,"encounters":5,"entities":21,"staticSpawns":252,"roamingPacks":14,"source":"azerothcore"},{"dungeonId":"blackrock-spire","mapId":229,"encounters":15,"entities":78,"staticSpawns":566,"roamingPacks":22,"source":"azerothcore"},{"dungeonId":"blackrock-depths","mapId":230,"encounters":13,"entities":61,"staticSpawns":1040,"roamingPacks":15,"source":"azerothcore"},{"dungeonId":"scholomance","mapId":289,"encounters":8,"entities":38,"staticSpawns":326,"roamingPacks":16,"source":"azerothcore"},{"dungeonId":"stratholme","mapId":329,"encounters":9,"entities":50,"staticSpawns":431,"roamingPacks":29,"source":"azerothcore"},{"dungeonId":"maraudon","mapId":349,"encounters":8,"entities":33,"staticSpawns":525,"roamingPacks":20,"source":"azerothcore"},{"dungeonId":"ragefire-chasm","mapId":389,"encounters":4,"entities":11,"staticSpawns":127,"roamingPacks":4,"source":"azerothcore"},{"dungeonId":"dire-maul","mapId":429,"encounters":12,"entities":75,"staticSpawns":756,"roamingPacks":59,"source":"azerothcore"},{"dungeonId":"shattered-halls","mapId":540,"encounters":3,"entities":32,"staticSpawns":198,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"blood-furnace","mapId":542,"encounters":3,"entities":17,"staticSpawns":139,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"hellfire-ramparts","mapId":543,"encounters":2,"entities":12,"staticSpawns":85,"roamingPacks":12,"source":"azerothcore"},{"dungeonId":"steamvault","mapId":545,"encounters":3,"entities":17,"staticSpawns":127,"roamingPacks":17,"source":"azerothcore"},{"dungeonId":"underbog","mapId":546,"encounters":4,"entities":22,"staticSpawns":161,"roamingPacks":23,"source":"azerothcore"},{"dungeonId":"slave-pens","mapId":547,"encounters":3,"entities":21,"staticSpawns":122,"roamingPacks":32,"source":"azerothcore"},{"dungeonId":"arcatraz","mapId":552,"encounters":4,"entities":29,"staticSpawns":85,"roamingPacks":9,"source":"azerothcore"},{"dungeonId":"botanica","mapId":553,"encounters":5,"entities":29,"staticSpawns":169,"roamingPacks":15,"source":"azerothcore"},{"dungeonId":"mechanar","mapId":554,"encounters":3,"entities":17,"staticSpawns":84,"roamingPacks":14,"source":"azerothcore"},{"dungeonId":"shadow-labyrinth","mapId":555,"encounters":4,"entities":22,"staticSpawns":189,"roamingPacks":13,"source":"azerothcore"},{"dungeonId":"sethekk-halls","mapId":556,"encounters":2,"entities":16,"staticSpawns":104,"roamingPacks":24,"source":"azerothcore"},{"dungeonId":"mana-tombs","mapId":557,"encounters":3,"entities":14,"staticSpawns":119,"roamingPacks":15,"source":"azerothcore"},{"dungeonId":"auchenai-crypts","mapId":558,"encounters":2,"entities":14,"staticSpawns":93,"roamingPacks":37,"source":"azerothcore"},{"dungeonId":"magisters-terrace","mapId":585,"encounters":3,"entities":18,"staticSpawns":145,"roamingPacks":8,"source":"azerothcore"},{"dungeonId":"black-morass","mapId":269,"encounters":3,"entitiesLine truncated
@@ -13370,8 +13370,8 @@
{
"id": "visual",
"url": "/assets/game/manastorm/230-blackrockdepths/visual.glb",
"checksum": "42d57961c31f54ecc7bc78829751110fc89294e6318336b8f260e132e478d13d",
"byteLength": 10266900,
"checksum": "7e4c7c75a898f5000fcb686dcfc6d3c1c4e675dc3dac5f7a8d48e53372b9f364",
"byteLength": 7068884,
"triangleCount": 248302,
"compression": "meshopt+ktx2"
}
@@ -54510,8 +54510,8 @@
{
"id": "visual",
"url": "/assets/game/manastorm/230-blackrockdepths/visual.glb",
"checksum": "42d57961c31f54ecc7bc78829751110fc89294e6318336b8f260e132e478d13d",
"byteLength": 10266900,
"checksum": "7e4c7c75a898f5000fcb686dcfc6d3c1c4e675dc3dac5f7a8d48e53372b9f364",
"byteLength": 7068884,
"triangleCount": 248302,
"compression": "meshopt+ktx2"
}
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"barbarian","trees":[{"id":"coa-barbarian-31","classId":"barbarian","name":"Brutality","icon":"/assets/ui/spells/novart_physical_ability_(47)_border.png","background":"","description":"Brutality nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-barbarian-32","classId":"barbarian","name":"Headhunting","icon":"/assets/ui/spells/inv_axe_1h_draenorcrafted_d_02_a_horde.png","background":"","description":"Headhunting nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-barbarian-33","classId":"barbarian","name":"Ancestry","icon":"/assets/ui/spells/ability_monk_elusiveale.png","background":"","description":"Ancestry nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-barbarian-87","classId":"barbarian","name":"Class","icon":"/assets/ui/spells/maiming_spear.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-5744","treeId":"coa-barbarian-31","index":5744,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/novart_physical_ability_(47)_border.png","maxRank":1,"name":"Decapitate","description":"Attempt to decapitate an injured enemy, dealing 220% Weapon Damage plus 27, and converting each extra point of Energy to deal additional damage (up to a maximum cost of 100 Energy). Only usable on enemies below 35% health.","rankDescriptions":["Attempt to decapitate an injured enemy, dealing 220% Weapon Damage plus 27, and converting each extra point of Energy to deal additional damage (up to a maximum cost of 100 Energy). Only usable on enemies below 35% health."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4001","treeId":"coa-barbarian-31","index":4001,"prerequisiteId":"coa-entry-29783","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29783","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/_orc_06.png","maxRank":1,"name":"Excessive Power","description":"Level 10 Passive Increases your maximum Energy by 100%.","rankDescriptions":["Level 10 Passive Increases your maximum Energy by 100%."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":1,"isPassive":true},{"id":"coa-entry-6744","treeId":"coa-barbarian-31","index":6744,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/inv_archaeology_ogres_warmaul_chieftain.png","maxRank":1,"name":"Beheader","description":"Scoring a kill blow with Decapitate now refunds 100% of your maximum Energy.","rankDescriptions":["Scoring a kill blow with Decapitate now refunds 100% of your maximum Energy."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30792","treeId":"coa-barbarian-31","index":30792,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/achievement_boss_blackhand.png","maxRank":1,"name":"Reckless Movements","description":"Increases the damage of Ancestral Strike and Barbaric Whirl by 20%.","rankDescriptions":["Increases the damage of Ancestral Strike and Barbaric Whirl by 20%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29281","treeId":"coa-barbarian-31","index":29281,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/_d3leapattack.png","maxRank":1,"name":"Killing Spree","description":"Charge at an enemy, dealing 25 + 30% AP Physical damage. Can only be used within 6 seconds of scoring a killing blow or applying Born in Blood.","rankDescriptions":["Charge at an enemy, dealing 25 + 30% AP Physical damage. Can only be used within 6 seconds of scoring a killing blow or applying Born in Blood."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6742","treeId":"coa-barbarian-31","index":6742,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/ability_revendreth_rogue.png","maxRank":2,"name":"Pure Power","description":"Increases the damage of Smash by 30% and your expertise by 10.","rankDescriptions":["Increases the damage of Smash by 15% and your expertise by 5.","Increases the damage of Smash by 30% and your expertise by 10."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-9170","treeId":"coa-bLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"bloodmage","trees":[{"id":"coa-bloodmage-26","classId":"bloodmage","name":"Sanguine","icon":"/assets/ui/spells/epic_rpg_icon_pack_blood_0002s_0000_foreground_border.png","background":"","description":"Sanguine nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-bloodmage-52","classId":"bloodmage","name":"Accursed","icon":"/assets/ui/spells/achievement_dungeon_hallsofattonement_echelon.png","background":"","description":"Accursed nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-bloodmage-53","classId":"bloodmage","name":"Eternal","icon":"/assets/ui/spells/5_clawstrike_border.png","background":"","description":"Eternal nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-bloodmage-93","classId":"bloodmage","name":"Fleshweaver","icon":"/assets/ui/spells/spell_animarevendreth_orb.png","background":"","description":"Fleshweaver nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-bloodmage-87","classId":"bloodmage","name":"Class","icon":"/assets/ui/spells/nhi_blooddrop_(2)_border.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31175","treeId":"coa-bloodmage-26","index":31175,"prerequisiteId":"coa-entry-4025","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4025","requiredRank":1},{"talentId":"coa-entry-29543","requiredRank":1}],"column":4,"row":1,"icon":"/assets/ui/spells/epic_rpg_icon_pack_blood_0002s_0000_foreground_border.png","maxRank":1,"name":"Transgression","description":"Transforms your Blood Curse into Transgression.Transgression (Cursed Form)Enter a unique Cursed Form for 30 seconds that does not disable the use of Mortal Form abilities and casts a free Vampiric Fang on your target. While active, direct spell damage triggers a Vampiric Feast, dealing 20% additional Shadow damage to enemies, healing you equal to 50% of the damage dealt.","rankDescriptions":["Transforms your Blood Curse into Transgression.Transgression (Cursed Form)Enter a unique Cursed Form for 30 seconds that does not disable the use of Mortal Form abilities and casts a free Vampiric Fang on your target. While active, direct spell damage triggers a Vampiric Feast, dealing 20% additional Shadow damage to enemies, healing you equal to 50% of the damage dealt."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4525","treeId":"coa-bloodmage-26","index":4525,"prerequisiteId":"coa-entry-4025","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4025","requiredRank":1},{"talentId":"coa-entry-29543","requiredRank":1}],"column":6,"row":1,"icon":"/assets/ui/spells/custom_t_bloodhaze_border.png","maxRank":1,"name":"Vampiric Fang","description":"Expends Thirst Stacks Steal 36 + 34% SP health from an enemy. Damage increased by 10% for each Thirst stack. Clears Insatiable and Thirst stacks.","rankDescriptions":["Expends Thirst Stacks Steal 36 + 34% SP health from an enemy. Damage increased by 10% for each Thirst stack. Clears Insatiable and Thirst stacks."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4025","treeId":"coa-bloodmage-26","index":4025,"prerequisiteId":"coa-entry-29543","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29543","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/epic_rpg_icon_pack_blood_0003s_0000_hand_border.png","maxRank":1,"name":"Thirst","description":"Level 10 Passive Spells that cost health now grant Thirst. Reaching 10 stacks makes you Insatiable, reducing your damage dealt by -30% every 3 sec until Thirst ends. ThirstGenerates 5 Rage and then increases the health costs of your spells by 5% and increases their damage by 3%. Stacks 10 times.","rankDescriptions":["Level 10 Passive Spells that cost health now grant Thirst. Reaching 10 stacks makes you Insatiable, reducing your damage dealt by -30% every 3 sec until Thirst ends. ThirstGenerates 5 Rage and then increases the health costs of your spells by 5% and increases their damage by 3%. Stacks 10 times."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-30360","treeId":"coa-bloodmage-26","index":30360,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/ability_deathknight_necroticaura.png","maxRank":1,"name":"Valanar's Vengeance","description":"Requires Mortal Form Launch a powerful blood bolt at an enemy, dealing 188 + 127.75% SP Shadow damage. Each stack of Thirst reduces the cast time of this ability and increases its damage.","rankDescriptions":["Requires Mortal Form Launch a powerful blood bolt at an enemy, dealing 188 + 127.75%Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"chronomancer","trees":[{"id":"coa-chronomancer-56","classId":"chronomancer","name":"Infinite","icon":"/assets/ui/spells/spell_animamaw_beam.png","background":"","description":"Infinite nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-chronomancer-57","classId":"chronomancer","name":"Artificer","icon":"/assets/ui/spells/shatterecho.png","background":"","description":"Artificer nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-chronomancer-87","classId":"chronomancer","name":"Class","icon":"/assets/ui/spells/spell_holy_healingfocus.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-chronomancer-58","classId":"chronomancer","name":"Time","icon":"/assets/ui/spells/inv_staff_2h_nazmirraid_d_01.png","background":"","description":"Time nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-3997","treeId":"coa-chronomancer-56","index":3997,"prerequisiteId":"coa-entry-4031","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4031","requiredRank":1},{"talentId":"coa-entry-30249","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/spell_animamaw_beam.png","maxRank":1,"name":"Timerend","description":"Transforms your Wand of Time into Timerend.TimerendRend the fabric of time, dealing 36 Chromatic Damage over 6 seconds.","rankDescriptions":["Transforms your Wand of Time into Timerend.TimerendRend the fabric of time, dealing 36 Chromatic Damage over 6 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4031","treeId":"coa-chronomancer-56","index":4031,"prerequisiteId":"coa-entry-30249","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30249","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/achievement_boss_infinitecorruptor.png","maxRank":1,"name":"Infinite Power","description":"Level 10 Passive Casting damaging spells now reduces your damaging spell cooldowns by 10% of their remaining cooldown.","rankDescriptions":["Level 10 Passive Casting damaging spells now reduces your damaging spell cooldowns by 10% of their remaining cooldown."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-7200","treeId":"coa-chronomancer-56","index":7200,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/nhi_timewarp_border.png","maxRank":1,"name":"Melt Reality","description":"Melt the target's reality, dealing 1638 Chromatic Damage over 36 seconds. While active, periodic damage dealt to the target is replicated for 20% of the value to all enemies near them.","rankDescriptions":["Melt the target's reality, dealing 1638 Chromatic Damage over 36 seconds. While active, periodic damage dealt to the target is replicated for 20% of the value to all enemies near them."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6156","treeId":"coa-chronomancer-56","index":6156,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/inv_ingot_titansteel_dark.png","maxRank":2,"name":"Anomaly Spikes","description":"Periodic damage dealt now has a 15% chance to launch an Anomaly Spike at your target. Anomaly SpikeDeals cond(gt(SPA, SPS), 161*1+SPA*0.25, 161*1+SPS*0.25) Chromatic Damage.","rankDescriptions":["Periodic damage dealt now has a 8% chance to launch an Anomaly Spike at your target. Anomaly SpikeDeals cond(gt(SPA, SPS), 161*1+SPA*0.25, 161*1+SPS*0.25) Chromatic Damage.","Periodic damage dealt now has a 15% chance to launch an Anomaly Spike at your target. Anomaly SpikeDeals cond(gt(SPA, SPS), 161*1+SPA*0.25, 161*1+SPS*0.25) Chromatic Damage."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-31139","treeId":"coa-chronomancer-56","index":31139,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/spell_shadow_brainwash.png","maxRank":1,"name":"Mind Melt","description":"Damage dealt by Melt Reality now also reduces the target's primary attributes by -3% for 15 sec, stacking 5 times.","rankDescriptions":["Damage dealt by Melt Reality now also reduces the target's primary attributes by -3% for 15 sec, stacking 5 times."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-9185","treeId":"coa-chronomancer-56","index":9185,"prerequisiteId":null,"prerequisiteRank":nuLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"cultist","trees":[{"id":"coa-cultist-65","classId":"cultist","name":"Corruption","icon":"/assets/ui/spells/spell_shadow_unstableaffliction_3_purple.png","background":"","description":"Corruption nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-cultist-64","classId":"cultist","name":"Godblade","icon":"/assets/ui/spells/inv_chest_armor_voidelf_d_01.png","background":"","description":"Godblade nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-cultist-66","classId":"cultist","name":"Heretic","icon":"/assets/ui/spells/inv_mace_1h_orgrimmarraid_d_03.png","background":"","description":"Heretic nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-cultist-88","classId":"cultist","name":"Dreadnought","icon":"/assets/ui/spells/inv_shield_1h_artifactstormfist_d_05.png","background":"","description":"Dreadnought nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-cultist-87","classId":"cultist","name":"Class","icon":"/assets/ui/spells/_d3energyarmor.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31189","treeId":"coa-cultist-64","index":31189,"prerequisiteId":"coa-entry-4040","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4040","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/inv_chest_armor_voidelf_d_01.png","maxRank":1,"name":"Rift","description":"Apply a dark boon to yourself for 15 seconds, causing your next Hammer of Twilight to deal an additional 80% of its damage dealt as Shadow damage. Creates a rift that absorbs the next 690 + 150% AP healing taken by enemies that step inside and reduces their periodic healing received by -50% for 10 seconds while inside.","rankDescriptions":["Apply a dark boon to yourself for 15 seconds, causing your next Hammer of Twilight to deal an additional 80% of its damage dealt as Shadow damage. Creates a rift that absorbs the next 690 + 150% AP healing taken by enemies that step inside and reduces their periodic healing received by -50% for 10 seconds while inside."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4040","treeId":"coa-cultist-64","index":4040,"prerequisiteId":"coa-entry-7608","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-7608","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/nzothicon.png","maxRank":1,"name":"Obliteration","description":"Level 10 Passive Your Gaze of C'Thun now gains an additional 15 base damage and healing.","rankDescriptions":["Level 10 Passive Your Gaze of C'Thun now gains an additional 15 base damage and healing."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":1,"isPassive":true},{"id":"coa-entry-33894","treeId":"coa-cultist-64","index":33894,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/spell_shadow_chilltouch.png","maxRank":1,"name":"Hand of N'Zoth","description":"Your Hammer of Twilight, Entropic Slam, and Gaze of C'Thun now refreshes a charge of Blade of the Empire.","rankDescriptions":["Your Hammer of Twilight, Entropic Slam, and Gaze of C'Thun now refreshes a charge of Blade of the Empire."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4810","treeId":"coa-cultist-64","index":4810,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/inv_sword_02.png","maxRank":3,"name":"Voidforged Edge","description":"Your auto attacks now deal an additional 30% of the damage dealt as Shadow damage.","rankDescriptions":["Your auto attacks now deal an additional 10% of the damage dealt as Shadow damage.","Your auto attacks now deal an additional 20% of the damage dealt as Shadow damage.","Your auto attacks now deal an additional 30% of the damage dealt as Shadow damage."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6543","treeId":"coa-cultist-64","index":6543,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/inv_sword_1h_draenei_c_03.png","maxRank":2,"name":"Abyssal Edge","description":"Increases the critical strike chance of Blade of the Empire by 4% and reduces its mana cost by -50%.","rankDescriptions":["Increases the critical strike chance of Blade of the Empire by 2% and reduces its mana cost by -25%.","Increases the critical strike chance of Blade of the Empire by 4% and reduces its mana cost by -50%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"death-knight","trees":[{"id":"death-knight-blood","classId":"death-knight","name":"Blood","icon":"/assets/ui/talents/icons/spell_deathknight_bloodpresence.png","background":"/assets/ui/talents/backgrounds/talent_deathknight1.png","description":"Drain life and withstand brutal attacks.","system":"classic"},{"id":"death-knight-frost","classId":"death-knight","name":"Frost","icon":"/assets/ui/talents/icons/spell_deathknight_frostpresence.png","background":"/assets/ui/talents/backgrounds/talent_deathknight2.png","description":"Command freezing power and rune weapons.","system":"classic"},{"id":"death-knight-unholy","classId":"death-knight","name":"Unholy","icon":"/assets/ui/talents/icons/spell_deathknight_unholypresence.png","background":"/assets/ui/talents/backgrounds/talent_deathknight3.png","description":"Spread disease and forbidden necromancy.","system":"classic"}],"nodes":[{"id":"talent-1938","treeId":"death-knight-blood","index":4,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/inv_shoulder_36.png","maxRank":5,"name":"Bladed Armor","description":"Increases your attack power by 5 for every the listed amount armor value you have.","rankDescriptions":["Increases your attack power by 1 for every the listed amount armor value you have.","Increases your attack power by 2 for every the listed amount armor value you have.","Increases your attack power by 3 for every the listed amount armor value you have.","Increases your attack power by 4 for every the listed amount armor value you have.","Increases your attack power by 5 for every the listed amount armor value you have."],"system":"classic"},{"id":"talent-1939","treeId":"death-knight-blood","index":1,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":1,"icon":"/assets/ui/talents/icons/inv_axe_68.png","maxRank":2,"name":"Butchery","description":"Whenever you kill an enemy that grants experience or honor, you generate up to 20 runic power. In addition, you generate 2 rage per 5 sec while in combat.","rankDescriptions":["Whenever you kill an enemy that grants experience or honor, you generate up to 10 runic power. In addition, you generate 1 rage per 5 sec while in combat.","Whenever you kill an enemy that grants experience or honor, you generate up to 20 runic power. In addition, you generate 2 rage per 5 sec while in combat."],"system":"classic"},{"id":"talent-1941","treeId":"death-knight-blood","index":7,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_deathknight_runetap.png","maxRank":1,"name":"Rune Tap","description":"Converts 1 Blood Rune into 10% of your maximum health.","rankDescriptions":["Converts 1 Blood Rune into 10% of your maximum health."],"system":"classic"},{"id":"talent-1942","treeId":"death-knight-blood","index":10,"prerequisiteId":"talent-1941","prerequisiteRank":1,"prerequisites":[{"talentId":"talent-1941","requiredRank":1}],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_deathknight_runetap.png","maxRank":3,"name":"Improved Rune Tap","description":"Increases the health provided by Rune Tap by 100% and lowers its cooldown by 30 sec.","rankDescriptions":["Increases the health provided by Rune Tap by 33% and lowers its cooldown by 10 sec.","Increases the health provided by Rune Tap by 66% and lowers its cooldown by 20 sec.","Increases the health provided by Rune Tap by 100% and lowers its cooldown by 30 sec."],"system":"classic"},{"id":"talent-1959","treeId":"death-knight-blood","index":24,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":9,"icon":"/assets/ui/talents/icons/ability_creature_cursed_02.png","maxRank":3,"name":"Will of the Necropolis","description":"Damage that would take you below 35% health or taken while you are at 35% health is reduced by 15%.","rankDescriptions":["Damage that would take you below 35% health or taken while you are at 35% health is reduced by 5%.","Damage that would take you below 35% health or taken while you are at 35% health is reduced by 10%.","Damage that would take you below 35% health or taken while you are at 35% health is reduced by 15%."],"system":"classic"},{"id":"talent-1960","treeId":"death-knight-blood","index":18,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":7,"icon":"/assets/ui/talents/icons/spell_shadow_soulleech.png","maxRank":3,"name":"Bloodworms","description":"Your weapon hits have a 9% chance to cause the target to spawn 2-4 Bloodworms. Bloodworms attack your enemies, healing you as they do damage for 20 sec or until killed.","rankDescriptions":["Your weapon hits have a 3% chance to cause the target to spawn 2-4 Bloodworms. Bloodworms attack your enemies, healing you as they do damage for 20 sec or until killed.","Your weapon hits have a 6% chance to cause the target to spawn 2-4 Bloodworms. Bloodworms attack yoLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"druid","trees":[{"id":"druid-balance","classId":"druid","name":"Balance","icon":"/assets/ui/talents/icons/spell_nature_starfall.png","background":"/assets/ui/talents/backgrounds/talent_druid1.png","description":"Wield lunar, solar, and natural magic.","system":"classic"},{"id":"druid-feral-combat","classId":"druid","name":"Feral Combat","icon":"/assets/ui/talents/icons/ability_racial_bearform.png","background":"/assets/ui/talents/backgrounds/talent_druid2.png","description":"Fight in powerful animal forms.","system":"classic"},{"id":"druid-restoration","classId":"druid","name":"Restoration","icon":"/assets/ui/talents/icons/spell_nature_healingtouch.png","background":"/assets/ui/talents/backgrounds/talent_druid3.png","description":"Restore life through natural regeneration.","system":"classic"}],"nodes":[{"id":"talent-797","treeId":"druid-feral-combat","index":13,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":5,"icon":"/assets/ui/talents/icons/ability_druid_bash.png","maxRank":3,"name":"Brutal Impact","description":"Increases the stun duration of your Bash by 1 sec. Capstone Bonus: Bash or Feral Charge (Bear) deals the listed amount power*66/100} damage.","rankDescriptions":["Increases the stun duration of your Bash by 0.33 sec. Capstone Bonus: Bash and Feral Charge (Bear) deals the listed amount power*66/100} damage.","Increases the stun duration of your Bash by 0.66. Capstone Bonus: Bash and Feral Charge (Bear) deals the listed amount power*66/100} damage.","Increases the stun duration of your Bash by 1 sec. Capstone Bonus: Bash or Feral Charge (Bear) deals the listed amount power*66/100} damage."],"system":"classic"},{"id":"talent-799","treeId":"druid-feral-combat","index":3,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/ability_ambush.png","maxRank":3,"name":"Feral Instinct","description":"Increases Swipe and Ravage damage by 30%. Increases all damage dealt by 3% while Tiger's Fury is active. Reduces all damage taken by 3% while Enrage is active. Capstone Bonus: Dealing damage with Swipe and Ravage reduce the cooldown of Tiger's Fury and Enrage by 1 second.","rankDescriptions":["Increases Swipe and Ravage damage by 10%. Increases all damage dealt by 1% while Tiger's Fury is active. Reduces all damage taken by 1% while Enrage is active. Capstone Bonus: Dealing damage with Swipe and Ravage reduce the cooldown of Tiger's Fury and Enrage by 1 second.","Increases Swipe and Ravage damage by 20%. Increases all damage dealt by 2% while Tiger's Fury is active. Reduces all damage taken by 2% while Enrage is active. Capstone Bonus: Dealing damage with Swipe and Ravage reduce the cooldown of Tiger's Fury and Enrage by 1 second.","Increases Swipe and Ravage damage by 30%. Increases all damage dealt by 3% while Tiger's Fury is active. Reduces all damage taken by 3% while Enrage is active. Capstone Bonus: Dealing damage with Swipe and Ravage reduce the cooldown of Tiger's Fury and Enrage by 1 second."],"system":"classic"},{"id":"talent-802","treeId":"druid-feral-combat","index":9,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_shadow_vampiricaura.png","maxRank":3,"name":"Shredding Attacks","description":"Reduces the energy cost of your Shred and Ravage by 15. Capstone Bonus: Using Shred or Ravage while you are behind a target applies Shredded Defense to the enemy, increasing the Physical damage the target takes from you by 5% for 6 seconds, stacks up to 3 times.","rankDescriptions":["Reduces the energy cost of your Shred and Ravage by 5. Capstone Bonus: Using Shred or Ravage while you are behind a target applies Shredded Defense to the enemy, increasing the physical damage the target takes from you by 5% for 6 seconds, stacks up to 3 times.","Reduces the energy cost of your Shred and Ravage by 10. Capstone Bonus: Using Shred or Ravage while you are behind a target applies Shredded Defense to the enemy, increasing the Physical damage the target takes from you by 5% for 6 seconds, stacks up to 3 times.","Reduces the energy cost of your Shred and Ravage by 15. Capstone Bonus: Using Shred or Ravage while you are behind a target applies Shredded Defense to the enemy, increasing the Physical damage the target takes from you by 5% for 6 seconds, stacks up to 3 times."],"system":"classic"},{"id":"talent-807","treeId":"druid-feral-combat","index":6,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_nature_spiritwolf.png","maxRank":2,"name":"Feral Swiftness","description":"Increases your movement speed by 20% in Cat Form and by 10% in Bear Form. Reduces the cooldown of Survival Instincts by 50%.","rankDescriptions":["Increases your movement speed by 10% in Cat Form and by 5% in Bear Form. Reduces the cooldown of Survival Instincts by 25%.","Increases Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"felsworn","trees":[{"id":"coa-felsworn-37","classId":"felsworn","name":"Slayer","icon":"/assets/ui/spells/ability_creature_felsunder.png","background":"","description":"Slayer nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-felsworn-38","classId":"felsworn","name":"Infernal","icon":"/assets/ui/spells/inv_infernalmountgreen.png","background":"","description":"Infernal nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-felsworn-18","classId":"felsworn","name":"Tyrant","icon":"/assets/ui/spells/ability_demonhunter_infernalstrike2.png","background":"","description":"Tyrant nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-felsworn-87","classId":"felsworn","name":"Class","icon":"/assets/ui/spells/ability_boss_lordanthricystgreen.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31159","treeId":"coa-felsworn-18","index":31159,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/ability_demonhunter_infernalstrike2.png","maxRank":1,"name":"Carve","description":"Consumes 2 Felfury Charge up a powerful attack over 2.5 seconds. Upon ending the channel, slash in front of you, dealing increased Weapon Damage with both weapons based on how long you channel, dealing less damage with each target struck. Inner Demon: Reduces affected enemies melee and ranged haste by -20% for 8 seconds.","rankDescriptions":["Consumes 2 Felfury Charge up a powerful attack over 2.5 seconds. Upon ending the channel, slash in front of you, dealing increased Weapon Damage with both weapons based on how long you channel, dealing less damage with each target struck. Inner Demon: Reduces affected enemies melee and ranged haste by -20% for 8 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4009","treeId":"coa-felsworn-18","index":4009,"prerequisiteId":"coa-entry-30554","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30554","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/ability_demonhunter_demonictrample.png","maxRank":1,"name":"Burning Commander","description":"Level 10 Passive Allows you to wield a Two-Handed Axe, Mace, Polearm or Sword in each hand and grants you additional Armor and magic resistance based on your attack power.","rankDescriptions":["Level 10 Passive Allows you to wield a Two-Handed Axe, Mace, Polearm or Sword in each hand and grants you additional Armor and magic resistance based on your attack power."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-29845","treeId":"coa-felsworn-18","index":29845,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/ability_demonhunter_infernalchains.png","maxRank":1,"name":"Demonic Will","description":"Generates 1 Felfury Strengthen your will, reducing Physical damage taken by -30% for 10 seconds. While active, direct damaging abilities heal you for 3% of your maximum health. Can only occur once every 0.5 sec.","rankDescriptions":["Generates 1 Felfury Strengthen your will, reducing Physical damage taken by -30% for 10 seconds. While active, direct damaging abilities heal you for 3% of your maximum health. Can only occur once every 0.5 sec."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-11121","treeId":"coa-felsworn-18","index":11121,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/mannoroth.png","maxRank":1,"name":"Annihilan Rituals","description":"Fully channeling Carve now refunds 1 Felfury.","rankDescriptions":["Fully channeling Carve now refunds 1 Felfury."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30567","treeId":"coa-felsworn-18","index":30567,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/inv_polearm_2h_fellord.png","maxRank":1,"name":"Quick Carving","description":"Carve now channels 1 sec faster.","rankDescriptions":["Carve now channels 1 sec faster."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6338","treeId":"coa-felsworn-18","index":6338,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/inv_felhound4_custom.png","maxRank":2,"name":"Nether Disciple","dLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"guardian","trees":[{"id":"coa-guardian-7","classId":"guardian","name":"Vanguard","icon":"/assets/ui/spells/spell_paladin_hammerofwrath.png","background":"","description":"Vanguard nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-guardian-48","classId":"guardian","name":"Inspiration","icon":"/assets/ui/spells/ability_maldraxxus_warriorplantbanner.png","background":"","description":"Inspiration nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-guardian-49","classId":"guardian","name":"Gladiator","icon":"/assets/ui/spells/custom_warriorskill_02_border.png","background":"","description":"Gladiator nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-guardian-87","classId":"guardian","name":"Class","icon":"/assets/ui/spells/ability_ensnare.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31169","treeId":"coa-guardian-7","index":31169,"prerequisiteId":"coa-entry-4019","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4019","requiredRank":1},{"talentId":"coa-entry-30057","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/spell_paladin_hammerofwrath.png","maxRank":1,"name":"Heavy Blow","description":"Smash an enemy and enemies behind them in a line, dealing 23 + 37% AP High Threat Physical damage, scaling with your defense rating.","rankDescriptions":["Smash an enemy and enemies behind them in a line, dealing 23 + 37% AP High Threat Physical damage, scaling with your defense rating."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4019","treeId":"coa-guardian-7","index":4019,"prerequisiteId":"coa-entry-30057","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30057","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/_human_06.png","maxRank":1,"name":"Footman's Calling","description":"Level 10 Passive Your damage taken is reduced by -10% while Tower Formation or Line Formation is active. In addition, your threat generated from Physical Damage dealt is increased significantly while Tower Formation or Line Formation is active.","rankDescriptions":["Level 10 Passive Your damage taken is reduced by -10% while Tower Formation or Line Formation is active. In addition, your threat generated from Physical Damage dealt is increased significantly while Tower Formation or Line Formation is active."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":10,"isPassive":true},{"id":"coa-entry-30056","treeId":"coa-guardian-7","index":30056,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/garrison_building_armory.png","maxRank":3,"name":"Iron Guardian","description":"Increases your Stamina by 15% and critical strike chance by 6%.","rankDescriptions":["Increases your Stamina by 5% and critical strike chance by 2%.","Increases your Stamina by 10% and critical strike chance by 4%.","Increases your Stamina by 15% and critical strike chance by 6%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30802","treeId":"coa-guardian-7","index":30802,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/ability_warrior_vigilance.png","maxRank":1,"name":"Heavy Expert","description":"Increases your chance to parry and dodge by 4% and increase your Armor contribution from mail and plate items by 20%.","rankDescriptions":["Increases your chance to parry and dodge by 4% and increase your Armor contribution from mail and plate items by 20%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-31319","treeId":"coa-guardian-7","index":31319,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/inv_shoulder_plate_raidpaladin_s_01.png","maxRank":1,"name":"With Honor","description":"Reduces the cooldown of Ram by -4 sec and its critical strike chance by 25%.","rankDescriptions":["Reduces the cooldown of Ram by -4 sec and its critical strike chance by 25%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4718","treeId":"coa-guardian-7","index":4718,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":11,"row":3,"icon":"/assets/ui/spells/inv_shield_06.png","maxRank":1,"name":"Bulwark","description":"Level 20 Passive Increases your block value by 25% and your hit rating by 5% oLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"hunter","trees":[{"id":"hunter-beast-mastery","classId":"hunter","name":"Beast Mastery","icon":"/assets/ui/talents/icons/ability_hunter_beasttaming.png","background":"/assets/ui/talents/backgrounds/talent_hunter1.png","description":"Strengthen the bond between hunter and beast.","system":"classic"},{"id":"hunter-marksmanship","classId":"hunter","name":"Marksmanship","icon":"/assets/ui/talents/icons/ability_marksmanship.png","background":"/assets/ui/talents/backgrounds/talent_hunter2.png","description":"Perfect precise and devastating ranged attacks.","system":"classic"},{"id":"hunter-survival","classId":"hunter","name":"Survival","icon":"/assets/ui/talents/icons/ability_hunter_swiftstrike.png","background":"/assets/ui/talents/backgrounds/talent_hunter3.png","description":"Control the battlefield with traps and cunning.","system":"classic"}],"nodes":[{"id":"talent-1384","treeId":"hunter-beast-mastery","index":7,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/ability_mount_jungletiger.png","maxRank":2,"name":"Pathfinding","description":"Increases the speed bonus of your Aspect of the Cheetah and Aspect of the Pack by 10%. Increases your speed while mounted by 10%. The mounted movement speed increase does not stack with similar effects.","rankDescriptions":["Increases the speed bonus of your Aspect of the Cheetah and Aspect of the Pack by 5%. Increases your speed while mounted by 5%. The mounted movement speed increase does not stack with similar effects.","Increases the speed bonus of your Aspect of the Cheetah and Aspect of the Pack by 10%. Increases your speed while mounted by 10%. The mounted movement speed increase does not stack with similar effects."],"system":"classic"},{"id":"talent-1388","treeId":"hunter-beast-mastery","index":12,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":5,"icon":"/assets/ui/talents/icons/ability_druid_demoralizingroar.png","maxRank":2,"name":"Spirit Bond","description":"While your pet is active, you and your pet will regenerate 3% of base health every 10 sec. Increases healing done to you and your pet by 6%. This effect does not stack with other similar effects.","rankDescriptions":["While your pet is active, you and your pet will regenerate 3% of base health every 20 sec. Increases healing done to you and your pet by 3%. This effect does not stack with other similar effects.","While your pet is active, you and your pet will regenerate 3% of base health every 10 sec. Increases healing done to you and your pet by 6%. This effect does not stack with other similar effects."],"system":"classic"},{"id":"talent-1624","treeId":"hunter-beast-mastery","index":3,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/ability_hunter_silenthunter.png","maxRank":2,"name":"Focused Fire","description":"All damage caused by you and your pet is increased by 2% while your pet is active and the critical strike chance of your tamed beast's special abilities is increased by 20% while Kill Command is active.","rankDescriptions":["All damage caused by you and your pet is increased by 1% while your pet is active and the critical strike chance of your tamed beast's special abilities is increased by 10% while Kill Command is active.","All damage caused by you and your pet is increased by 2% while your pet is active and the critical strike chance of your tamed beast's special abilities is increased by 20% while Kill Command is active."],"system":"classic"},{"id":"talent-1799","treeId":"hunter-beast-mastery","index":15,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":6,"icon":"/assets/ui/talents/icons/ability_hunter_animalhandler.png","maxRank":2,"name":"Animal Handler","description":"Increases your tamed beast's attack power by 12% and increases the duration of your Master's Call effect by 6 sec.","rankDescriptions":["Increases your tamed beast's attack power by 6% and increases the duration of your Master's Call effect by 3 sec.","Increases your tamed beast's attack power by 12% and increases the duration of your Master's Call effect by 6 sec."],"system":"classic"},{"id":"talent-1800","treeId":"hunter-beast-mastery","index":17,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":7,"icon":"/assets/ui/talents/icons/ability_hunter_ferociousinspiration.png","maxRank":3,"name":"Ferocious Inspiration","description":"Increases the damage of all party and raid members by 3%. Does not stack with other similar effects. Increases the damage dealt by Arcane Shot and Steady Shot by 9%.","rankDescriptions":["Increases the damage of all party and raid members by 1%. Does not stack with other similar effects. Increases the damage dealt by Arcane Shot and Steady Shot by 3%.","Increases the damage of all party and raid members by 2%. Does not stack with other similar Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"knight-of-xoroth","trees":[{"id":"coa-knight-of-xoroth-46","classId":"knight-of-xoroth","name":"Hellfire","icon":"/assets/ui/spells/inv_firecatmount.png","background":"","description":"Hellfire nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-knight-of-xoroth-45","classId":"knight-of-xoroth","name":"War","icon":"/assets/ui/spells/inv_mace_2h_pvpcataclysms3_c_01.png","background":"","description":"War nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-knight-of-xoroth-47","classId":"knight-of-xoroth","name":"Defiance","icon":"/assets/ui/spells/inv_shield_draenorraid_d_02.png","background":"","description":"Defiance nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-knight-of-xoroth-87","classId":"knight-of-xoroth","name":"Class","icon":"/assets/ui/spells/_enslavespell_fire.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-12166","treeId":"coa-knight-of-xoroth-45","index":12166,"prerequisiteId":"coa-entry-4016","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4016","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/inv_mace_2h_pvpcataclysms3_c_01.png","maxRank":1,"name":"Warbringer","description":"Transforms your Flames of Xoroth into Warbringer.WarbringerSlam the ground, dealing 65% Weapon Damage plus 2 to nearby enemies, reducing the effectiveness of any healing by -50% for 10 seconds. Deals increased damage per Demonfire consumed.","rankDescriptions":["Transforms your Flames of Xoroth into Warbringer.WarbringerSlam the ground, dealing 65% Weapon Damage plus 2 to nearby enemies, reducing the effectiveness of any healing by -50% for 10 seconds. Deals increased damage per Demonfire consumed."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4016","treeId":"coa-knight-of-xoroth-45","index":4016,"prerequisiteId":"coa-entry-30668","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30668","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/warrior_skullbanner.png","maxRank":1,"name":"Crusher","description":"Level 10 Passive Doubles the base Weapon Damage dealt by Infernal Strike and increases all critical damage dealt by 25%.","rankDescriptions":["Level 10 Passive Doubles the base Weapon Damage dealt by Infernal Strike and increases all critical damage dealt by 25%."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":1,"isPassive":true},{"id":"coa-entry-31166","treeId":"coa-knight-of-xoroth-45","index":31166,"prerequisiteId":"coa-entry-4016","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4016","requiredRank":1},{"talentId":"coa-entry-30668","requiredRank":1}],"column":5,"row":2,"icon":"/assets/ui/spells/inv_sword_140.png","maxRank":1,"name":"Gore","description":"2 Charges, 8 sec recharge Generates 1 Demonfire Quickly gore an enemy, dealing 100% Weapon Damage plus 15.","rankDescriptions":["2 Charges, 8 sec recharge Generates 1 Demonfire Quickly gore an enemy, dealing 100% Weapon Damage plus 15."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-34127","treeId":"coa-knight-of-xoroth-45","index":34127,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/ability_skeer_bloodletting.png","maxRank":3,"name":"Mutilation","description":"Increases the damage of Gore and Sever by 30%.","rankDescriptions":["Increases the damage of Gore and Sever by 10%.","Increases the damage of Gore and Sever by 20%.","Increases the damage of Gore and Sever by 30%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6936","treeId":"coa-knight-of-xoroth-45","index":6936,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/sha_ability_warrior_bloodnova_nightmare.png","maxRank":1,"name":"Gored","description":"Damage dealt by Gore and Meatsaw now increases your target's damage taken from Skulltaker and Warbringer by 15% for 10 seconds, stacking 2 times.","rankDescriptions":["Damage dealt by Gore and Meatsaw now increases your target's damage taken from Skulltaker and Warbringer by 15% for 10 seconds, stacking 2 times."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-7881","treeId":"coa-knight-of-xoroth-45","index":7881,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spellLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"mage","trees":[{"id":"mage-arcane","classId":"mage","name":"Arcane","icon":"/assets/ui/talents/icons/spell_holy_magicalsentry.png","background":"/assets/ui/talents/backgrounds/talent_mage1.png","description":"Shape raw magical energy with precision.","system":"classic"},{"id":"mage-fire","classId":"mage","name":"Fire","icon":"/assets/ui/talents/icons/spell_fire_firebolt02.png","background":"/assets/ui/talents/backgrounds/talent_mage2.png","description":"Incinerate enemies with explosive flame.","system":"classic"},{"id":"mage-frost","classId":"mage","name":"Frost","icon":"/assets/ui/talents/icons/spell_frost_frostbolt02.png","background":"/assets/ui/talents/backgrounds/talent_mage3.png","description":"Slow, control, and shatter frozen enemies.","system":"classic"}],"nodes":[{"id":"talent-25","treeId":"mage-fire","index":11,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_fire_soulburn.png","maxRank":3,"name":"Improved Scorch","description":"Increases your chance to critically hit with Scorch, Fireball and Frostfire Bolt by an additional 3%. Your Scorch spell has a 100% chance to cause your target to be vulnerable to spell damage, increasing spell critical strike chance against that target by 5% and lasts 30 seconds. Does not stack with other similar effects.","rankDescriptions":["Increases your chance to critically hit with Scorch, Fireball and Frostfire Bolt by an additional 1%. Your Scorch spell has a 33% chance to cause your target to be vulnerable to spell damage, increasing spell critical strike chance against that target by 5% and lasts 30 seconds. Does not stack with other similar effects.","Increases your chance to critically hit with Scorch, Fireball and Frostfire Bolt by an additional 2%. Your Scorch spell has a 66% chance to cause your target to be vulnerable to spell damage, increasing spell critical strike chance against that target by 5% and lasts 30 seconds. Does not stack with other similar effects.","Increases your chance to critically hit with Scorch, Fireball and Frostfire Bolt by an additional 3%. Your Scorch spell has a 100% chance to cause your target to be vulnerable to spell damage, increasing spell critical strike chance against that target by 5% and lasts 30 seconds. Does not stack with other similar effects."],"system":"classic"},{"id":"talent-27","treeId":"mage-fire","index":1,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":1,"icon":"/assets/ui/talents/icons/spell_fire_fireball.png","maxRank":2,"name":"Improved Fire Blast","description":"Reduces the cooldown of your Fire Blast spell by 2 sec and increases the damage of your Fire Blast by 10% to monsters.","rankDescriptions":["Reduces the cooldown of your Fire Blast spell by 1 sec and increases the damage of your Fire Blast by 5% to monsters.","Reduces the cooldown of your Fire Blast spell by 2 sec and increases the damage of your Fire Blast by 10% to monsters."],"system":"classic"},{"id":"talent-28","treeId":"mage-fire","index":7,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_fire_flare.png","maxRank":3,"name":"Flame Throwing","description":"Increases the range of your damaging spells by 6 yards. This does not stack with other similar effects. Capstone Bonus: The cast time of your Fireball is reduced by 20%. This effect becomes inactive for 12 seconds after use.","rankDescriptions":["Increases the range of your damaging spells by 2 yards. This does not stack with other similar effects. Capstone Bonus: The cast time of your Fireball is reduced by 20%. This effect becomes inactive for 12 seconds after use.","Increases the range of your damaging spells by 4 yards. This does not stack with other similar effects. Capstone Bonus: The cast time of your Fireball is reduced by 20%. This effect becomes inactive for 12 seconds after use.","Increases the range of your damaging spells by 6 yards. This does not stack with other similar effects. Capstone Bonus: The cast time of your Fireball is reduced by 20%. This effect becomes inactive for 12 seconds after use."],"system":"classic"},{"id":"talent-34","treeId":"mage-fire","index":4,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/spell_fire_incinerate.png","maxRank":5,"name":"Ignite","description":"Your critical strikes from direct Fire damage spells and abilities cause the target to burn for an additional 30% of your spell's damage and cause them to take 40% less healing over 4 seconds. Does not stack with other similar effects.","rankDescriptions":["Your critical strikes from direct Fire damage spells and abilities cause the target to burn for an additional 6% of your spell's damage and cause them to take 8% less healing over 4 seconds. Does not stack with other similar effects.","Your critical strikes from direcLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"necromancer","trees":[{"id":"coa-necromancer-61","classId":"necromancer","name":"Animation","icon":"/assets/ui/spells/skeletalarcher.png","background":"","description":"Animation nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-necromancer-87","classId":"necromancer","name":"Class","icon":"/assets/ui/spells/ui_darkshore_warfront_horde_abomination.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-necromancer-59","classId":"necromancer","name":"Death","icon":"/assets/ui/spells/inv_pet_batpetmaldraxxus.png","background":"","description":"Death nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-necromancer-60","classId":"necromancer","name":"Rime","icon":"/assets/ui/spells/uico_frost_spell_09_border.png","background":"","description":"Rime nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-29866","treeId":"coa-necromancer-59","index":29866,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/inv_pet_batpetmaldraxxus.png","maxRank":1,"name":"Flesh to Worms","description":"Disease an enemy, dealing 15 + 11.06% shadow SP Plague damage and generating Runic Power every 3 sec for 18 seconds.","rankDescriptions":["Disease an enemy, dealing 15 + 11.06% shadow SP Plague damage and generating Runic Power every 3 sec for 18 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4034","treeId":"coa-necromancer-59","index":4034,"prerequisiteId":"coa-entry-29244","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29244","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/spell_shadow_plaguecloud.png","maxRank":1,"name":"Crypt Plague","description":"Level 10 Passive Damage dealt by Crypt Swarm now applies 1 stack of Crypt Plague and Lichfrost applies 2 stacks.Crypt Plague (Damage)Deals 2 + 6% SP Plague Damage every 2 sec for 10 seconds, stacking 10 times. Additional applications do not refresh duration.","rankDescriptions":["Level 10 Passive Damage dealt by Crypt Swarm now applies 1 stack of Crypt Plague and Lichfrost applies 2 stacks.Crypt Plague (Damage)Deals 2 + 6% SP Plague Damage every 2 sec for 10 seconds, stacking 10 times. Additional applications do not refresh duration."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":1,"isPassive":true},{"id":"coa-entry-11904","treeId":"coa-necromancer-59","index":11904,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":2,"icon":"/assets/ui/spells/spell_holy_turnundead.png","maxRank":1,"name":"Cycle of Death","description":"Increases your spell haste by 5%.","rankDescriptions":["Increases your spell haste by 5%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-33752","treeId":"coa-necromancer-59","index":33752,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":2,"icon":"/assets/ui/spells/spell_shadow_deathanddecay.png","maxRank":1,"name":"Master of Death","description":"Casting Command spells on an enemy now applies Crypt Plague.","rankDescriptions":["Casting Command spells on an enemy now applies Crypt Plague."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-7808","treeId":"coa-necromancer-59","index":7808,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":2,"row":3,"icon":"/assets/ui/spells/spell_shadow_raisedead.png","maxRank":1,"name":"Rotting Flesh","description":"Increases the damage of Flesh to Worms by 25% and allows its periodic damage to scale with your spell haste.","rankDescriptions":["Increases the damage of Flesh to Worms by 25% and allows its periodic damage to scale with your spell haste."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6904","treeId":"coa-necromancer-59","index":6904,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/spell_shadow_darksummoning.png","maxRank":1,"name":"Swarmer","description":"Increases the Runic Power generated by Crypt Swarm by 2 per tick.","rankDescriptions":["Increases the Runic Power generated by Crypt Swarm by 2 per tick."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6863","treeId":"coa-necromancer-59","index":6863,Line truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"paladin","trees":[{"id":"paladin-holy","classId":"paladin","name":"Holy","icon":"/assets/ui/talents/icons/spell_holy_holybolt.png","background":"/assets/ui/talents/backgrounds/talent_paladin1.png","description":"Channel the Light into powerful healing.","system":"classic"},{"id":"paladin-protection","classId":"paladin","name":"Protection","icon":"/assets/ui/talents/icons/spell_holy_devotionaura.png","background":"/assets/ui/talents/backgrounds/talent_paladin2.png","description":"Defend allies with shield and sacred magic.","system":"classic"},{"id":"paladin-retribution","classId":"paladin","name":"Retribution","icon":"/assets/ui/talents/icons/spell_holy_auraoflight.png","background":"/assets/ui/talents/backgrounds/talent_paladin3.png","description":"Judge enemies with holy weapon strikes.","system":"classic"}],"nodes":[{"id":"talent-1410","treeId":"paladin-retribution","index":13,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":5,"icon":"/assets/ui/talents/icons/inv_hammer_04.png","maxRank":3,"name":"Two-Handed Weapon Specialization","description":"Increases the physical damage you deal and your melee critical strike chance by 3% with two-handed melee weapons. Increases the critical strike chance of Seal of Command, Seal of Righteousness and Seal of Vengeance by 15% while a two-handed melee weapon is equipped.","rankDescriptions":["Increases the physical damage you deal and your melee critical strike chance by 1% with two-handed melee weapons. Increases the critical strike chance of Seal of Command, Seal of Righteousness and Seal of Vengeance by 5% while a two-handed melee weapon is equipped.","Increases the physical damage you deal and your melee critical strike chance by 2% with two-handed melee weapons. Increases the critical strike chance of Seal of Command, Seal of Righteousness and Seal of Vengeance by 10% while a two-handed melee weapon is equipped.","Increases the physical damage you deal and your melee critical strike chance by 3% with two-handed melee weapons. Increases the critical strike chance of Seal of Command, Seal of Righteousness and Seal of Vengeance by 15% while a two-handed melee weapon is equipped."],"system":"classic"},{"id":"talent-1631","treeId":"paladin-retribution","index":3,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/spell_holy_righteousfury.png","maxRank":3,"name":"Improved Judgements","description":"Reduces the cooldown of your Judgement spells by 3 sec. Capstone Bonus: Smite and Holy Fire can trigger your active seal for 10 seconds after using Judgement.","rankDescriptions":["Reduces the cooldown of your Judgement spells by 1 sec. Capstone Bonus: Smite and Holy Fire can trigger your active seal for 10 seconds after using Judgement.","Reduces the cooldown of your Judgement spells by 2 sec. Capstone Bonus: Smite and Holy Fire can trigger your active seal for 10 seconds after using Judgement.","Reduces the cooldown of your Judgement spells by 3 sec. Capstone Bonus: Smite and Holy Fire can trigger your active seal for 10 seconds after using Judgement."],"system":"classic"},{"id":"talent-1632","treeId":"paladin-retribution","index":10,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_holy_eyeforaneye.png","maxRank":3,"name":"Eye for an Eye","description":"All criticals against you cause 15% of the damage taken to the attacker as well. The damage caused by Eye for an Eye will not exceed 50% of your total health.","rankDescriptions":["All criticals against you cause 5% of the damage taken to the attacker as well. The damage caused by Eye for an Eye will not exceed 50% of your total health.","All criticals against you cause 10% of the damage taken to the attacker as well. The damage caused by Eye for an Eye will not exceed 50% of your total health.","All criticals against you cause 15% of the damage taken to the attacker as well. The damage caused by Eye for an Eye will not exceed 50% of your total health."],"system":"classic"},{"id":"talent-1633","treeId":"paladin-retribution","index":6,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_holy_vindication.png","maxRank":3,"name":"Vindication","description":"Gives your Holy spells and Paladin melee abilities a 65% chance to reduce the targets attack power by the listed amountthe listed amount (scaling with level). Does not stack with other similar effects. Capstone Bonus: Your attack power is increased whenever you deal Holy damage to a target afflicted by Vindication.","rankDescriptions":["Gives your Holy spells and Paladin melee abilities a 17% chance to reduce the targets attack power by the listed amountthe listed amount (scaling with level). Does not stack with other similar effects. Capstone Bonus: Your attack power is increased whenever you deal Holy daLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"priest","trees":[{"id":"priest-discipline","classId":"priest","name":"Discipline","icon":"/assets/ui/talents/icons/spell_holy_wordfortitude.png","background":"/assets/ui/talents/backgrounds/talent_priest1.png","description":"Prevent harm with shields and focused will.","system":"classic"},{"id":"priest-holy","classId":"priest","name":"Holy","icon":"/assets/ui/talents/icons/spell_holy_guardianspirit.png","background":"/assets/ui/talents/backgrounds/talent_priest2.png","description":"Restore allies with direct and group healing.","system":"classic"},{"id":"priest-shadow","classId":"priest","name":"Shadow","icon":"/assets/ui/talents/icons/spell_shadow_shadowwordpain.png","background":"/assets/ui/talents/backgrounds/talent_priest3.png","description":"Assault the minds of enemies with shadow magic.","system":"classic"}],"nodes":[{"id":"talent-347","treeId":"priest-discipline","index":7,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_nature_sleep.png","maxRank":3,"name":"Meditation","description":"Allows 25% of your mana regeneration to continue while casting. Capstone Bonus: Your spell critical strike rating is increased by 15% of your Spirit.","rankDescriptions":["Allows 8% of your mana regeneration to continue while casting. Capstone Bonus: Your spell critical strike rating is increased by 15% of your Spirit.","Allows 16% of your mana regeneration to continue while casting. Capstone Bonus: Your spell critical strike rating is increased by 15% of your Spirit.","Allows 25% of your mana regeneration to continue while casting. Capstone Bonus: Your spell critical strike rating is increased by 15% of your Spirit."],"system":"classic"},{"id":"talent-352","treeId":"priest-discipline","index":3,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/spell_nature_manaregentotem.png","maxRank":3,"name":"Copious Power","description":"After casting Power Word: Shield your next healing spell with a cast time is 15% more effective.","rankDescriptions":["After casting Power Word: Shield your next healing spell with a cast time is 5% more effective.","After casting Power Word: Shield your next healing spell with a cast time is 10% more effective.","After casting Power Word: Shield your next healing spell with a cast time is 15% more effective."],"system":"classic"},{"id":"talent-1769","treeId":"priest-discipline","index":10,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_holy_absolution.png","maxRank":3,"name":"Absolution","description":"Reduces the mana cost of your Dispel Magic, Cure Disease, Abolish Disease and Mass Dispel spells by 30%. Increases the range of Mass Dispel by 5 yards. Capstone Bonus: The cooldown of your Dispel Magic is reduced by 2 seconds. In addition, it can be used on enemies to remove 1 beneficial magic effect.","rankDescriptions":["Reduces the mana cost of your Dispel Magic, Cure Disease, Abolish Disease and Mass Dispel spells by 10%. Increases the range of Mass Dispel by 2 yards. Capstone Bonus: The cooldown of your Dispel Magic is reduced by 2 seconds. In addition, it can be used on enemies to remove 1 beneficial magic effect.","Reduces the mana cost of your Dispel Magic, Cure Disease, Abolish Disease and Mass Dispel spells by 20%. Increases the range of Mass Dispel by 4 yards. Capstone Bonus: The cooldown of your Dispel Magic is reduced by 2 seconds. In addition, it can be used on enemies to remove 1 beneficial magic effect.","Reduces the mana cost of your Dispel Magic, Cure Disease, Abolish Disease and Mass Dispel spells by 30%. Increases the range of Mass Dispel by 5 yards. Capstone Bonus: The cooldown of your Dispel Magic is reduced by 2 seconds. In addition, it can be used on enemies to remove 1 beneficial magic effect."],"system":"classic"},{"id":"talent-1771","treeId":"priest-discipline","index":16,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":6,"icon":"/assets/ui/talents/icons/spell_shadow_focusedpower.png","maxRank":2,"name":"Focused Power","description":"Increases all damage done by 2% and your Holy and Shadow healing done by 2%. The cast time of Mass dispel is reduced 0.6 sec.","rankDescriptions":["Increases all damage done by 1% and your Holy and Shadow healing done by 1%. The cast time of Mass dispel is reduced 0.3 sec.","Increases all damage done by 2% and your Holy and Shadow healing done by 2%. The cast time of Mass dispel is reduced 0.6 sec."],"system":"classic"},{"id":"talent-1858","treeId":"priest-discipline","index":18,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":7,"icon":"/assets/ui/talents/icons/spell_arcane_focusedpower.png","maxRank":3,"name":"Focused Will","description":"Increases your spell critical effect chance by 3%, Capstone Bonus: Gain the Focused Will effect wLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"primalist","trees":[{"id":"coa-primalist-84","classId":"primalist","name":"Life","icon":"/assets/ui/spells/inv_mace_1h_draenorraid_d_04green.png","background":"","description":"Life nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-primalist-83","classId":"primalist","name":"Geomancy","icon":"/assets/ui/spells/seismic_tremor.png","background":"","description":"Geomancy nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-primalist-82","classId":"primalist","name":"Primal","icon":"/assets/ui/spells/spell_beastmaster_rylak.png","background":"","description":"Primal nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-primalist-91","classId":"primalist","name":"Mountain King","icon":"/assets/ui/spells/spell_shaman_earthquake.png","background":"","description":"Mountain King nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-primalist-87","classId":"primalist","name":"Class","icon":"/assets/ui/spells/spell_nature_stoneclawtotem.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-29667","treeId":"coa-primalist-82","index":29667,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/spell_beastmaster_rylak.png","maxRank":1,"name":"Rylak's Bite","description":"2 Charges, 10 sec recharge You and your pet rush towards an enemy and strike them, dealing 120% Weapon Damage plus 8.","rankDescriptions":["2 Charges, 10 sec recharge You and your pet rush towards an enemy and strike them, dealing 120% Weapon Damage plus 8."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4058","treeId":"coa-primalist-82","index":4058,"prerequisiteId":"coa-entry-30254","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30254","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/ability_druid_ripandtear.png","maxRank":1,"name":"Spirit Beast Master","description":"Level 10 Passive You may now tame beasts in Azeroth to aid you as a companion.","rankDescriptions":["Level 10 Passive You may now tame beasts in Azeroth to aid you as a companion."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-7109","treeId":"coa-primalist-82","index":7109,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/druid_stagstatue01.png","maxRank":1,"name":"Fury of the Wild","description":"When you cast a Boon, you cast the same Boon on your pet at 50% effectiveness.","rankDescriptions":["When you cast a Boon, you cast the same Boon on your pet at 50% effectiveness."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29382","treeId":"coa-primalist-82","index":29382,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/ability_smash.png","maxRank":1,"name":"Totemic Smash","description":"Smash an enemy for 140% Weapon Damage plus 20. Deals an additional 10 + 35% AP damage to up to 5 enemies within 8 yds.","rankDescriptions":["Smash an enemy for 140% Weapon Damage plus 20. Deals an additional 10 + 35% AP damage to up to 5 enemies within 8 yds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6205","treeId":"coa-primalist-82","index":6205,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/ability_druid_freshwound.png","maxRank":1,"name":"Primal Shred","description":"Command your pet to shred up to 5 enemies within 8 yds, causing them to bleed, dealing 53 + 35% AP Physical damage over 21 seconds.","rankDescriptions":["Command your pet to shred up to 5 enemies within 8 yds, causing them to bleed, dealing 53 + 35% AP Physical damage over 21 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-9212","treeId":"coa-primalist-82","index":9212,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":11,"row":3,"icon":"/assets/ui/spells/spell_nature_naturesblessing.png","maxRank":1,"name":"Primal Weapons","description":"Level 20 Passive Teaches you Primal Weapons which when used will grant you a bonus based on whether you use one-handed weapons or two-handed weapons.Primal Weapon: Bestial MightWhile wielding a one-handed weapon, your Physical critical strikes enrage you and any active pet for 8 seconds, increasing the haste ofLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"pyromancer","trees":[{"id":"coa-pyromancer-63","classId":"pyromancer","name":"Draconic","icon":"/assets/ui/spells/nozdormuicon.png","background":"","description":"Draconic nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-pyromancer-19","classId":"pyromancer","name":"Flameweaving","icon":"/assets/ui/spells/inv_misc_phoenixegg.png","background":"","description":"Flameweaving nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-pyromancer-62","classId":"pyromancer","name":"Incineration","icon":"/assets/ui/spells/ability_mage_fierypayback.png","background":"","description":"Incineration nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-pyromancer-87","classId":"pyromancer","name":"Class","icon":"/assets/ui/spells/nhi_firehands_border.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-29189","treeId":"coa-pyromancer-19","index":29189,"prerequisiteId":"coa-entry-4038","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4038","requiredRank":1},{"talentId":"coa-entry-30206","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/inv_misc_phoenixegg.png","maxRank":1,"name":"Phoenix Egg","description":"Summon a Phoenix for 1 minute at the target location that heals nearby party members for 117 + 15% healing every 5 sec. You may only have 1 Phoenix active at a time.","rankDescriptions":["Summon a Phoenix for 1 minute at the target location that heals nearby party members for 117 + 15% healing every 5 sec. You may only have 1 Phoenix active at a time."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4038","treeId":"coa-pyromancer-19","index":4038,"prerequisiteId":"coa-entry-30206","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30206","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/custom_t_phoenix_border.png","maxRank":1,"name":"Spirit of the Phoenix","description":"Level 10 Passive Upon taking damage that would otherwise kill you, you are instead transformed into the Spirit of the Phoenix for 15 seconds. While transformed, your spells have no mana cost and your Spirit is increased by 100%. At the end of the duration, you will be reborn. Can only occur once every 10 min.","rankDescriptions":["Level 10 Passive Upon taking damage that would otherwise kill you, you are instead transformed into the Spirit of the Phoenix for 15 seconds. While transformed, your spells have no mana cost and your Spirit is increased by 100%. At the end of the duration, you will be reborn. Can only occur once every 10 min."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-29550","treeId":"coa-pyromancer-19","index":29550,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":4,"row":2,"icon":"/assets/ui/spells/novart_magicspell_(37)_border.png","maxRank":1,"name":"Phoenix Dive","description":"Command your Phoenix to swoop to the target ally and shield allies in their path with fire, absorbing 175 + 50% SP + 100% Spirit damage for 30 seconds, scaling with your Spirit.","rankDescriptions":["Command your Phoenix to swoop to the target ally and shield allies in their path with fire, absorbing 175 + 50% SP + 100% Spirit damage for 30 seconds, scaling with your Spirit."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-33919","treeId":"coa-pyromancer-19","index":33919,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":6,"row":2,"icon":"/assets/ui/spells/nhi_firebreath_(2)_border.png","maxRank":1,"name":"Cleansing Flames","description":"Generates 10 Heat Each Tick Spread cleansing flames on 5 allies and enemies in front of you, damaging or healing for 69 + 44.4% SP over 3 seconds.","rankDescriptions":["Generates 10 Heat Each Tick Spread cleansing flames on 5 allies and enemies in front of you, damaging or healing for 69 + 44.4% SP over 3 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30637","treeId":"coa-pyromancer-19","index":30637,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/ability_monk_breathoffire.png","maxRank":1,"name":"Soothing Flames","description":"Healing done by Kindle and Cinderheart now additionally heals the target for 30% of the healing done over 3 seconds.","rankDescriptions":["Healing done by Kindle and Cinderheart now additionally heals the target for 30% of the healing done over 3 seconds."],"system":"coa","entryTyLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"ranger","trees":[{"id":"coa-ranger-55","classId":"ranger","name":"Brigand","icon":"/assets/ui/spells/ability_hunter_mongoosebite.png","background":"","description":"Brigand nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-ranger-87","classId":"ranger","name":"Class","icon":"/assets/ui/spells/custom_dismounting_shot.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-ranger-2","classId":"ranger","name":"Farstrider","icon":"/assets/ui/spells/ability_felarakkoa_focusedblast.png","background":"","description":"Farstrider nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-ranger-54","classId":"ranger","name":"Archery","icon":"/assets/ui/spells/5_archerskill07_border.png","background":"","description":"Archery nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31133","treeId":"coa-ranger-2","index":31133,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/ability_felarakkoa_focusedblast.png","maxRank":1,"name":"Falconstrike","description":"Every 5th Quick Shot within 15 seconds transforms into Falconstrike. Using a Horn instantly transforms Quick Shot into Falconstrike.Falconstrike (Transform)Generates 2 Advantage Call a cast of falcons to strike an enemy, dealing 121% Ranged Weapon Damage plus 10 Nature damage and calling 1 War Falcon to your aid for 6 seconds.","rankDescriptions":["Every 5th Quick Shot within 15 seconds transforms into Falconstrike. Using a Horn instantly transforms Quick Shot into Falconstrike.Falconstrike (Transform)Generates 2 Advantage Call a cast of falcons to strike an enemy, dealing 121% Ranged Weapon Damage plus 10 Nature damage and calling 1 War Falcon to your aid for 6 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":10,"isPassive":false},{"id":"coa-entry-4030","treeId":"coa-ranger-2","index":4030,"prerequisiteId":"coa-entry-30352","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-30352","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/inv_legion_faction_dreamweavers.png","maxRank":1,"name":"Dream Flowers","description":"Level 10 Passive Your damaging critical strikes now spawn a green Dream Flower at a random location within 15 yds of you. Dream Flower (Spawner)When an ally runs over the flower, they consume it to heal for 3% maximum health and gain 40% increased movement speed for 5 seconds.Can only occur once per sec.","rankDescriptions":["Level 10 Passive Your damaging critical strikes now spawn a green Dream Flower at a random location within 15 yds of you. Dream Flower (Spawner)When an ally runs over the flower, they consume it to heal for 3% maximum health and gain 40% increased movement speed for 5 seconds.Can only occur once per sec."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-30926","treeId":"coa-ranger-2","index":30926,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":2,"icon":"/assets/ui/spells/misc_legionfall_hunter.png","maxRank":2,"name":"Cunning","description":"Increases your Focus regeneration by 30%.","rankDescriptions":["Increases your Focus regeneration by 15%.","Increases your Focus regeneration by 30%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-7050","treeId":"coa-ranger-2","index":7050,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":2,"icon":"/assets/ui/spells/inv_ascend_horn_b_01.png","maxRank":2,"name":"Blow the Horns!","description":"Reduces the cooldown of Horn spells by -50%.","rankDescriptions":["Reduces the cooldown of Horn spells by -25%.","Reduces the cooldown of Horn spells by -50%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-34181","treeId":"coa-ranger-2","index":34181,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":2,"row":3,"icon":"/assets/ui/spells/ability_skyreach_castdown.png","maxRank":1,"name":"Falcon's Call","description":"Call down war falcons upon a targeted area, slowing up to 8 enemies within the area by -60% for 5 seconds. A Falcon is summoned for each enemy affected for 12 seconds.","rankDescriptions":["Call down war falcons upon a targeted area, slowing up to 8 enemies within the area by -60% for 5 seconds. A Falcon is summoned for each enemy affected for 12 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPasLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"reaper","trees":[{"id":"coa-reaper-79","classId":"reaper","name":"Harvest","icon":"/assets/ui/spells/inv_knife_1h_revendrethquest_b_03.png","background":"","description":"Harvest nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-reaper-80","classId":"reaper","name":"Soul","icon":"/assets/ui/spells/nhi_spiritstab_border.png","background":"","description":"Soul nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-reaper-81","classId":"reaper","name":"Domination","icon":"/assets/ui/spells/ability_argus_edgeofobliteration.png","background":"","description":"Domination nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-reaper-87","classId":"reaper","name":"Class","icon":"/assets/ui/spells/inv_archaeology_orcclans_tattooknife.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-29378","treeId":"coa-reaper-79","index":29378,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/inv_knife_1h_revendrethquest_b_03.png","maxRank":1,"name":"Doomrend","description":"Rend an enemy dealing 140% Weapon Damage plus 17 + 35% AP, causing you to apply a dark shield to them that absorbs the next 75 + 100% Strength healing done to them for 5 seconds, and generates Runic Power.","rankDescriptions":["Rend an enemy dealing 140% Weapon Damage plus 17 + 35% AP, causing you to apply a dark shield to them that absorbs the next 75 + 100% Strength healing done to them for 5 seconds, and generates Runic Power."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4055","treeId":"coa-reaper-79","index":4055,"prerequisiteId":"coa-entry-29248","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29248","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/ability_revendreth_deathknight.png","maxRank":1,"name":"Harvester","description":"Level 10 Passive You now heal yourself equal to 15% of all damage dealt.","rankDescriptions":["Level 10 Passive You now heal yourself equal to 15% of all damage dealt."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-29246","treeId":"coa-reaper-79","index":29246,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":2,"icon":"/assets/ui/spells/inv_helmet_plate_deathknight_m_01.png","maxRank":2,"name":"Maw Knight","description":"Increases the critical strike chance of Doomrend by 10%.","rankDescriptions":["Increases the critical strike chance of Doomrend by 5%.","Increases the critical strike chance of Doomrend by 10%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-9270","treeId":"coa-reaper-79","index":9270,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":2,"icon":"/assets/ui/spells/inv_harvestgolempet.png","maxRank":1,"name":"Bountiful Harvest","description":"Increases the damage of Reap and Murder by 25%.","rankDescriptions":["Increases the damage of Reap and Murder by 25%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-34480","treeId":"coa-reaper-79","index":34480,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":2,"row":3,"icon":"/assets/ui/spells/inv_polearm_2h_warfrontshorde_c_01red.png","maxRank":1,"name":"Crow's Harvest","description":"Strike all nearby enemies for 65% Weapon Damage plus 6. Damage dealt harvests a Soul Fragment, up to a maximum of 3.","rankDescriptions":["Strike all nearby enemies for 65% Weapon Damage plus 6. Damage dealt harvests a Soul Fragment, up to a maximum of 3."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-31371","treeId":"coa-reaper-79","index":31371,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/ability_revendreth_warrior.png","maxRank":1,"name":"Slaughter","description":"Generates 1 Reaped Soul Eradicate an enemy with your scythe, dealing 130% Weapon Damage plus 14. Only usable on enemies below 35% health.","rankDescriptions":["Generates 1 Reaped Soul Eradicate an enemy with your scythe, dealing 130% Weapon Damage plus 14. Only usable on enemies below 35% health."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-5767","treeId":"coa-reaperLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"rogue","trees":[{"id":"rogue-assassination","classId":"rogue","name":"Assassination","icon":"/assets/ui/talents/icons/ability_rogue_eviscerate.png","background":"/assets/ui/talents/backgrounds/talent_rogue1.png","description":"Use poisons and finishers to dispatch targets.","system":"classic"},{"id":"rogue-combat","classId":"rogue","name":"Combat","icon":"/assets/ui/talents/icons/ability_backstab.png","background":"/assets/ui/talents/backgrounds/talent_rogue2.png","description":"Excel in sustained weapon combat.","system":"classic"},{"id":"rogue-subtlety","classId":"rogue","name":"Subtlety","icon":"/assets/ui/talents/icons/ability_stealth.png","background":"/assets/ui/talents/backgrounds/talent_rogue3.png","description":"Strike from stealth and manipulate the shadows.","system":"classic"}],"nodes":[{"id":"talent-184","treeId":"rogue-combat","index":14,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":5,"icon":"/assets/ui/talents/icons/inv_mace_01.png","maxRank":5,"name":"Mace Specialization","description":"Increases your melee attack speed by 10% and armor penetration by 15% while a mace is equipped.","rankDescriptions":["Increases your melee attack speed by 2% and armor penetration by 3% while a mace is equipped.","Increases your melee attack speed by 4% and armor penetration by 6% while a mace is equipped.","Increases your melee attack speed by 6% and armor penetration by 9% while a mace is equipped.","Increases your melee attack speed by 8% and armor penetration by 12% while a mace is equipped.","Increases your melee attack speed by 10% and armor penetration by 15% while a mace is equipped."],"system":"classic"},{"id":"talent-203","treeId":"rogue-combat","index":1,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":1,"icon":"/assets/ui/talents/icons/ability_gouge.png","maxRank":2,"name":"Improved Gouge","description":"Increases the duration of your Gouge ability by 1 sec.","rankDescriptions":["Increases the effect duration of your Gouge ability by 0.5 sec.","Increases the duration of your Gouge ability by 1 sec."],"system":"classic"},{"id":"talent-204","treeId":"rogue-combat","index":7,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_shadow_shadowward.png","maxRank":2,"name":"Endurance","description":"Reduces the cooldown of your Evasion ability by 60 sec. Increases your total Stamina by 4%. You take 20% less Magic damage while Evasion is active.","rankDescriptions":["Reduces the cooldown of your Evasion ability by 30 sec. Increases your total Stamina by 2%. You take 10% less Magic damage while Evasion is active.","Reduces the cooldown of your Evasion ability by 60 sec. Increases your total Stamina by 4%. You take 20% less Magic damage while Evasion is active."],"system":"classic"},{"id":"talent-206","treeId":"rogue-combat","index":10,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/ability_kick.png","maxRank":2,"name":"Improved Kick","description":"Your Kick has a 100% chance of preventing your target from moving faster than their normal movement speed for 3 seconds. Capstone Bonus: Your successful interrupts with Kick grants you 40 energy and 35% attack speed for 6 sec.","rankDescriptions":["Your Kick has a 50% chance of preventing your target from moving faster than their normal movement speed for 3 seconds. Capstone Bonus: Your successful interrupts with Kick grants you 40 energy and 35% attack speed for 6 sec.","Your Kick has a 100% chance of preventing your target from moving faster than their normal movement speed for 3 seconds. Capstone Bonus: Your successful interrupts with Kick grants you 40 energy and 35% attack speed for 6 sec."],"system":"classic"},{"id":"talent-1705","treeId":"rogue-combat","index":19,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":7,"icon":"/assets/ui/talents/icons/ability_warrior_revenge.png","maxRank":3,"name":"Vitality","description":"Increases your Energy regeneration rate by 40%.","rankDescriptions":["Increases your Energy regeneration rate by 13%.","Increases your Energy regeneration rate by 26%.","Increases your Energy regeneration rate by 40%."],"system":"classic"},{"id":"talent-1827","treeId":"rogue-combat","index":4,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/ability_rogue_slicedice.png","maxRank":2,"name":"Improved Slice and Dice","description":"Increases the duration of your Slice and Dice ability by 50% and increases the attack speed it grants by 6%.","rankDescriptions":["Increases the duration of your Slice and Dice ability by 25% and increases the attack speed it grants by 3%.","Increases the duration of your Slice and Dice ability by 50% and increases the attack speed it grants by 6%."],"system":"classic"},{"id":"talent-2Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"runemaster","trees":[{"id":"coa-runemaster-85","classId":"runemaster","name":"Runic","icon":"/assets/ui/spells/5_mageskill14_border.png","background":"","description":"Runic nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-runemaster-11","classId":"runemaster","name":"Arcane","icon":"/assets/ui/spells/achievement_raidprimalist_council.png","background":"","description":"Arcane nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-runemaster-86","classId":"runemaster","name":"Riftblade","icon":"/assets/ui/spells/uico_fire_spell_02_border.png","background":"","description":"Riftblade nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-runemaster-87","classId":"runemaster","name":"Class","icon":"/assets/ui/spells/custom_t_nhance_rpg_icons_magickeeper_border.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-66733","treeId":"coa-runemaster-11","index":66733,"prerequisiteId":"coa-entry-4061","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4061","requiredRank":1},{"talentId":"coa-entry-31102","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/achievement_raidprimalist_council.png","maxRank":1,"name":"Glyphic Ruin","description":"Unleash your active Glyph effect on an enemy and deal 82 + 100% SP Elemental Damage.","rankDescriptions":["Unleash your active Glyph effect on an enemy and deal 82 + 100% SP Elemental Damage."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4061","treeId":"coa-runemaster-11","index":4061,"prerequisiteId":"coa-entry-31102","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-31102","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/70_inscription_vantus_rune_azure.png","maxRank":1,"name":"Frost Glyph","description":"Level 10 Passive Using Elemental Burst and Primordial Blast now grants you Frost Glyph. Frost GlyphUnleash: Deals 437 Frost Damage and slows movement speed by -30% for 4 seconds.","rankDescriptions":["Level 10 Passive Using Elemental Burst and Primordial Blast now grants you Frost Glyph. Frost GlyphUnleash: Deals 437 Frost Damage and slows movement speed by -30% for 4 seconds."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":10,"isPassive":true},{"id":"coa-entry-34664","treeId":"coa-runemaster-11","index":34664,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/70_inscription_vantus_rune_nightmare.png","maxRank":1,"name":"Flame Glyph","description":"Using Elemental Burst or Primordial Blast while Frost Glyph is active now grants you a Flame Glyph.Flame GlyphUnleash: Deals 250 + 65% fire SP Fire Damage and an additional 750 + 30% SP Fire Damage over 6 seconds.","rankDescriptions":["Using Elemental Burst or Primordial Blast while Frost Glyph is active now grants you a Flame Glyph.Flame GlyphUnleash: Deals 250 + 65% fire SP Fire Damage and an additional 750 + 30% SP Fire Damage over 6 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30208","treeId":"coa-runemaster-11","index":30208,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/spell_arcane_blast.png","maxRank":2,"name":"Focusing Crystals","description":"Increases your Magic Damage dealt by 6% and allows 60% of your mana regeneration to continue while in combat.","rankDescriptions":["Increases your Magic Damage dealt by 3% and allows 30% of your mana regeneration to continue while in combat.","Increases your Magic Damage dealt by 6% and allows 60% of your mana regeneration to continue while in combat."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-7834","treeId":"coa-runemaster-11","index":7834,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/70_inscription_vantus_rune_suramar.png","maxRank":1,"name":"Arcane Glyph","description":"Using Elemental Burst or Primordial Blast while Flame Glyph is active now grants you Arcane Glyph.Arcane GlyphUnleash: Deals 276 + 18% arcane SP Arcane Damage to up to 0 enemies near the primary target.","rankDescriptions":["Using Elemental Burst or Primordial Blast while Flame Glyph is active now grants you Arcane Glyph.Arcane GlyphUnleash: Deals 276 + 18% arcane SP Arcane Damage to up to 0 enemies near the primary target."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":Line truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"shaman","trees":[{"id":"shaman-elemental","classId":"shaman","name":"Elemental","icon":"/assets/ui/talents/icons/spell_nature_lightning.png","background":"/assets/ui/talents/backgrounds/talent_shaman1.png","description":"Call lightning, fire, and earth against enemies.","system":"classic"},{"id":"shaman-enhancement","classId":"shaman","name":"Enhancement","icon":"/assets/ui/talents/icons/spell_nature_lightningshield.png","background":"/assets/ui/talents/backgrounds/talent_shaman2.png","description":"Empower weapons through elemental spirits.","system":"classic"},{"id":"shaman-restoration","classId":"shaman","name":"Restoration","icon":"/assets/ui/talents/icons/spell_nature_magicimmunity.png","background":"/assets/ui/talents/backgrounds/talent_shaman3.png","description":"Mend allies with water and ancestral magic.","system":"classic"}],"nodes":[{"id":"talent-561","treeId":"shaman-elemental","index":3,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/spell_fire_immolation.png","maxRank":3,"name":"Call of Flame","description":"Increases the damage, and reduces the mana cost of your Fire Totems and Fire Nova by 30%. Increases the damage done by your Lava Burst spell by 15%.","rankDescriptions":["Increases the damage done and reduces the mana cost of your Fire Totems and Fire Nova by 10%. Increases the damage done by your Lava Burst spell by 5%.","Increases the damage, and reduces the mana cost of your Fire Totems and Fire Nova by 20%. Increases the damage done by your Lava Burst spell by 10%.","Increases the damage, and reduces the mana cost of your Fire Totems and Fire Nova by 30%. Increases the damage done by your Lava Burst spell by 15%."],"system":"classic"},{"id":"talent-567","treeId":"shaman-elemental","index":9,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_fire_sealoffire.png","maxRank":2,"name":"Rising Flames","description":"Increases the cast speed of your Searing Totem by 30% and the critical strike damage bonus of your Searing and Magma totems by 100%. In addition, reduces the cooldown of Fire Nova by 4 sec. Capstone Bonus: Casting Magma Totem now gives you a stack of Rising Flames every 2 seconds. @s:983971:0@","rankDescriptions":["Increases the cast speed of your Searing Totem by 15% and the critical strike damage bonus of your Searing and Magma totems by 50%. Reduces the cooldown of Fire Nova by 2 sec. Capstone Bonus: Casting Magma Totem now gives you a stack of Rising Flames every 2 seconds. @s:983971:0@","Increases the cast speed of your Searing Totem by 30% and the critical strike damage bonus of your Searing and Magma totems by 100%. In addition, reduces the cooldown of Fire Nova by 4 sec. Capstone Bonus: Casting Magma Totem now gives you a stack of Rising Flames every 2 seconds. @s:983971:0@"],"system":"classic"},{"id":"talent-575","treeId":"shaman-elemental","index":6,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_frost_frostward.png","maxRank":3,"name":"Reverberation","description":"Reduces the cooldown of your Shaman Shocks by 1.5 sec. When you deal damage with a Shaman Shock spell you have a 100% to increase the direct damage of your next different Shaman Shock or Elemental Blast spell within 8 sec by 20%.","rankDescriptions":["Reduces the cooldown of your Shaman Shocks by 0.5 sec. When you deal damage with a Shaman Shock spell you have a 33% to increase the direct damage of your next different Shaman Shock or Elemental Blast spell within 8 sec by 20%.","Reduces the cooldown of your Shaman Shocks by 1 sec. When you deal damage with a Shaman Shock spell you have a 66% to increase the direct damage of your next different Shaman Shock or Elemental Blast spell within 8 sec by 20%.","Reduces the cooldown of your Shaman Shocks by 1.5 sec. When you deal damage with a Shaman Shock spell you have a 100% to increase the direct damage of your next different Shaman Shock or Elemental Blast spell within 8 sec by 20%."],"system":"classic"},{"id":"talent-1641","treeId":"shaman-elemental","index":11,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":5,"icon":"/assets/ui/talents/icons/spell_nature_stormreach.png","maxRank":3,"name":"Elemental Reach","description":"Increases the range of your damaging spells by 6 yards. This does not stack with other similar effects. Capstone Bonus: Your direct damage Fire, Nature and Frost spells on targets further than 20 yards away from you have a 33% chance to increase your magic damage by 6% for 10 seconds. This effect can only occur once every 15 seconds.","rankDescriptions":["Increases the range of your damaging spells by 2 yards. This does not stack with other similar effects. Capstone Bonus: Your direct damage Fire, Nature and Frost spells on targets further than 20 yards away from you hLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"starcaller","trees":[{"id":"coa-starcaller-67","classId":"starcaller","name":"Moon Guard","icon":"/assets/ui/spells/ability_argus_soulburst.png","background":"","description":"Moon Guard nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-starcaller-69","classId":"starcaller","name":"Sentinel","icon":"/assets/ui/spells/_arcaneshot_lightblue.png","background":"","description":"Sentinel nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-starcaller-68","classId":"starcaller","name":"Moon Priest","icon":"/assets/ui/spells/achievement_leader_tyrande_whisperwind.png","background":"","description":"Moon Priest nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-starcaller-89","classId":"starcaller","name":"Warden","icon":"/assets/ui/spells/_fanofknives_lightblue.png","background":"","description":"Warden nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-starcaller-87","classId":"starcaller","name":"Class","icon":"/assets/ui/spells/spell_nature_moonglow.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-29896","treeId":"coa-starcaller-67","index":29896,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/ability_argus_soulburst.png","maxRank":1,"name":"Starburst","description":"Applies 1 Scattered Star Per Hit Smash up to 8 enemies, dealing 2 + 30% arcane SP + 15% AP Arcane damage, scaling with block value and maximum mana and reducing their attack speed by -20% for 10 seconds. Consuming a Scattered Star reduces the remaining cooldown of Starburst by -2 sec.","rankDescriptions":["Applies 1 Scattered Star Per Hit Smash up to 8 enemies, dealing 2 + 30% arcane SP + 15% AP Arcane damage, scaling with block value and maximum mana and reducing their attack speed by -20% for 10 seconds. Consuming a Scattered Star reduces the remaining cooldown of Starburst by -2 sec."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4043","treeId":"coa-starcaller-67","index":4043,"prerequisiteId":"coa-entry-29642","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29642","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/artifactability_balancedruid_newmoon.png","maxRank":1,"name":"Moon Guard","description":"Level 10 Passive You now gain Intellect equal to your Strength.","rankDescriptions":["Level 10 Passive You now gain Intellect equal to your Strength."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-29656","treeId":"coa-starcaller-67","index":29656,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":4,"row":2,"icon":"/assets/ui/spells/inv_cosmicvoid_orb.png","maxRank":1,"name":"Blanket of Stars","description":"Cover your shield in a blanket of stars for 8 seconds, increasing your block chance and block value by 100%.","rankDescriptions":["Cover your shield in a blanket of stars for 8 seconds, increasing your block chance and block value by 100%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30665","treeId":"coa-starcaller-67","index":30665,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":6,"row":2,"icon":"/assets/ui/spells/inv_sword_1h_warfrontsnightelf_d_01.png","maxRank":1,"name":"Starsweep","description":"Consumes Scattered Stars Sweep an enemy and all nearby enemies with your astral blade, dealing 30 + 30% AP + 35% SP Arcane damage. Every Scattered Star consumed reduces the cooldown of this spell by -3 sec.Consume Scattered StarsDeals 7 + 18.22% SP Arcane Damage and restores 8% maximum mana for each Scattered Star.","rankDescriptions":["Consumes Scattered Stars Sweep an enemy and all nearby enemies with your astral blade, dealing 30 + 30% AP + 35% SP Arcane damage. Every Scattered Star consumed reduces the cooldown of this spell by -3 sec.Consume Scattered StarsDeals 7 + 18.22% SP Arcane Damage and restores 8% maximum mana for each Scattered Star."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29651","treeId":"coa-starcaller-67","index":29651,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/spell_arcane_arcane01.png","maxRank":1,"name":"Improved Eclipse of Fury","description":"Increases the effectiveness of Eclipse of Fury by 40%.","rankDescriptions":["Increases the effectiveness of Eclipse of Fury by 40%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"stormbringer","trees":[{"id":"coa-stormbringer-42","classId":"stormbringer","name":"Lightning","icon":"/assets/ui/spells/epic_rpg_icon_pack_wind_icon_0002s_0000_lightning_border.png","background":"","description":"Lightning nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-stormbringer-43","classId":"stormbringer","name":"Wind","icon":"/assets/ui/spells/spell_nature_tranquility.png","background":"","description":"Wind nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-stormbringer-44","classId":"stormbringer","name":"Maelstrom","icon":"/assets/ui/spells/_liquidstone_water.png","background":"","description":"Maelstrom nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-stormbringer-87","classId":"stormbringer","name":"Class","icon":"/assets/ui/spells/inv_misc_volatileair.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31163","treeId":"coa-stormbringer-42","index":31163,"prerequisiteId":"coa-entry-4013","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4013","requiredRank":1},{"talentId":"coa-entry-29138","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/epic_rpg_icon_pack_wind_icon_0002s_0000_lightning_border.png","maxRank":1,"name":"Arm of Thorim","description":"Depletes All Static Call down a terrible beam of lightning upon an enemy, dealing 135 + 120% nature SP Nature damage and stunning them for 1 seconds. Damage and cast time increased based on Static level.","rankDescriptions":["Depletes All Static Call down a terrible beam of lightning upon an enemy, dealing 135 + 120% nature SP Nature damage and stunning them for 1 seconds. Damage and cast time increased based on Static level."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4013","treeId":"coa-stormbringer-42","index":4013,"prerequisiteId":"coa-entry-29138","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29138","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/nhi_frozenlightning_border.png","maxRank":1,"name":"Electrocutioner","description":"Level 10 Passive Dealing spell damage now has a 5% chance to grant you Electrocutioner.Electrocutioner (Proc)Resets the cooldown of Electrocute and makes your next usable regardless of the target's health percentage. Chance increases based on Static level.","rankDescriptions":["Level 10 Passive Dealing spell damage now has a 5% chance to grant you Electrocutioner.Electrocutioner (Proc)Resets the cooldown of Electrocute and makes your next usable regardless of the target's health percentage. Chance increases based on Static level."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":1,"isPassive":true},{"id":"coa-entry-29837","treeId":"coa-stormbringer-42","index":29837,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/ability_siege_engineer_magnetic_crush.png","maxRank":1,"name":"Superconductor","description":"Increases the damage of your Arm of Thorim by an additional 1% per Static depleted.","rankDescriptions":["Increases the damage of your Arm of Thorim by an additional 1% per Static depleted."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29833","treeId":"coa-stormbringer-42","index":29833,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/spell_nature_lightningoverload.png","maxRank":1,"name":"Forked Lightning","description":"Shoot lightning at an enemy, dealing 69 + 49% SP Nature damage, bouncing to up to 4 enemies. Generates 5 Static for each enemy struck.","rankDescriptions":["Shoot lightning at an enemy, dealing 69 + 49% SP Nature damage, bouncing to up to 4 enemies. Generates 5 Static for each enemy struck."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29290","treeId":"coa-stormbringer-42","index":29290,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/shaman_pvp_staticcling.png","maxRank":1,"name":"Volt","description":"Fuse lightning into an enemy, dealing 150 + 114% nature SP Nature damage over 18 seconds and slowing them by -40%. Generates 2 Static per tick.","rankDescriptions":["Fuse lightning into an enemy, dealing 150 + 114% nature SP Nature damage over 18 seconds and slowing them by -40%. Generates 2 Static per tick."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":Line truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"sun-cleric","trees":[{"id":"coa-sun-cleric-72","classId":"sun-cleric","name":"Seraphim","icon":"/assets/ui/spells/nhi_energyshield_border.png","background":"","description":"Seraphim nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-sun-cleric-70","classId":"sun-cleric","name":"Piety","icon":"/assets/ui/spells/nhi_fire_solar_border.png","background":"","description":"Piety nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-sun-cleric-90","classId":"sun-cleric","name":"Valkyrie","icon":"/assets/ui/spells/inv_sword_2h_armyoflight_c_01.png","background":"","description":"Valkyrie nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-sun-cleric-71","classId":"sun-cleric","name":"Blessings","icon":"/assets/ui/spells/ability_priest_ascendance.png","background":"","description":"Blessings nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-sun-cleric-87","classId":"sun-cleric","name":"Class","icon":"/assets/ui/spells/paladin_holy.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31194","treeId":"coa-sun-cleric-70","index":31194,"prerequisiteId":"coa-entry-4046","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4046","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/nhi_fire_solar_border.png","maxRank":1,"name":"Dawnsear","description":"Blast an enemy with burning light, dealing 88 + 100% fire SP Fire damage.","rankDescriptions":["Blast an enemy with burning light, dealing 88 + 100% fire SP Fire damage."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4046","treeId":"coa-sun-cleric-70","index":4046,"prerequisiteId":"coa-entry-29510","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29510","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/custom_t_nhance_rpg_icons_holymeditation_border.png","maxRank":1,"name":"Sunrise and Sunset","description":"Level 10 Passive After activating Dawn, casting a Holy spell grants Sunrise or casting a Fire spell grants Sunset. Entering Sunrise or Sunset prevents you from entering the other until you enter the next. SunriseIncreases all Holy Damage dealt by 20% for 2 minutes. SunsetIncreases your critical strike chance with Fire spells by 20% and Fire Damage by 10% for 2 minutes.","rankDescriptions":["Level 10 Passive After activating Dawn, casting a Holy spell grants Sunrise or casting a Fire spell grants Sunset. Entering Sunrise or Sunset prevents you from entering the other until you enter the next. SunriseIncreases all Holy Damage dealt by 20% for 2 minutes. SunsetIncreases your critical strike chance with Fire spells by 20% and Fire Damage by 10% for 2 minutes."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-30957","treeId":"coa-sun-cleric-70","index":30957,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/nhi_holysparks_border.png","maxRank":1,"name":"Radiant Flame","description":"Launch radiant spheres at an enemy each dealing 31 + 20.69% SP Holyflame Damage, repeating every 1 sec for 4 seconds.","rankDescriptions":["Launch radiant spheres at an enemy each dealing 31 + 20.69% SP Holyflame Damage, repeating every 1 sec for 4 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-34050","treeId":"coa-sun-cleric-70","index":34050,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/inv_shield_1h_artifactstormfist_d_03.png","maxRank":1,"name":"Scorch Marks","description":"Casting Dawnsear and Sunflare now have a 40% chance to grant Scorch Marks for 10 seconds.Scorch MarksYour next Radiant Flame has no mana cost, ticks -50% faster, and its duration is reduced by -50%.","rankDescriptions":["Casting Dawnsear and Sunflare now have a 40% chance to grant Scorch Marks for 10 seconds.Scorch MarksYour next Radiant Flame has no mana cost, ticks -50% faster, and its duration is reduced by -50%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30311","treeId":"coa-sun-cleric-70","index":30311,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/custom_t_fireinourhands_border.png","maxRank":1,"name":"Solar Conduit","description":"Reduces the cast time of Dawnsear by -20% while Dawn is active.","rankDescriptions":["Reduces the cast time of Dawnsear by -20% while Dawn is active."],"system":"coa","entryType":"TLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"templar","trees":[{"id":"coa-templar-50","classId":"templar","name":"Zealot","icon":"/assets/ui/spells/nhi_holystrike_border.png","background":"","description":"Zealot nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-templar-16","classId":"templar","name":"Oathkeeper","icon":"/assets/ui/spells/5_staffstrike_border.png","background":"","description":"Oathkeeper nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-templar-51","classId":"templar","name":"Crusader","icon":"/assets/ui/spells/_whirlwind_yellow.png","background":"","description":"Crusader nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-templar-87","classId":"templar","name":"Class","icon":"/assets/ui/spells/nhi_holymeditation_border.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31173","treeId":"coa-templar-16","index":31173,"prerequisiteId":"coa-entry-4023","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4023","requiredRank":1},{"talentId":"coa-entry-34402","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/5_staffstrike_border.png","maxRank":1,"name":"Sacred Swing","description":"Swing at enemies in front of you, dealing 125% High Threat Weapon Damage plus 9, slowing their attack and movement speed by -20% for 10 seconds. Only usable after avoiding an attack.","rankDescriptions":["Swing at enemies in front of you, dealing 125% High Threat Weapon Damage plus 9, slowing their attack and movement speed by -20% for 10 seconds. Only usable after avoiding an attack."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4023","treeId":"coa-templar-16","index":4023,"prerequisiteId":"coa-entry-34402","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-34402","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/inv_staff_2h_nazmirraid_d_01.png","maxRank":1,"name":"Keeping the Oath","description":"Level 10 Passive You now delay 40% of direct damage taken, instead taking it over 8 seconds. In addition, you no longer consume your Oaths with Oath Breakers.","rankDescriptions":["Level 10 Passive You now delay 40% of direct damage taken, instead taking it over 8 seconds. In addition, you no longer consume your Oaths with Oath Breakers."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":1,"isPassive":true},{"id":"coa-entry-34395","treeId":"coa-templar-16","index":34395,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":2,"icon":"/assets/ui/spells/spell_holy_powerwordshield.png","maxRank":2,"name":"Blessed Padding","description":"Increases your Armor contribution from mail items by 100% and reduces damage taken from area of effect attacks by -20%.","rankDescriptions":["Increases your Armor contribution from mail items by 50% and reduces damage taken from area of effect attacks by -10%.","Increases your Armor contribution from mail items by 100% and reduces damage taken from area of effect attacks by -20%."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29717","treeId":"coa-templar-16","index":29717,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":2,"icon":"/assets/ui/spells/inv_staff_05.png","maxRank":1,"name":"Staffguard","description":"Casting Sacred Swing now grants you Staffguard, absorbing 125 + 30% Stamina damage, scaling with Stamina, parry and dodge rating, for 8 seconds.","rankDescriptions":["Casting Sacred Swing now grants you Staffguard, absorbing 125 + 30% Stamina damage, scaling with Stamina, parry and dodge rating, for 8 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-30437","treeId":"coa-templar-16","index":30437,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":2,"row":3,"icon":"/assets/ui/spells/spell_holy_surgeoflight.png","maxRank":1,"name":"Paragon","description":"Increases your Stamina by 10, plus an additional amount equal to 10% of your Agility.","rankDescriptions":["Increases your Stamina by 10, plus an additional amount equal to 10% of your Agility."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6376","treeId":"coa-templar-16","index":6376,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/custom_t_nhance_rpg_icons_holyrod_border.png","maxRank":1,"name":"Reckoning","description":"UnLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"tinker","trees":[{"id":"coa-tinker-87","classId":"tinker","name":"Class","icon":"/assets/ui/spells/inv_gizmo_rocketbootextreme.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-tinker-75","classId":"tinker","name":"Mechanics","icon":"/assets/ui/spells/custom_engineerskill_49_border.png","background":"","description":"Mechanics nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-tinker-74","classId":"tinker","name":"Invention","icon":"/assets/ui/spells/spell_mekkatorque_bot_greenspring.png","background":"","description":"Invention nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-tinker-73","classId":"tinker","name":"Demolition","icon":"/assets/ui/spells/5_bomb_border.png","background":"","description":"Demolition nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-6828","treeId":"coa-tinker-73","index":6828,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":1,"icon":"/assets/ui/spells/5_bomb_border.png","maxRank":1,"name":"Bomb Toss","description":"Lob a bomb at an enemy, dealing 36 + 30% ranged AP + 50% fire SP Fire damage and reducing their armor by -5% for 15 seconds, stacking 4 times.","rankDescriptions":["Lob a bomb at an enemy, dealing 36 + 30% ranged AP + 50% fire SP Fire damage and reducing their armor by -5% for 15 seconds, stacking 4 times."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4049","treeId":"coa-tinker-73","index":4049,"prerequisiteId":"coa-entry-31113","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-31113","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/inv_eng_bombfire.png","maxRank":1,"name":"Napalm","description":"Level 10 Passive Dealing direct Fire damage now applies Napalm to your target.Napalm (Damage)Fire Damage taken by you is increased and healing received reduced by -3% for 8 seconds. Stacks 10 times.","rankDescriptions":["Level 10 Passive Dealing direct Fire damage now applies Napalm to your target.Napalm (Damage)Fire Damage taken by you is increased and healing received reduced by -3% for 8 seconds. Stacks 10 times."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-29613","treeId":"coa-tinker-73","index":29613,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/ability_racial_rocketbarrage.png","maxRank":1,"name":"Rocket Launcher","description":"Fire a powerful rocket at an enemy that deals 126 + 35% ranged AP + 35% fire SP Fire damage.","rankDescriptions":["Fire a powerful rocket at an enemy that deals 126 + 35% ranged AP + 35% fire SP Fire damage."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-7001","treeId":"coa-tinker-73","index":7001,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/ability_siege_engineer_detonate.png","maxRank":1,"name":"Build: Spider Bomb","description":"Build a Spider Bomb that will immediately run towards your target and detonate dealing 250 + 30% ranged AP Fire damage in an 8 yd radius. Using Scrap Shot will redirect the Spider Bombs to your new target.","rankDescriptions":["Build a Spider Bomb that will immediately run towards your target and detonate dealing 250 + 30% ranged AP Fire damage in an 8 yd radius. Using Scrap Shot will redirect the Spider Bombs to your new target."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-34996","treeId":"coa-tinker-73","index":34996,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":3,"icon":"/assets/ui/spells/nhi_holybullet_border.png","maxRank":2,"name":"Incendiary Bullets","description":"Increases the damage of Scrap Shot by 30% and increases your chance to hit by 4%.","rankDescriptions":["Increases the damage of Scrap Shot by 15% and increases your chance to hit by 2%.","Increases the damage of Scrap Shot by 30% and increases your chance to hit by 4%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-9621","treeId":"coa-tinker-73","index":9621,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":11,"row":3,"icon":"/assets/ui/spells/nhi_tech_rocket_border.png","maxRank":1,"name":"Sparked and Ready!","description":"Level 20 Passive Fire damage dealt has a 5% chance to grant you Sparked andLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"venomancer","trees":[{"id":"coa-venomancer-92","classId":"venomancer","name":"Vizier","icon":"/assets/ui/spells/nhi_natureburn_border.png","background":"","description":"Vizier nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-venomancer-76","classId":"venomancer","name":"Venom","icon":"/assets/ui/spells/custom_t_nhance_rpg_icons_naturewrath_border.png","background":"","description":"Venom nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-venomancer-77","classId":"venomancer","name":"Stalking","icon":"/assets/ui/spells/inv_spidermountc5.png","background":"","description":"Stalking nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-venomancer-78","classId":"venomancer","name":"Fortitude","icon":"/assets/ui/spells/achievment_boss_wellofeternity.png","background":"","description":"Fortitude nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-venomancer-87","classId":"venomancer","name":"Class","icon":"/assets/ui/spells/inv_pet_shalespider.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-30477","treeId":"coa-venomancer-76","index":30477,"prerequisiteId":"coa-entry-4052","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4052","requiredRank":1},{"talentId":"coa-entry-29607","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/custom_t_nhance_rpg_icons_naturewrath_border.png","maxRank":1,"name":"Wilt","description":"Wilt the life of an enemy with vile poison, dealing 144 Nature damage over 18 seconds.","rankDescriptions":["Wilt the life of an enemy with vile poison, dealing 144 Nature damage over 18 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4052","treeId":"coa-venomancer-76","index":4052,"prerequisiteId":"coa-entry-29607","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29607","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/_instableaffliction_green.png","maxRank":1,"name":"Rot Lich","description":"Level 10 Passive Direct damage dealt now has a 20% chance to reset the cooldown of Serpent's Fang and grant you Rot Lich and allies Replenishment.Rot Lich (Proc)Your next Serpent's Fang within 15 seconds is free of cost.ReplenishmentReplenishes 5% of maximum mana per 5 sec for 15 seconds.","rankDescriptions":["Level 10 Passive Direct damage dealt now has a 20% chance to reset the cooldown of Serpent's Fang and grant you Rot Lich and allies Replenishment.Rot Lich (Proc)Your next Serpent's Fang within 15 seconds is free of cost.ReplenishmentReplenishes 5% of maximum mana per 5 sec for 15 seconds."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-30606","treeId":"coa-venomancer-76","index":30606,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":2,"icon":"/assets/ui/spells/nhi_unholy_mushroom_border.png","maxRank":1,"name":"Spore","description":"Inject an enemy with parasitic spores, dealing 20 + 17.5% nature SP Shadow damage, plus an additional 231 over 21 seconds. After 10 sec, drop a Mushroom below the target that explodes after 2 sec, dealing 303 + 25% nature SP Nature damage to nearby enemies.","rankDescriptions":["Inject an enemy with parasitic spores, dealing 20 + 17.5% nature SP Shadow damage, plus an additional 231 over 21 seconds. After 10 sec, drop a Mushroom below the target that explodes after 2 sec, dealing 303 + 25% nature SP Nature damage to nearby enemies."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-7219","treeId":"coa-venomancer-76","index":7219,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/custom_t_nhance_rpg_icons_natureportal_border.png","maxRank":2,"name":"Protraction","description":"Increases the duration of your Venomancer periodic damage effects by 6 sec.","rankDescriptions":["Increases the duration of your Venomancer periodic damage effects by 3 sec.","Increases the duration of your Venomancer periodic damage effects by 6 sec."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-6137","treeId":"coa-venomancer-76","index":6137,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/inv_misc_starspecklemushroom.png","maxRank":1,"name":"Fungal Growth","description":"Shadow and Nature damage dealt now has a 35% chance to increase periodic damage you deal to the target by 2% for 30 seconds, stacking 10 times.","rankDescriLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"warlock","trees":[{"id":"warlock-affliction","classId":"warlock","name":"Affliction","icon":"/assets/ui/talents/icons/spell_shadow_deathcoil.png","background":"/assets/ui/talents/backgrounds/talent_warlock1.png","description":"Erode enemies with curses and lasting agony.","system":"classic"},{"id":"warlock-demonology","classId":"warlock","name":"Demonology","icon":"/assets/ui/talents/icons/spell_shadow_metamorphosis.png","background":"/assets/ui/talents/backgrounds/talent_warlock2.png","description":"Draw greater power from demonic allies.","system":"classic"},{"id":"warlock-destruction","classId":"warlock","name":"Destruction","icon":"/assets/ui/talents/icons/spell_shadow_rainoffire.png","background":"/assets/ui/talents/backgrounds/talent_warlock3.png","description":"Burn enemies with chaotic fire and shadow.","system":"classic"}],"nodes":[{"id":"talent-982","treeId":"warlock-destruction","index":3,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/spell_fire_fire.png","maxRank":2,"name":"Aftermath","description":"Increases the periodic damage done by your Immolate by 6%. Your Conflagrate has a 100% chance to daze the target reducing movement speed by 50% for 4 seconds.","rankDescriptions":["Increases the periodic damage done by your Immolate by 3%. Your Conflagrate has a 50% chance to daze the target reducing movement speed by 50% for 4 seconds.","Increases the periodic damage done by your Immolate by 6%. Your Conflagrate has a 100% chance to daze the target reducing movement speed by 50% for 4 seconds."],"system":"classic"},{"id":"talent-983","treeId":"warlock-destruction","index":6,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/spell_fire_firebolt.png","maxRank":2,"name":"Demonic Power","description":"Reduces the cooldown of your Succubus' Lash of Pain spell by 6 sec. Reduces the cast time of your Imp's Firebolt and the Firebolt of your Wild Imps by 0.25 sec, and increases their damage by 14%.","rankDescriptions":["Reduces the cooldown of your Succubus' Lash of Pain spell by 3 sec. Reduces the cast time of your Imp's Firebolt and the Firebolt of your Wild Imps by 0.25 sec, and increases their damage by 7%.","Reduces the cooldown of your Succubus' Lash of Pain spell by 6 sec. Reduces the cast time of your Imp's Firebolt and the Firebolt of your Wild Imps by 0.25 sec, and increases their damage by 14%."],"system":"classic"},{"id":"talent-985","treeId":"warlock-destruction","index":9,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":4,"icon":"/assets/ui/talents/icons/spell_fire_lavaspawn.png","maxRank":3,"name":"Intensity","description":"Increases all damage done by 3%. Reduces spell pushback suffered from damaging attacks by 100%.","rankDescriptions":["Increases all damage done by 1%. Reduces spell pushback suffered from damaging attacks by 33%.","Increases all damage done by 2%. Reduces spell pushback suffered from damaging attacks by 66%.","Increases all damage done by 3%. Reduces spell pushback suffered from damaging attacks by 100%."],"system":"classic"},{"id":"talent-1679","treeId":"warlock-destruction","index":15,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":6,"icon":"/assets/ui/talents/icons/spell_shadow_netherprotection.png","maxRank":3,"name":"Nether Protection","description":"Reduces periodic spell damage taken by 6%. Capstone Bonus: Gives you a 20% chance when being hit with a spell or taking periodic spell damage to gain Nether Protection, reducing all damage by that spell school by 10% for 6 seconds. This effect can only occur every 4 seconds.","rankDescriptions":["Reduces periodic spell damage taken by 2%. Capstone Bonus: Gives you a 20% chance when being hit with a spell or taking periodic spell damage to gain Nether Protection, reducing all damage by that spell school by 10% for 6 seconds. This effect can only occur every 4 seconds.","Reduces periodic spell damage taken by 4%. Capstone Bonus: Gives you a 20% chance when being hit with a spell or taking periodic spell damage to gain Nether Protection, reducing all damage by that spell school by 10% for 6 seconds. This effect can only occur every 4 seconds.","Reduces periodic spell damage taken by 6%. Capstone Bonus: Gives you a 20% chance when being hit with a spell or taking periodic spell damage to gain Nether Protection, reducing all damage by that spell school by 10% for 6 seconds. This effect can only occur every 4 seconds."],"system":"classic"},{"id":"talent-1817","treeId":"warlock-destruction","index":12,"prerequisiteId":"talent-985","prerequisiteRank":2,"prerequisites":[{"talentId":"talent-985","requiredRank":2}],"column":1,"row":5,"icon":"/assets/ui/talents/icons/spell_fire_playingwithfire.png","maxRank":3,"name":"Backlash","description":"Increases your critical strike chance with all spells and abiliLine truncated
+1
View File
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"warrior","trees":[{"id":"warrior-arms","classId":"warrior","name":"Arms","icon":"/assets/ui/talents/icons/ability_rogue_eviscerate.png","background":"/assets/ui/talents/backgrounds/talent_warrior1.png","description":"Master weapons and decisive physical attacks.","system":"classic"},{"id":"warrior-fury","classId":"warrior","name":"Fury","icon":"/assets/ui/talents/icons/ability_warrior_innerrage.png","background":"/assets/ui/talents/backgrounds/talent_warrior2.png","description":"Overwhelm enemies with relentless aggression.","system":"classic"},{"id":"warrior-protection","classId":"warrior","name":"Protection","icon":"/assets/ui/talents/icons/inv_shield_06.png","background":"/assets/ui/talents/backgrounds/talent_warrior3.png","description":"Endure punishment and protect the party.","system":"classic"}],"nodes":[{"id":"talent-124","treeId":"warrior-arms","index":1,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":1,"icon":"/assets/ui/talents/icons/ability_rogue_ambush.png","maxRank":3,"name":"Improved Heroic Strike","description":"Increases the damage of your Heroic Strike by 9% and reduces the rage cost by 6.","rankDescriptions":["Increases the damage of your Heroic Strike by 3% and reduces the rage cost by 2.","Increases the damage of your Heroic Strike by 6% and reduces the rage cost by 4.","Increases the damage of your Heroic Strike by 9% and reduces the rage cost by 6."],"system":"classic"},{"id":"talent-126","treeId":"warrior-arms","index":4,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":2,"icon":"/assets/ui/talents/icons/ability_warrior_charge.png","maxRank":3,"name":"Improved Charge","description":"Increases the duration of your Charge root by 1 sec. Capstone Bonus: The range of your Charge is increased by 5 yards.","rankDescriptions":["Increases the duration of your Charge root by 0.33 sec. Capstone Bonus: The range of your Charge is increased by 5 yards.","Increases the duration of your Charge root by 0.66 sec. Capstone Bonus: The range of your Charge is increased by 5 yards.","Increases the duration of your Charge root by 1 sec. Capstone Bonus: The range of your Charge is increased by 5 yards."],"system":"classic"},{"id":"talent-131","treeId":"warrior-arms","index":7,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":3,"icon":"/assets/ui/talents/icons/inv_sword_05.png","maxRank":2,"name":"Improved Overpower","description":"Increases the critical strike chance of your Overpower ability by 50%.","rankDescriptions":["Increases the critical strike chance of your Overpower ability by 25%.","Increases the critical strike chance of your Overpower ability by 50%."],"system":"classic"},{"id":"talent-132","treeId":"warrior-arms","index":13,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":5,"icon":"/assets/ui/talents/icons/inv_axe_06.png","maxRank":5,"name":"Poleaxe Specialization","description":"Increases your chance to get a critical strike and the Physical critical damage caused with Axes and Polearms by 5%.","rankDescriptions":["Increases your chance to get a critical strike and the Physical critical damage caused with Axes and Polearms by 1%.","Increases your chance to get a critical strike and the Physical critical damage caused with Axes and Polearms by 2%.","Increases your chance to get a critical strike and the Physical critical damage caused with Axes and Polearms by 3%.","Increases your chance to get a critical strike and the Physical critical damage caused with Axes and Polearms by 4%.","Increases your chance to get a critical strike and the Physical critical damage caused with Axes and Polearms by 5%."],"system":"classic"},{"id":"talent-134","treeId":"warrior-arms","index":17,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":1,"row":6,"icon":"/assets/ui/talents/icons/ability_warrior_weaponmastery.png","maxRank":2,"name":"Weapon Mastery","description":"Whenever one of your attacks is dodged or blocked you have a 50% chance to gain 2% critical strike chance for 8 seconds, stacks up to 3 times. Reduces the duration of all Disarm effects used against you by 30%. This does not stack with other Disarm duration reducing effects.","rankDescriptions":["Whenever one of your attacks is dodged or blocked you have a 50% chance to gain 2% critical strike chance for 8 seconds, stacks up to 3 times. Reduces the duration of all Disarm effects used against you by 15%. This does not stack with other Disarm duration reducing effects.","Whenever one of your attacks is dodged or blocked you have a 50% chance to gain 2% critical strike chance for 8 seconds, stacks up to 3 times. Reduces the duration of all Disarm effects used against you by 30%. This does not stack with other Disarm duration reducing effects."],"system":"classic"},{"id":"talent-1662","treeId":"warrior-arms","index":27,"prerequisiteId":null,"prerequisiteRank":null,"prerLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"witch-doctor","trees":[{"id":"coa-witch-doctor-36","classId":"witch-doctor","name":"Shadowhunting","icon":"/assets/ui/spells/nhi_naturearrow_(2)_border.png","background":"","description":"Shadowhunting nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-doctor-34","classId":"witch-doctor","name":"Voodoo","icon":"/assets/ui/spells/custom_45_voodoo_border.png","background":"","description":"Voodoo nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-doctor-35","classId":"witch-doctor","name":"Brewing","icon":"/assets/ui/spells/inv_mushroom_07.png","background":"","description":"Brewing nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-doctor-87","classId":"witch-doctor","name":"Class","icon":"/assets/ui/spells/nhi_naturehide_border.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31154","treeId":"coa-witch-doctor-34","index":31154,"prerequisiteId":"coa-entry-4004","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4004","requiredRank":1},{"talentId":"coa-entry-29301","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/custom_45_voodoo_border.png","maxRank":1,"name":"Shadow Puppets","description":"Summon a Shadow Puppet that collects a Spirit and rushes towards your target, dealing 25 + 22% shadow SP Shadow damage, repeating every 1 sec for 3 seconds.","rankDescriptions":["Summon a Shadow Puppet that collects a Spirit and rushes towards your target, dealing 25 + 22% shadow SP Shadow damage, repeating every 1 sec for 3 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4004","treeId":"coa-witch-doctor-34","index":4004,"prerequisiteId":"coa-entry-29301","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29301","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/trade_archaeology_troll_voodoodoll.png","maxRank":1,"name":"Puppeteer's Threads","description":"Level 10 Passive Damaging abilities now leave behind Puppeteer's Threads on enemies for 10 seconds. Puppeteer’s Threads (Debuff)Damage taken from the Witch Doctor stores 15% of its value. When the effect ends the damage stored is dealt instantly.","rankDescriptions":["Level 10 Passive Damaging abilities now leave behind Puppeteer's Threads on enemies for 10 seconds. Puppeteer’s Threads (Debuff)Damage taken from the Witch Doctor stores 15% of its value. When the effect ends the damage stored is dealt instantly."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-31345","treeId":"coa-witch-doctor-34","index":31345,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":4,"row":2,"icon":"/assets/ui/spells/nhi_spiritualrage_border.png","maxRank":2,"name":"Loa Spirits","description":"Damage dealt and healing done now has a 15% chance to collect a Spirit. In addition, each active Spirit now increases your Spirit by 4%.SpiritRegenerates 7 health and mana, repeating every 4 sec for 12 seconds, stacking 5 times.","rankDescriptions":["Damage dealt and healing done now has a 8% chance to collect a Spirit. In addition, each active Spirit now increases your Spirit by 2%.SpiritRegenerates 7 health and mana, repeating every 4 sec for 12 seconds, stacking 5 times.","Damage dealt and healing done now has a 15% chance to collect a Spirit. In addition, each active Spirit now increases your Spirit by 4%.SpiritRegenerates 7 health and mana, repeating every 4 sec for 12 seconds, stacking 5 times."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-31344","treeId":"coa-witch-doctor-34","index":31344,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":6,"row":2,"icon":"/assets/ui/spells/achievement_zone_tanaanjungle.png","maxRank":1,"name":"Stranglethorn Style","description":"Increases your critical strike chance by 4% and reduces threat generated by your Voodoo spells by -20%.","rankDescriptions":["Increases your critical strike chance by 4% and reduces threat generated by your Voodoo spells by -20%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29928","treeId":"coa-witch-doctor-34","index":29928,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":3,"icon":"/assets/ui/spells/skill_icon_skill5_border.png","maxRank":1,"name":"Bad Juju","description":"Hurl a bolt of dark magic at an enemy, dealing 191 + 100% SP + 30% Spirit Shadow damage. If the target is affected by Hex of Malice it also redLine truncated
@@ -0,0 +1 @@
{"schemaVersion":1,"classId":"witch-hunter","trees":[{"id":"coa-witch-hunter-39","classId":"witch-hunter","name":"Boltslinger","icon":"/assets/ui/spells/_d3rapidfire.png","background":"","description":"Boltslinger nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-hunter-40","classId":"witch-hunter","name":"Houndmaster","icon":"/assets/ui/spells/unleashthehounds.png","background":"","description":"Houndmaster nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-hunter-41","classId":"witch-hunter","name":"Inquisition","icon":"/assets/ui/spells/5_run_border.png","background":"","description":"Inquisition nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-hunter-94","classId":"witch-hunter","name":"Black Knight","icon":"/assets/ui/spells/nhi_brokensword_border.png","background":"","description":"Black Knight nodes synchronized from Vol'Jin.","system":"coa"},{"id":"coa-witch-hunter-87","classId":"witch-hunter","name":"Class","icon":"/assets/ui/spells/ability_demonhunter_vengefulretreat2.png","background":"","description":"Class nodes synchronized from Vol'Jin.","system":"coa"}],"nodes":[{"id":"coa-entry-31160","treeId":"coa-witch-hunter-39","index":31160,"prerequisiteId":"coa-entry-4010","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-4010","requiredRank":1},{"talentId":"coa-entry-29150","requiredRank":1}],"column":5,"row":1,"icon":"/assets/ui/spells/_d3rapidfire.png","maxRank":1,"name":"Witchbane","description":"Unleash a series of devastating shots dealing 60 + 45% ranged AP Physical damage over 3 seconds.","rankDescriptions":["Unleash a series of devastating shots dealing 60 + 45% ranged AP Physical damage over 3 seconds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-4010","treeId":"coa-witch-hunter-39","index":4010,"prerequisiteId":"coa-entry-29150","prerequisiteRank":1,"prerequisites":[{"talentId":"coa-entry-29150","requiredRank":1}],"column":11,"row":1,"icon":"/assets/ui/spells/inv_weapon_crossbow_21.png","maxRank":1,"name":"Boltslinger","description":"Level 10 Passive You may now cast Darkslayer while moving. Ranged attacks and abilities now have a 25% chance to shoot an additional shot, dealing 20% ranged AP Physical damage and generating 5 Rage.","rankDescriptions":["Level 10 Passive You may now cast Darkslayer while moving. Ranged attacks and abilities now have a 25% chance to shoot an additional shot, dealing 20% ranged AP Physical damage and generating 5 Rage."],"system":"coa","entryType":"Ability","abilityEssenceCost":0,"talentEssenceCost":0,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":true},{"id":"coa-entry-5076","treeId":"coa-witch-hunter-39","index":5076,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":3,"row":2,"icon":"/assets/ui/spells/ability_hunter_blindingshot.png","maxRank":1,"name":"Mechanized Crossbows","description":"Increases your ranged attack power by 10% and the range of your ranged abilities by 5 yds.","rankDescriptions":["Increases your ranged attack power by 10% and the range of your ranged abilities by 5 yds."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-34570","treeId":"coa-witch-hunter-39","index":34570,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":7,"row":2,"icon":"/assets/ui/spells/inv_weapon_crossbow_32.png","maxRank":2,"name":"My Trusty Arbalest","description":"Reduces the Rage cost of Witchbane and Shadowblast by -20% and increases your chance to hit by 4%.","rankDescriptions":["Reduces the Rage cost of Witchbane and Shadowblast by -10% and increases your chance to hit by 2%.","Reduces the Rage cost of Witchbane and Shadowblast by -20% and increases your chance to hit by 4%."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPoints":0,"requiredLevel":0,"isPassive":false},{"id":"coa-entry-29372","treeId":"coa-witch-hunter-39","index":29372,"prerequisiteId":null,"prerequisiteRank":null,"prerequisites":[],"column":5,"row":3,"icon":"/assets/ui/spells/nhi_shadowarrow_border.png","maxRank":1,"name":"Heartseeking Bolt","description":"Charge up a powerful bolt that deals 200% Ranged Weapon Damage plus 40 + 50% ranged AP + 30% shadow SP to an enemy and reduces their healing received by -30% for 10 seconds. Generates Rage based on the damage dealt.","rankDescriptions":["Charge up a powerful bolt that deals 200% Ranged Weapon Damage plus 40 + 50% ranged AP + 30% shadow SP to an enemy and reduces their healing received by -30% for 10 seconds. Generates Rage based on the damage dealt."],"system":"coa","entryType":"Talent","abilityEssenceCost":0,"talentEssenceCost":1,"requiredClassPoints":0,"requiredSpecPLine truncated
+2 -4
View File
@@ -4,6 +4,7 @@ import {
abilityById,
isAbilityUnlocked,
resourceProfileForClass,
triggeredAbilityBySpellId,
type AbilityDefinition,
type AbilityEffect,
type ResourceType,
@@ -51,8 +52,6 @@ import {
} from "./partyAbilityAi";
import { normalizeActorResourcePool } from "./combatActors";
import { advanceCombatResourcePool } from "./combatResources";
import { romTriggeredAbilityBySpellId } from "./romAbilityCatalog";
import { coaTriggeredAbilityBySpellId } from "./coaAbilityRuntimeCatalog";
import {
combatHasLineOfSight,
combatSpatialActor,
@@ -1010,8 +1009,7 @@ function executePartyAbility(
};
} else if (effect.kind === "trigger-spell" && depth < 2) {
const triggered = abilitiesForClass(member.classId).find((candidate) => candidate.dbcSpellId === effect.spellId)
?? romTriggeredAbilityBySpellId(effect.spellId)
?? coaTriggeredAbilityBySpellId(effect.spellId);
?? triggeredAbilityBySpellId(effect.spellId);
if (triggered && triggered.id !== ability.id) {
const result = executePartyAbility(runtimeMember, triggered, targetId, now, members, depth + 1);
runtimeMember = result.member;
+10 -3
View File
@@ -14,18 +14,25 @@ function planKey(classId: ClassId, specialization: string): string {
return `${classId}:${specialization}`;
}
export function runtimePartyTalentPlan(
classId: ClassId,
specialization: string,
): readonly string[] {
const plan = snapshot.plans[planKey(classId, specialization)];
if (!plan) throw new Error(`Unsupported party specialization: ${classId}:${specialization}`);
return plan;
}
/** Runtime-only projection of the catalog-validated 71-point party plans. */
export function runtimePartyTalentRanksForLevel(
classId: ClassId,
specialization: string,
level: number,
): TalentRanks {
const plan = snapshot.plans[planKey(classId, specialization)];
if (!plan) throw new Error(`Unsupported party specialization: ${classId}:${specialization}`);
const plan = runtimePartyTalentPlan(classId, specialization);
const safeLevel = Number.isFinite(level) ? Math.max(1, Math.min(80, Math.trunc(level))) : 1;
const points = Math.max(0, safeLevel - 9);
const ranks: Record<string, number> = {};
for (const nodeId of plan.slice(0, points)) ranks[nodeId] = (ranks[nodeId] ?? 0) + 1;
return Object.freeze(ranks);
}
+23
View File
@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import { partyTalentAllocationPlan } from "./partyTalents";
import { partyTalentSelections } from "./partyTalentUi";
import { loadTalentUiCatalog } from "./talentUiCatalog";
describe("party talent UI projection", () => {
it("reconstructs the generated runtime plan from one class shard", async () => {
const catalog = await loadTalentUiCatalog("warrior");
const projected = partyTalentSelections(catalog, "warrior", "Protection");
const source = partyTalentAllocationPlan("warrior", "Protection");
expect(projected).toHaveLength(71);
expect(projected.map((selection) => ({
nodeId: selection.nodeId,
rank: selection.rank,
description: selection.description,
}))).toEqual(source.map((selection) => ({
nodeId: selection.nodeId,
rank: selection.rank,
description: selection.description,
})));
});
});
+73
View File
@@ -0,0 +1,73 @@
import type { ClassId } from "../app/characterCatalog";
import { clampPlayerLevel } from "./progression";
import { runtimePartyTalentPlan } from "./partyTalentRuntime";
import {
talentUiDescriptionForRank,
talentUiNodeById,
talentUiTreeById,
type TalentUiCatalog,
} from "./talentUiCatalog";
export interface PartyTalentSelection {
readonly point: number;
readonly level: number;
readonly nodeId: string;
readonly treeId: string;
readonly treeName: string;
readonly name: string;
readonly rank: number;
readonly maxRank: number;
readonly icon: string;
readonly description: string;
}
export function partyTalentSelections(
catalog: TalentUiCatalog,
classId: ClassId,
specialization: string,
): readonly PartyTalentSelection[] {
if (catalog.classId !== classId) return [];
const ranks: Record<string, number> = {};
return runtimePartyTalentPlan(classId, specialization).map((nodeId, index) => {
const node = talentUiNodeById(catalog, nodeId);
if (!node) throw new Error(`Party talent plan references missing UI node ${nodeId}.`);
const tree = talentUiTreeById(catalog, node.treeId);
if (!tree) throw new Error(`Party talent plan references missing UI tree ${node.treeId}.`);
const rank = (ranks[nodeId] ?? 0) + 1;
ranks[nodeId] = rank;
return Object.freeze({
point: index + 1,
level: index + 10,
nodeId,
treeId: tree.id,
treeName: tree.name,
name: node.name,
rank,
maxRank: node.maxRank,
icon: node.icon,
description: talentUiDescriptionForRank(node, rank),
});
});
}
export function learnedPartyTalentSelections(
catalog: TalentUiCatalog,
classId: ClassId,
specialization: string,
level: number,
): readonly PartyTalentSelection[] {
const points = Math.max(0, clampPlayerLevel(level) - 9);
return partyTalentSelections(catalog, classId, specialization).slice(0, points);
}
export function upcomingPartyTalentSelections(
catalog: TalentUiCatalog,
classId: ClassId,
specialization: string,
level: number,
limit = 5,
): readonly PartyTalentSelection[] {
const start = Math.max(0, clampPlayerLevel(level) - 9);
const safeLimit = Number.isFinite(limit) ? Math.max(0, Math.trunc(limit)) : 0;
return partyTalentSelections(catalog, classId, specialization).slice(start, start + safeLimit);
}
+32
View File
@@ -204,6 +204,38 @@ function allocationFailure(
return null;
}
export function runtimeTalentAllocationFailure(
ranks: RuntimeTalentRanks,
classId: ClassId,
nodeId: string,
level: number,
): TalentAllocationFailure | null {
return allocationFailure(ranks, classId, nodeId, level);
}
export function runtimeSpentTalentPointsInTree(
ranks: RuntimeTalentRanks,
treeId: string,
): number {
return spentTalentPointsInTree(ranks, treeId);
}
export function runtimeUnspentTalentPoints(
level: number,
ranks: RuntimeTalentRanks,
classId?: ClassId,
): number {
return unspentTalentPoints(level, ranks, classId);
}
export function runtimeUnspentCoaEssence(
level: number,
ranks: RuntimeTalentRanks,
classId: CoaClassId,
): { readonly ability: number; readonly talent: number } {
return unspentCoaEssence(level, ranks, classId);
}
export function runtimeNormalizeTalentRanks(
classId: ClassId,
level: number,
+20
View File
@@ -0,0 +1,20 @@
import { describe, expect, it } from "vitest";
import { TALENT_NODES, TALENT_TREES } from "./talentCatalog";
import { loadTalentUiCatalog, talentUiNodesForTree } from "./talentUiCatalog";
describe("talent UI catalog shards", () => {
it.each(["warrior", "barbarian"] as const)("loads only the %s class projection", async (classId) => {
const catalog = await loadTalentUiCatalog(classId);
const sourceTrees = TALENT_TREES.filter((tree) => tree.classId === classId);
const sourceTreeIds = new Set(sourceTrees.map((tree) => tree.id));
const sourceNodes = TALENT_NODES.filter((node) => sourceTreeIds.has(node.treeId));
expect(catalog.classId).toBe(classId);
expect(catalog.trees.map((tree) => tree.id)).toEqual(sourceTrees.map((tree) => tree.id));
expect(catalog.nodes.map((node) => node.id)).toEqual(sourceNodes.map((node) => node.id));
expect(catalog.nodes.every((node) => !("rankEffects" in node))).toBe(true);
for (const tree of catalog.trees) {
expect(talentUiNodesForTree(catalog, tree.id).every((node) => node.treeId === tree.id)).toBe(true);
}
});
});
+93
View File
@@ -0,0 +1,93 @@
import type { ClassId } from "../app/characterCatalog";
export interface TalentUiTree {
readonly id: string;
readonly classId: ClassId;
readonly name: string;
readonly icon: string;
readonly background: string;
readonly description: string;
readonly system?: "classic" | "coa";
}
export interface TalentUiNode {
readonly id: string;
readonly treeId: string;
readonly index: number;
readonly prerequisiteId: string | null;
readonly prerequisiteRank: number | null;
readonly prerequisites: readonly {
readonly talentId: string;
readonly requiredRank: number;
}[];
readonly column: number;
readonly row: number;
readonly icon: string;
readonly maxRank: number;
readonly name: string;
readonly description: string;
readonly rankDescriptions: readonly string[];
readonly system?: "classic" | "coa";
readonly entryType?: "Ability" | "Talent";
readonly abilityEssenceCost?: number;
readonly talentEssenceCost?: number;
readonly requiredClassPoints?: number;
readonly requiredSpecPoints?: number;
readonly requiredLevel?: number;
readonly isPassive?: boolean;
}
export interface TalentUiCatalog {
readonly schemaVersion: 1;
readonly classId: ClassId;
readonly trees: readonly TalentUiTree[];
readonly nodes: readonly TalentUiNode[];
}
interface TalentUiCatalogModule {
readonly default: TalentUiCatalog;
}
const shardLoaders = import.meta.glob<TalentUiCatalogModule>("./generated/talentUi/*.json");
const loadCache = new Map<ClassId, Promise<TalentUiCatalog>>();
export function loadTalentUiCatalog(classId: ClassId): Promise<TalentUiCatalog> {
const cached = loadCache.get(classId);
if (cached) return cached;
const key = `./generated/talentUi/${classId}.json`;
const loader = shardLoaders[key];
if (!loader) return Promise.reject(new Error(`No talent UI catalog exists for ${classId}.`));
const pending = loader().then((module) => {
if (module.default.schemaVersion !== 1 || module.default.classId !== classId) {
throw new Error(`Talent UI catalog ${classId} has incompatible metadata.`);
}
return module.default;
}).catch((error: unknown) => {
loadCache.delete(classId);
throw error;
});
loadCache.set(classId, pending);
return pending;
}
export function talentUiDescriptionForRank(node: TalentUiNode, rank: number): string {
const normalizedRank = Math.min(
node.maxRank,
Math.max(1, Math.trunc(Number.isFinite(rank) ? rank : 1)),
);
return node.rankDescriptions[normalizedRank - 1] ?? node.description;
}
export function talentUiTreeById(catalog: TalentUiCatalog, treeId: string): TalentUiTree | null {
return catalog.trees.find((tree) => tree.id === treeId) ?? null;
}
export function talentUiNodeById(catalog: TalentUiCatalog, nodeId: string): TalentUiNode | null {
return catalog.nodes.find((node) => node.id === nodeId) ?? null;
}
export function talentUiNodesForTree(catalog: TalentUiCatalog, treeId: string): readonly TalentUiNode[] {
return catalog.nodes
.filter((node) => node.treeId === treeId)
.sort((left, right) => left.row - right.row || left.index - right.index);
}
+15
View File
@@ -0,0 +1,15 @@
import { describe, expect, it } from "vitest";
import { dprForPerformanceFactor } from "./adaptiveGraphicsQualityMath";
describe("adaptive graphics quality", () => {
it("maps the performance range onto the supported pixel ratio", () => {
expect(dprForPerformanceFactor(0)).toBe(1);
expect(dprForPerformanceFactor(0.5)).toBe(1.25);
expect(dprForPerformanceFactor(1)).toBe(1.5);
});
it("clamps out-of-range monitor factors", () => {
expect(dprForPerformanceFactor(-1)).toBe(1);
expect(dprForPerformanceFactor(2)).toBe(1.5);
});
});
+20
View File
@@ -0,0 +1,20 @@
import { PerformanceMonitor } from "@react-three/drei";
import { dprForPerformanceFactor } from "./adaptiveGraphicsQualityMath";
export function AdaptiveGraphicsQuality({
onDprChange,
}: {
readonly onDprChange: (dpr: number) => void;
}) {
return (
<PerformanceMonitor
factor={1}
iterations={6}
ms={250}
step={0.25}
threshold={0.75}
bounds={(refreshRate) => refreshRate > 100 ? [60, 100] : [52, 58]}
onChange={({ factor }) => onDprChange(dprForPerformanceFactor(factor))}
/>
);
}
+38
View File
@@ -0,0 +1,38 @@
import { useFrame } from "@react-three/fiber";
import { useEffect, useRef } from "react";
const DATASET_KEY = "gamePerformance";
/** Publishes low-overhead renderer counters for local profiling only. */
export function DevelopmentPerformanceProbe() {
const elapsedRef = useRef(0);
const framesRef = useRef(0);
const slowestFrameRef = useRef(0);
useFrame(({ gl }, delta) => {
elapsedRef.current += delta;
framesRef.current += 1;
slowestFrameRef.current = Math.max(slowestFrameRef.current, delta);
if (elapsedRef.current < 1) return;
document.documentElement.dataset[DATASET_KEY] = JSON.stringify({
fps: framesRef.current / elapsedRef.current,
averageFrameMs: elapsedRef.current * 1_000 / framesRef.current,
slowestFrameMs: slowestFrameRef.current * 1_000,
drawCalls: gl.info.render.calls,
triangles: gl.info.render.triangles,
geometries: gl.info.memory.geometries,
textures: gl.info.memory.textures,
pixelRatio: gl.getPixelRatio(),
});
elapsedRef.current = 0;
framesRef.current = 0;
slowestFrameRef.current = 0;
});
useEffect(() => () => {
delete document.documentElement.dataset[DATASET_KEY];
}, []);
return null;
}
+20 -1
View File
@@ -28,6 +28,7 @@ import {
encounterWorldIsReady,
encounterWorldKey,
rendererCanvasKey,
sceneFrameLoop,
} from "./sceneLifecycle";
import { manastormChaoticLinkRuntimeIds } from "../game/manastormChaoticLink";
import { manastormStagePopulation, manastormStageRoamingPacks } from "../game/manastormStagePopulation";
@@ -44,6 +45,8 @@ import { GmPlacementMarkers } from "./GmPlacementMarkers";
import { useOnlineGroupStore } from "../app/onlineGroupStore";
import { useOnlineSessionStore } from "../app/onlineSessionStore";
import { OnlinePlayerPopulation } from "./OnlinePlayerPopulation";
import { DevelopmentPerformanceProbe } from "./DevelopmentPerformanceProbe";
import { AdaptiveGraphicsQuality } from "./AdaptiveGraphicsQuality";
export function GameScene() {
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
@@ -97,12 +100,21 @@ export function GameScene() {
const canvasRef = useRef<HTMLCanvasElement>(null);
const [readySessionRevision, setReadySessionRevision] = useState<number | null>(null);
const [safeGraphics, setSafeGraphics] = useState(false);
const [adaptiveDpr, setAdaptiveDpr] = useState(1.5);
const [canvasRevision, setCanvasRevision] = useState(0);
const [graphicsRecovery, setGraphicsRecovery] = useState<"lost" | "recovering" | null>(null);
const worldReady = encounterWorldIsReady(readySessionRevision, sessionRevision);
const simulationBlocked = graphicsRecovery !== null
|| !worldReady
|| (!sharedOnline && (paused || mapOpen || companionOpen));
const frameloop = sceneFrameLoop({
worldReady,
graphicsRecovering: graphicsRecovery !== null,
sharedOnline,
paused,
mapOpen,
companionOpen,
});
const allowedRuntimeIds = useMemo(
() => gameMode === "manastorm" && manastormEncounter
? manastormChaoticLinkRuntimeIds(manastormEncounter, manastormPhase)
@@ -153,6 +165,10 @@ export function GameScene() {
useWailingEncounterStore.getState().reset();
}, [activeDungeonId, gameMode, sessionRevision]);
useEffect(() => {
setAdaptiveDpr(1.5);
}, [activeDungeonId, sessionRevision]);
const endMouseLook = useCallback(() => {
endMouseLookDrag();
}, []);
@@ -193,7 +209,8 @@ export function GameScene() {
key={rendererCanvasKey(canvasRevision)}
ref={canvasRef}
shadows={!safeGraphics}
dpr={safeGraphics ? 1 : [1, 1.5]}
dpr={safeGraphics ? 1 : adaptiveDpr}
frameloop={frameloop}
camera={{
fov: 62,
near: 0.08,
@@ -210,6 +227,8 @@ export function GameScene() {
}}
>
<GameGltfLoaderLifecycle>
{!safeGraphics && worldReady && <AdaptiveGraphicsQuality onDprChange={setAdaptiveDpr} />}
{import.meta.env.DEV && <DevelopmentPerformanceProbe />}
<color attach="background" args={[dungeon.presentation.background]} />
<fog attach="fog" args={[dungeon.presentation.fog.color, dungeon.presentation.fog.near, dungeon.presentation.fog.far]} />
<ambientLight intensity={dungeon.presentation.ambientLight.intensity} color={dungeon.presentation.ambientLight.color} />
+2 -19
View File
@@ -78,6 +78,7 @@ import { useGameStore } from "../game/store";
import { useManastormStore } from "../game/manastormStore";
import { registerCombatSpatialProvider } from "../game/combatSpatial";
import { PLAYER_AGGRO_ID } from "../game/aggro";
import { hasDungeonLineOfSight } from "./dungeonLineOfSight";
const PARTY_MOVE_SPEED = 5.25;
const PARTY_CATCH_UP_SPEED = 7.5;
@@ -378,25 +379,7 @@ function PartyActors({
const hasStaticLineOfSight = useCallback((
start: PartyWorldPosition,
end: PartyWorldPosition,
): boolean => {
const dx = end[0] - start[0];
const dy = end[1] - start[1];
const dz = end[2] - start[2];
const distance = Math.hypot(dx, dy, dz);
if (!Number.isFinite(distance)) return false;
if (distance <= 0.08) return true;
const ray = new rapier.Ray(
{ x: start[0], y: start[1] + 1.05, z: start[2] },
{ x: dx / distance, y: dy / distance, z: dz / distance },
);
const hit = world.castRay(
ray,
distance,
true,
rapier.QueryFilterFlags.EXCLUDE_SENSORS | rapier.QueryFilterFlags.EXCLUDE_DYNAMIC,
);
return !hit || hit.timeOfImpact >= distance - 0.08;
}, [rapier, world]);
): boolean => hasDungeonLineOfSight(rapier, world, start, end), [rapier, world]);
const routeSurfaceSegmentAllowed = useCallback((
start: PartyWorldPosition,
end: PartyWorldPosition,
+40 -1
View File
@@ -7,7 +7,11 @@ import {
MeshBasicMaterial,
} from "three";
import { describe, expect, it } from "vitest";
import { collisionTrimeshes, prepareCollision } from "./productionDungeonCollision";
import {
collisionLineOfSightTrimeshes,
collisionTrimeshes,
prepareCollision,
} from "./productionDungeonCollision";
describe("streamed dungeon collision preparation", () => {
it("dequantizes normalized Meshopt position buffers before Rapier consumes them", () => {
@@ -54,4 +58,39 @@ describe("streamed dungeon collision preparation", () => {
expect(Array.from(trimesh.indices)).toEqual([0, 1, 2]);
});
it("builds sight collision from walls while excluding ground and ramps", () => {
const geometry = new BufferGeometry();
geometry.setAttribute(
"position",
new Float32BufferAttribute([
0, 0, 0,
2, 0, 0,
0, 0, 2,
0, 0, 3,
2, 0, 3,
0, 2, 5,
4, 0, 0,
4, 2, 0,
4, 0, 2,
], 3),
);
geometry.setIndex([
0, 1, 2,
3, 4, 5,
6, 7, 8,
]);
const root = new Group();
root.add(new Mesh(geometry, new MeshBasicMaterial()));
const prepared = prepareCollision(root);
const [blocker] = collisionLineOfSightTrimeshes(prepared);
expect(Array.from(blocker.indices)).toEqual([0, 1, 2]);
expect(Array.from(blocker.vertices)).toEqual([
4, 0, 0,
4, 2, 0,
4, 0, 2,
]);
});
});
+21 -1
View File
@@ -12,8 +12,17 @@ import {
import type { ResolvedDungeonAssets } from "../game/dungeonAssets";
import type { DungeonDefinition, DungeonMaterialRoles } from "../game/dungeonTypes";
import { useGameStore } from "../game/store";
import { collisionTrimeshes, prepareCollision } from "./productionDungeonCollision";
import {
collisionLineOfSightTrimeshes,
collisionTrimeshes,
prepareCollision,
} from "./productionDungeonCollision";
import {
DUNGEON_PHYSICAL_COLLISION_GROUPS,
DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS,
} from "./dungeonLineOfSight";
import { disposeObject3DResources } from "./threeResourceDisposal";
import { instanceRepeatedStaticMeshes } from "./staticSceneInstancing";
import { useGameGLTF } from "./useGameGLTF";
import {
DUNGEON_COLLISION_LOAD_BATCH_SIZE,
@@ -81,6 +90,7 @@ function prepareVisual(root: Object3D, roles: DungeonMaterialRoles): Object3D {
instanced.computeBoundingSphere();
}
});
instanceRepeatedStaticMeshes(clone);
return clone;
}
@@ -141,6 +151,7 @@ function CollisionChunk({
const gltf = useGameGLTF(url);
const collision = useMemo(() => prepareCollision(gltf.scene), [gltf.scene]);
const trimeshes = useMemo(() => collisionTrimeshes(collision), [collision]);
const sightBlockers = useMemo(() => collisionLineOfSightTrimeshes(collision), [collision]);
useEffect(() => () => {
disposeObject3DResources(collision, {
materials: false,
@@ -166,6 +177,15 @@ function CollisionChunk({
<TrimeshCollider
key={trimesh.id}
args={[trimesh.vertices, trimesh.indices]}
collisionGroups={DUNGEON_PHYSICAL_COLLISION_GROUPS}
/>
))}
{sightBlockers.map((trimesh) => (
<TrimeshCollider
key={trimesh.id}
args={[trimesh.vertices, trimesh.indices]}
collisionGroups={DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS}
sensor
/>
))}
<primitive object={collision} />
+25 -6
View File
@@ -1,17 +1,36 @@
import { Sparkles } from "@react-three/drei";
import { RigidBody } from "@react-three/rapier";
import type { DungeonDefinition } from "../game/dungeonTypes";
import {
DUNGEON_PHYSICAL_COLLISION_GROUPS,
DUNGEON_WALL_COLLISION_GROUPS,
} from "./dungeonLineOfSight";
interface SlabProps {
position: [number, number, number];
size: [number, number, number];
rotationY?: number;
color?: string;
blocksLineOfSight?: boolean;
}
function CaveSlab({ position, size, rotationY = 0, color = "#25352b" }: SlabProps) {
function CaveSlab({
position,
size,
rotationY = 0,
color = "#25352b",
blocksLineOfSight = false,
}: SlabProps) {
return (
<RigidBody type="fixed" colliders="cuboid" position={position} rotation={[0, rotationY, 0]}>
<RigidBody
type="fixed"
colliders="cuboid"
collisionGroups={blocksLineOfSight
? DUNGEON_WALL_COLLISION_GROUPS
: DUNGEON_PHYSICAL_COLLISION_GROUPS}
position={position}
rotation={[0, rotationY, 0]}
>
<mesh receiveShadow castShadow>
<boxGeometry args={size} />
<meshStandardMaterial color={color} roughness={0.96} metalness={0.02} />
@@ -45,11 +64,11 @@ export function PrototypeDungeon({ definition }: { readonly definition: DungeonD
rotation={[0, entrance.yaw, 0]}
>
<CaveSlab position={[0, -0.3, 11]} size={[7.4, 0.6, 28]} />
<CaveSlab position={[-4.1, 2.15, 11]} size={[1.1, 4.9, 28]} color="#1c2c24" />
<CaveSlab position={[4.1, 2.15, 11]} size={[1.1, 4.9, 28]} color="#1c2c24" />
<CaveSlab position={[-4.1, 2.15, 11]} size={[1.1, 4.9, 28]} color="#1c2c24" blocksLineOfSight />
<CaveSlab position={[4.1, 2.15, 11]} size={[1.1, 4.9, 28]} color="#1c2c24" blocksLineOfSight />
<CaveSlab position={[0, -0.36, 31]} size={[18, 0.72, 15]} color="#2b3d31" />
<CaveSlab position={[-9.25, 2, 31]} size={[1.1, 4.7, 15]} color="#1b2a23" />
<CaveSlab position={[9.25, 2, 31]} size={[1.1, 4.7, 15]} color="#1b2a23" />
<CaveSlab position={[-9.25, 2, 31]} size={[1.1, 4.7, 15]} color="#1b2a23" blocksLineOfSight />
<CaveSlab position={[9.25, 2, 31]} size={[1.1, 4.7, 15]} color="#1b2a23" blocksLineOfSight />
<CaveSlab position={[3.3, -0.3, 44]} size={[9, 0.6, 19]} rotationY={-0.34} />
{stonePositions.map((position, index) => <Stone key={index} position={position} />)}
+3
View File
@@ -0,0 +1,3 @@
export function dprForPerformanceFactor(factor: number): number {
return 1 + Math.max(0, Math.min(1, factor)) * 0.5;
}
+57
View File
@@ -0,0 +1,57 @@
import RAPIER from "@dimforge/rapier3d-compat";
import { beforeAll, describe, expect, it } from "vitest";
import {
DUNGEON_PHYSICAL_COLLISION_GROUPS,
DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS,
hasDungeonLineOfSight,
} from "./dungeonLineOfSight";
beforeAll(async () => {
await RAPIER.init();
});
function fixedCuboid(
world: RAPIER.World,
translation: readonly [number, number, number],
collisionGroups: number,
sensor = false,
): void {
const body = world.createRigidBody(RAPIER.RigidBodyDesc.fixed());
world.createCollider(
RAPIER.ColliderDesc.cuboid(0.1, 2, 2)
.setTranslation(...translation)
.setCollisionGroups(collisionGroups)
.setSensor(sensor),
body,
);
}
function kinematicCaster(world: RAPIER.World): void {
const body = world.createRigidBody(
RAPIER.RigidBodyDesc.kinematicPositionBased().setTranslation(0, 1.05, 0),
);
world.createCollider(RAPIER.ColliderDesc.capsule(0.5, 0.3), body);
}
describe("dungeon line of sight", () => {
it("ignores physical ground geometry even when it crosses the sight ray", () => {
const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 });
fixedCuboid(world, [2, 1.05, 0], DUNGEON_PHYSICAL_COLLISION_GROUPS);
kinematicCaster(world);
world.step();
expect(hasDungeonLineOfSight(RAPIER, world, [0, 0, 0], [4, 0, 0])).toBe(true);
world.free();
});
it("is blocked by dedicated wall and pillar geometry", () => {
const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 });
fixedCuboid(world, [2, 1.05, 0], DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS, true);
world.step();
expect(hasDungeonLineOfSight(RAPIER, world, [0, 0, 0], [4, 0, 0])).toBe(false);
world.free();
});
});
+60
View File
@@ -0,0 +1,60 @@
import { interactionGroups } from "@react-three/rapier";
import type {
QueryFilterFlags,
Ray,
Vector,
World,
} from "@dimforge/rapier3d-compat";
interface RapierApi {
readonly Ray: new (origin: Vector, direction: Vector) => Ray;
readonly QueryFilterFlags: {
readonly EXCLUDE_DYNAMIC: QueryFilterFlags;
readonly EXCLUDE_KINEMATIC: QueryFilterFlags;
};
}
type WorldPosition = readonly [number, number, number];
export const DUNGEON_LINE_OF_SIGHT_GROUP = 15;
export const DUNGEON_PHYSICAL_COLLISION_GROUPS = interactionGroups(0);
export const DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS = interactionGroups(DUNGEON_LINE_OF_SIGHT_GROUP);
export const DUNGEON_WALL_COLLISION_GROUPS = interactionGroups([0, DUNGEON_LINE_OF_SIGHT_GROUP]);
export const DUNGEON_SIGHT_QUERY_GROUPS = interactionGroups(
DUNGEON_LINE_OF_SIGHT_GROUP,
DUNGEON_LINE_OF_SIGHT_GROUP,
);
const ACTOR_SIGHT_HEIGHT = 1.05;
const TARGET_MARGIN = 0.08;
/**
* Checks only the dedicated wall/pillar collision layer. Walkable terrain and
* ceilings remain physical, but never participate in combat visibility.
*/
export function hasDungeonLineOfSight(
rapier: RapierApi,
world: World,
start: WorldPosition,
end: WorldPosition,
): boolean {
const dx = end[0] - start[0];
const dy = end[1] - start[1];
const dz = end[2] - start[2];
const distance = Math.hypot(dx, dy, dz);
if (!Number.isFinite(distance)) return false;
if (distance <= TARGET_MARGIN) return true;
const ray = new rapier.Ray(
{ x: start[0], y: start[1] + ACTOR_SIGHT_HEIGHT, z: start[2] },
{ x: dx / distance, y: dy / distance, z: dz / distance },
);
const hit = world.castRay(
ray,
distance,
true,
rapier.QueryFilterFlags.EXCLUDE_DYNAMIC | rapier.QueryFilterFlags.EXCLUDE_KINEMATIC,
DUNGEON_SIGHT_QUERY_GROUPS,
);
return !hit || hit.timeOfImpact >= distance - TARGET_MARGIN;
}
+62
View File
@@ -11,6 +11,10 @@ export interface PreparedCollisionTrimesh {
readonly indices: ArrayLike<number>;
}
// A surface must be within 30 degrees of vertical to occlude combat sight.
// This deliberately rejects floors, ramps, slopes, and ceilings.
const MAX_SIGHT_BLOCKER_NORMAL_Y = 0.5;
export function prepareCollision(root: Object3D): Group {
root.updateWorldMatrix(true, true);
const inverseRootMatrix = root.matrixWorld.clone().invert();
@@ -60,3 +64,61 @@ export function collisionTrimeshes(root: Object3D): readonly PreparedCollisionTr
});
return result;
}
export function collisionLineOfSightTrimeshes(root: Object3D): readonly PreparedCollisionTrimesh[] {
const result: PreparedCollisionTrimesh[] = [];
root.traverse((node) => {
const mesh = node as Mesh;
if (!mesh.isMesh) return;
const position = mesh.geometry.getAttribute("position");
const sourceIndices = mesh.geometry.index?.array
?? Uint32Array.from({ length: position.count }, (_, vertex) => vertex);
const blockerSourceIndices: number[] = [];
for (let offset = 0; offset + 2 < sourceIndices.length; offset += 3) {
const first = Number(sourceIndices[offset]);
const second = Number(sourceIndices[offset + 1]);
const third = Number(sourceIndices[offset + 2]);
const firstX = position.getX(first);
const firstY = position.getY(first);
const firstZ = position.getZ(first);
const abX = position.getX(second) - firstX;
const abY = position.getY(second) - firstY;
const abZ = position.getZ(second) - firstZ;
const acX = position.getX(third) - firstX;
const acY = position.getY(third) - firstY;
const acZ = position.getZ(third) - firstZ;
const normalX = abY * acZ - abZ * acY;
const normalY = abZ * acX - abX * acZ;
const normalZ = abX * acY - abY * acX;
const normalLength = Math.hypot(normalX, normalY, normalZ);
if (normalLength <= Number.EPSILON) continue;
if (Math.abs(normalY) / normalLength > MAX_SIGHT_BLOCKER_NORMAL_Y) continue;
blockerSourceIndices.push(first, second, third);
}
if (!blockerSourceIndices.length) return;
const remappedVertices: number[] = [];
const remappedIndices = new Uint32Array(blockerSourceIndices.length);
const remap = new Map<number, number>();
blockerSourceIndices.forEach((sourceIndex, indexOffset) => {
let remappedIndex = remap.get(sourceIndex);
if (remappedIndex === undefined) {
remappedIndex = remap.size;
remap.set(sourceIndex, remappedIndex);
remappedVertices.push(
position.getX(sourceIndex),
position.getY(sourceIndex),
position.getZ(sourceIndex),
);
}
remappedIndices[indexOffset] = remappedIndex;
});
result.push({
id: `${mesh.uuid}-line-of-sight`,
vertices: Float32Array.from(remappedVertices),
indices: remappedIndices,
});
});
return result;
}
+19
View File
@@ -3,6 +3,7 @@ import {
encounterWorldIsReady,
encounterWorldKey,
rendererCanvasKey,
sceneFrameLoop,
} from "./sceneLifecycle";
describe("R3F scene lifecycle", () => {
@@ -18,4 +19,22 @@ describe("R3F scene lifecycle", () => {
expect(encounterWorldIsReady(4, 4)).toBe(true);
expect(encounterWorldIsReady(4, 5)).toBe(false);
});
it("renders local paused worlds on demand without stalling loading or online worlds", () => {
const readyWorld = {
worldReady: true,
graphicsRecovering: false,
sharedOnline: false,
paused: false,
mapOpen: false,
companionOpen: false,
};
expect(sceneFrameLoop({ ...readyWorld, paused: true })).toBe("demand");
expect(sceneFrameLoop({ ...readyWorld, mapOpen: true })).toBe("demand");
expect(sceneFrameLoop({ ...readyWorld, companionOpen: true })).toBe("demand");
expect(sceneFrameLoop({ ...readyWorld, paused: true, sharedOnline: true })).toBe("always");
expect(sceneFrameLoop({ ...readyWorld, paused: true, worldReady: false })).toBe("always");
expect(sceneFrameLoop({ ...readyWorld, paused: true, graphicsRecovering: true })).toBe("always");
expect(sceneFrameLoop(readyWorld)).toBe("always");
});
});
+21
View File
@@ -1,4 +1,5 @@
import type { DungeonId } from "../game/dungeonRegistry";
import type { Frameloop } from "@react-three/fiber";
/**
* Encounter transitions must never remount the Canvas: R3F intentionally loses
@@ -27,3 +28,23 @@ export function encounterWorldIsReady(
return readySessionRevision !== null
&& readySessionRevision === Math.max(0, Math.trunc(sessionRevision));
}
/**
* A paused local world only needs a frame when React or R3F invalidates it.
* Loading, recovery, and shared-online worlds keep the continuous loop so
* asynchronous scene setup and authoritative remote simulation can progress.
*/
export function sceneFrameLoop(options: {
readonly worldReady: boolean;
readonly graphicsRecovering: boolean;
readonly sharedOnline: boolean;
readonly paused: boolean;
readonly mapOpen: boolean;
readonly companionOpen: boolean;
}): Frameloop {
const locallyPaused = options.worldReady
&& !options.graphicsRecovering
&& !options.sharedOnline
&& (options.paused || options.mapOpen || options.companionOpen);
return locallyPaused ? "demand" : "always";
}
+109
View File
@@ -0,0 +1,109 @@
import { describe, expect, it } from "vitest";
import {
BoxGeometry,
Group,
InstancedMesh,
Matrix4,
Mesh,
MeshBasicMaterial,
Vector3,
} from "three";
import { instanceRepeatedStaticMeshes } from "./staticSceneInstancing";
function batchIn(root: Group): InstancedMesh {
let result: InstancedMesh | null = null;
root.traverse((node) => {
if ((node as InstancedMesh).isInstancedMesh) result = node as InstancedMesh;
});
if (!result) throw new Error("Expected an instanced mesh batch.");
return result;
}
function batchesIn(root: Group): readonly InstancedMesh[] {
const result: InstancedMesh[] = [];
root.traverse((node) => {
if ((node as InstancedMesh).isInstancedMesh) result.push(node as InstancedMesh);
});
return result;
}
describe("static scene instancing", () => {
it("batches repeated meshes while retaining their world transforms", () => {
const root = new Group();
root.position.set(10, 0, 0);
const geometry = new BoxGeometry();
const material = new MeshBasicMaterial();
for (const x of [1, 3, 7]) {
const mesh = new Mesh(geometry, material);
mesh.position.x = x;
root.add(mesh);
}
expect(instanceRepeatedStaticMeshes(root)).toEqual({
batches: 1,
instances: 3,
removedMeshes: 3,
});
const batch = batchIn(root);
const matrix = new Matrix4();
const position = new Vector3();
const positions = Array.from({ length: batch.count }, (_, index) => {
batch.getMatrixAt(index, matrix);
position.setFromMatrixPosition(matrix);
return position.x;
});
expect(positions).toEqual([1, 3, 7]);
});
it("leaves small groups and existing instance batches unchanged", () => {
const root = new Group();
const geometry = new BoxGeometry();
const material = new MeshBasicMaterial();
root.add(new Mesh(geometry, material), new Mesh(geometry, material));
const existing = new InstancedMesh(geometry, material, 4);
root.add(existing);
expect(instanceRepeatedStaticMeshes(root)).toEqual({
batches: 0,
instances: 0,
removedMeshes: 0,
});
expect(root.children).toHaveLength(3);
expect(root.children).toContain(existing);
});
it("does not combine meshes whose render state differs", () => {
const root = new Group();
const geometry = new BoxGeometry();
const material = new MeshBasicMaterial();
for (let index = 0; index < 3; index += 1) {
const mesh = new Mesh(geometry, material);
mesh.receiveShadow = index !== 2;
root.add(mesh);
}
expect(instanceRepeatedStaticMeshes(root)).toEqual({
batches: 0,
instances: 0,
removedMeshes: 0,
});
});
it("keeps distant repetitions in separate cullable spatial batches", () => {
const root = new Group();
const geometry = new BoxGeometry();
const material = new MeshBasicMaterial();
for (const x of [1, 2, 3, 385, 386, 387]) {
const mesh = new Mesh(geometry, material);
mesh.position.x = x;
root.add(mesh);
}
expect(instanceRepeatedStaticMeshes(root)).toEqual({
batches: 2,
instances: 6,
removedMeshes: 6,
});
expect(batchesIn(root).map((batch) => batch.count)).toEqual([3, 3]);
});
});
+116
View File
@@ -0,0 +1,116 @@
import {
InstancedMesh,
Matrix4,
type Material,
type Mesh,
type Object3D,
Vector3,
} from "three";
export const STATIC_INSTANCE_CELL_SIZE = 192;
export interface StaticSceneInstancingReport {
readonly batches: number;
readonly instances: number;
readonly removedMeshes: number;
}
function materialKey(material: Material | readonly Material[]): string {
return (Array.isArray(material) ? material : [material])
.map((entry) => entry.uuid)
.join(",");
}
function candidateKey(mesh: Mesh): string {
return [
mesh.geometry.uuid,
materialKey(mesh.material),
mesh.castShadow ? "cast" : "no-cast",
mesh.receiveShadow ? "receive" : "no-receive",
mesh.renderOrder,
mesh.layers.mask,
mesh.frustumCulled ? "culled" : "not-culled",
].join("|");
}
function candidateCell(mesh: Mesh, cellSize: number, center: Vector3): string {
if (!mesh.geometry.boundingSphere) mesh.geometry.computeBoundingSphere();
const geometryCenter = mesh.geometry.boundingSphere?.center;
if (geometryCenter) center.copy(geometryCenter);
else center.set(0, 0, 0);
center.applyMatrix4(mesh.matrixWorld);
return [
Math.floor(center.x / cellSize),
Math.floor(center.y / cellSize),
Math.floor(center.z / cellSize),
].join(":");
}
function isStaticInstancingCandidate(root: Object3D, node: Object3D): node is Mesh {
const mesh = node as Mesh;
return node !== root
&& mesh.isMesh === true
&& (mesh as Mesh & { readonly isInstancedMesh?: boolean }).isInstancedMesh !== true
&& (mesh as Mesh & { readonly isSkinnedMesh?: boolean }).isSkinnedMesh !== true
&& mesh.visible
&& mesh.children.length === 0
&& Object.keys(mesh.geometry.morphAttributes).length === 0
&& mesh.matrixWorld.determinant() > 0;
}
/**
* Flattens repeated static meshes into InstancedMesh batches once, immediately
* after a dungeon visual is cloned. This keeps legacy packs efficient without
* moving scene work into the render loop; newly optimized GLBs are left alone.
*/
export function instanceRepeatedStaticMeshes(
root: Object3D,
minimumInstances = 3,
cellSize = STATIC_INSTANCE_CELL_SIZE,
): StaticSceneInstancingReport {
root.updateWorldMatrix(true, true);
const safeCellSize = Number.isFinite(cellSize) && cellSize > 0
? cellSize
: STATIC_INSTANCE_CELL_SIZE;
const center = new Vector3();
const groups = new Map<string, Mesh[]>();
root.traverse((node) => {
if (!isStaticInstancingCandidate(root, node)) return;
const key = `${candidateKey(node)}|cell:${candidateCell(node, safeCellSize, center)}`;
const group = groups.get(key);
if (group) group.push(node);
else groups.set(key, [node]);
});
const inverseRootWorld = new Matrix4().copy(root.matrixWorld).invert();
let batches = 0;
let instances = 0;
let removedMeshes = 0;
for (const meshes of groups.values()) {
if (meshes.length < minimumInstances) continue;
const prototype = meshes[0];
const batch = new InstancedMesh(prototype.geometry, prototype.material, meshes.length);
batch.name = `${prototype.name || prototype.geometry.name || "mesh"}-instances`;
batch.castShadow = prototype.castShadow;
batch.receiveShadow = prototype.receiveShadow;
batch.renderOrder = prototype.renderOrder;
batch.layers.mask = prototype.layers.mask;
batch.frustumCulled = prototype.frustumCulled;
for (let index = 0; index < meshes.length; index += 1) {
const mesh = meshes[index];
batch.setMatrixAt(index, new Matrix4().multiplyMatrices(inverseRootWorld, mesh.matrixWorld));
mesh.removeFromParent();
}
batch.instanceMatrix.needsUpdate = true;
batch.computeBoundingBox();
batch.computeBoundingSphere();
root.add(batch);
batches += 1;
instances += meshes.length;
removedMeshes += meshes.length;
}
return { batches, instances, removedMeshes };
}
+58 -11
View File
@@ -4,14 +4,18 @@ import {
learnedPartyTalentSelections,
upcomingPartyTalentSelections,
type PartyTalentSelection,
} from "../game/partyTalents";
} from "../game/partyTalentUi";
import {
PARTY_ROLE_LABELS,
usePartyStore,
type PartyCommand,
type PartyMember,
} from "../game/partyStore";
import { talentTreeById } from "../game/talentCatalog";
import {
loadTalentUiCatalog,
talentUiTreeById,
type TalentUiCatalog,
} from "../game/talentUiCatalog";
import { useGameStore } from "../game/store";
import { useMenuController, type MenuAction } from "../input/useMenuController";
import { ControllerButton } from "./ControllerButton";
@@ -70,6 +74,8 @@ function PartyManagementDialog() {
const command = usePartyStore((state) => state.command);
const openOverlay = useGameStore((state) => state.openOverlay);
const [inspectedMemberId, setInspectedMemberId] = useState(() => members[0]?.id ?? "");
const [talentCatalog, setTalentCatalog] = useState<TalentUiCatalog | null>(null);
const [talentCatalogErrorClassId, setTalentCatalogErrorClassId] = useState<string | null>(null);
const close = useCallback(() => openOverlay("pause"), [openOverlay]);
useEffect(() => {
@@ -79,13 +85,45 @@ function PartyManagementDialog() {
}, [inspectedMemberId, members]);
const inspectedMember = members.find((member) => member.id === inspectedMemberId) ?? members[0] ?? null;
const learned = useMemo(() => inspectedMember
? learnedPartyTalentSelections(inspectedMember.classId, inspectedMember.specialization, inspectedMember.level)
: [], [inspectedMember]);
useEffect(() => {
const classId = inspectedMember?.classId;
if (!classId || classId.startsWith("rom-")) {
setTalentCatalog(null);
setTalentCatalogErrorClassId(null);
return;
}
let active = true;
setTalentCatalogErrorClassId(null);
void loadTalentUiCatalog(classId).then((catalog) => {
if (active) setTalentCatalog(catalog);
}).catch(() => {
if (!active) return;
setTalentCatalog(null);
setTalentCatalogErrorClassId(classId);
});
return () => { active = false; };
}, [inspectedMember?.classId]);
const activeTalentCatalog = inspectedMember && talentCatalog?.classId === inspectedMember.classId
? talentCatalog
: null;
const learned = useMemo(() => inspectedMember && activeTalentCatalog
? learnedPartyTalentSelections(
activeTalentCatalog,
inspectedMember.classId,
inspectedMember.specialization,
inspectedMember.level,
)
: [], [activeTalentCatalog, inspectedMember]);
const currentTalents = useMemo(() => currentTalentRanks(learned), [learned]);
const upcomingTalents = useMemo(() => inspectedMember
? upcomingPartyTalentSelections(inspectedMember.classId, inspectedMember.specialization, inspectedMember.level, 3)
: [], [inspectedMember]);
const upcomingTalents = useMemo(() => inspectedMember && activeTalentCatalog
? upcomingPartyTalentSelections(
activeTalentCatalog,
inspectedMember.classId,
inspectedMember.specialization,
inspectedMember.level,
3,
)
: [], [activeTalentCatalog, inspectedMember]);
const actions = useMemo<MenuAction[]>(() => [
...members.map((member) => ({
@@ -106,7 +144,9 @@ function PartyManagementDialog() {
const memberClass = inspectedMember ? classById(inspectedMember.classId) : null;
const memberRace = inspectedMember ? raceById(inspectedMember.raceId) : null;
const primaryTree = inspectedMember ? talentTreeById(inspectedMember.talentTreeId) : null;
const primaryTree = inspectedMember && activeTalentCatalog
? talentUiTreeById(activeTalentCatalog, inspectedMember.talentTreeId)
: null;
const primaryPoints = inspectedMember
? learned.filter((selection) => selection.treeId === inspectedMember.talentTreeId).length
: 0;
@@ -210,7 +250,14 @@ function PartyManagementDialog() {
</header>
<div className="party-management__talent-list">
{currentTalents.map((selection) => <TalentSelectionCard key={selection.nodeId} selection={selection} />)}
{!currentTalents.length && (
{!activeTalentCatalog && (
<p className="party-management__empty-talents">
{talentCatalogErrorClassId === inspectedMember.classId
? "Talent details are temporarily unavailable."
: "Preparing this class's talent catalog…"}
</p>
)}
{activeTalentCatalog && !currentTalents.length && (
<p className="party-management__empty-talents">
Talent training begins at level 10. This build will advance automatically with you.
</p>
@@ -227,7 +274,7 @@ function PartyManagementDialog() {
{upcomingTalents.map((selection) => (
<TalentSelectionCard key={`${selection.level}-${selection.nodeId}`} selection={selection} upcoming />
))}
{!upcomingTalents.length && (
{activeTalentCatalog && !upcomingTalents.length && (
<p className="party-management__empty-talents">This party member has completed the level 80 talent plan.</p>
)}
</div>
+15 -17
View File
@@ -1,14 +1,12 @@
import { useMemo } from "react";
import { classById } from "../app/characterCatalog";
import { use, useMemo } from "react";
import { classById, type CoaClassId } from "../app/characterCatalog";
import { useCombatStore } from "../game/combatStore";
import {
spentTalentPointsInTree,
talentNodesForTree,
talentTreesForClass,
unspentCoaEssence,
unspentTalentPoints,
} from "../game/talentCatalog";
import { isCoaClassId } from "../game/coaLiveCatalog";
runtimeSpentTalentPointsInTree,
runtimeUnspentCoaEssence,
runtimeUnspentTalentPoints,
} from "../game/talentRuntimeCatalog";
import { loadTalentUiCatalog, talentUiNodesForTree } from "../game/talentUiCatalog";
import { TalentsPanel } from "./TalentsPanel";
function treeSigil(name: string): string {
@@ -20,19 +18,20 @@ export default function TalentGameplayPanel() {
const level = useCombatStore((state) => state.level);
const talentRanks = useCombatStore((state) => state.talentRanks);
const classDefinition = classById(classId);
const talentTrees = useMemo(() => talentTreesForClass(classId).map((tree) => ({
const catalog = use(loadTalentUiCatalog(classId));
const talentTrees = useMemo(() => catalog.trees.map((tree) => ({
id: tree.id,
name: tree.name,
description: tree.description,
points: spentTalentPointsInTree(talentRanks, tree.id),
points: runtimeSpentTalentPointsInTree(talentRanks, tree.id),
color: classDefinition.color,
sigil: treeSigil(tree.name),
iconUrl: tree.icon,
backgroundUrl: tree.background,
nodes: talentNodesForTree(tree.id),
})), [classDefinition.color, classId, talentRanks]);
const coaEssence = isCoaClassId(classId)
? unspentCoaEssence(level, talentRanks, classId)
nodes: talentUiNodesForTree(catalog, tree.id),
})), [catalog, classDefinition.color, talentRanks]);
const coaEssence = classDefinition.mode === "conquest"
? runtimeUnspentCoaEssence(level, talentRanks, classId as CoaClassId)
: null;
return <TalentsPanel
@@ -40,11 +39,10 @@ export default function TalentGameplayPanel() {
ranks={talentRanks}
classId={classId}
playerLevel={level}
availablePoints={unspentTalentPoints(level, talentRanks, classId)}
availablePoints={runtimeUnspentTalentPoints(level, talentRanks, classId)}
abilityEssence={coaEssence?.ability}
talentEssence={coaEssence?.talent}
onInvest={(nodeId) => { useCombatStore.getState().allocateTalent(nodeId); }}
onReset={() => useCombatStore.getState().resetTalents()}
/>;
}
+18 -16
View File
@@ -1,11 +1,13 @@
import { useEffect, useMemo, useState, type CSSProperties } from "react";
import type { ClassId } from "../app/characterCatalog";
import { runtimeTalentAllocationFailure } from "../game/talentRuntimeCatalog";
import {
talentDescriptionForRank,
talentAllocationFailure,
type TalentAllocationFailure,
type TalentNodeDefinition,
type TalentRanks,
talentUiDescriptionForRank,
type TalentUiNode,
} from "../game/talentUiCatalog";
import type {
TalentAllocationFailure,
TalentRanks,
} from "../game/talentCatalog";
import { useGameStore } from "../game/store";
import { useMenuController, type MenuAction, type MenuDirection } from "../input/useMenuController";
@@ -20,7 +22,7 @@ export interface TalentTreeView {
sigil: string;
iconUrl?: string;
backgroundUrl: string;
nodes: readonly TalentNodeDefinition[];
nodes: readonly TalentUiNode[];
}
export interface TalentsPanelProps {
@@ -53,10 +55,10 @@ function TalentImage({ src, fallback }: { src?: string; fallback: string }) {
}
function nearestNode(
nodes: readonly TalentNodeDefinition[],
source: TalentNodeDefinition,
nodes: readonly TalentUiNode[],
source: TalentUiNode,
direction: MenuDirection,
): TalentNodeDefinition | null {
): TalentUiNode | null {
const vertical = direction === "up" || direction === "down";
const candidates = nodes.filter((candidate) => {
if (direction === "up") return candidate.row < source.row;
@@ -77,9 +79,9 @@ function nearestNode(
function failureText(
failure: TalentAllocationFailure | null,
node: TalentNodeDefinition,
node: TalentUiNode,
tree: TalentTreeView,
prerequisite: TalentNodeDefinition | null,
prerequisite: TalentUiNode | null,
): string {
if (!failure) return "Ready to learn";
if (failure === "max-rank") return "Maximum rank learned";
@@ -125,7 +127,7 @@ function TalentsDialog({
const nodeStateById = useMemo(() => new Map(allNodes.map((node) => {
const rank = Math.max(0, Math.min(node.maxRank, Math.trunc(ranks[node.id] ?? 0)));
const tree = treeByNodeId.get(node.id);
const rawFailure = talentAllocationFailure(ranks, classId, node.id, playerLevel);
const rawFailure = runtimeTalentAllocationFailure(ranks, classId, node.id, playerLevel);
const failure: TalentAllocationFailure | null = rank >= node.maxRank
? "max-rank"
: node.system !== "coa" && tree && tree.points < (node.row - 1) * 5
@@ -215,7 +217,7 @@ function TalentsDialog({
setDetailNodeId(nodeId);
};
const activateNode = (treeId: string, node: TalentNodeDefinition) => {
const activateNode = (treeId: string, node: TalentUiNode) => {
inspectNode(treeId, node.id);
if (!nodeStateById.get(node.id)?.failure) onInvest(node.id);
};
@@ -333,7 +335,7 @@ function TalentsDialog({
aria-label={label}
aria-disabled={state.failure !== null}
aria-describedby={detailNode?.id === node.id ? "talent-node-details" : undefined}
title={`${label} — ${talentDescriptionForRank(node, state.rank || 1)}`}
title={`${label} — ${talentUiDescriptionForRank(node, state.rank || 1)}`}
onFocus={() => inspectNode(tree.id, node.id)}
onPointerEnter={() => inspectNode(tree.id, node.id)}
onClick={() => activateNode(tree.id, node)}
@@ -368,11 +370,11 @@ function TalentsDialog({
<small className="talent-details__effect-rank">
{detailState.rank > 0 ? `Rank ${detailState.rank} effect` : "Rank 1 effect"}
</small>
<p>{talentDescriptionForRank(detailNode, detailState.rank || 1)}</p>
<p>{talentUiDescriptionForRank(detailNode, detailState.rank || 1)}</p>
{detailState.rank > 0 && detailState.rank < detailNode.maxRank && (
<>
<small className="talent-details__effect-rank">Next rank</small>
<p>{talentDescriptionForRank(detailNode, detailState.rank + 1)}</p>
<p>{talentUiDescriptionForRank(detailNode, detailState.rank + 1)}</p>
</>
)}
{(detailNode.row > 1 || prerequisite || detailNode.system === "coa") && (