Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -0,0 +1,244 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyAura, type ActiveAura, type AuraDefinition } from "./combatAuras";
|
||||
import {
|
||||
ENEMY_BLOCK_AURA_SOURCE_PINS,
|
||||
enemyBlockAuraContract,
|
||||
enemyBlockAuraInputDefinition,
|
||||
ordinaryCreatureSelfTargetCriticalBlockAuraDefinition,
|
||||
type EnemyNpcCriticalBlockImportProof,
|
||||
enemyNpcBlockValueAfterCritical,
|
||||
enemyNpcCriticalBlockChanceForRoll,
|
||||
resolveEnemyNpcBlockAuraInputs,
|
||||
supportedEnemyBlockAuraDefinition,
|
||||
SPELL_AURA_IGNORE_HIT_DIRECTION,
|
||||
SPELL_AURA_MOD_BLOCK_CRIT_CHANCE,
|
||||
SPELL_AURA_MOD_BLOCK_PERCENT,
|
||||
} from "./enemyBlockAuras";
|
||||
|
||||
function addAura(
|
||||
auras: readonly ActiveAura[],
|
||||
definition: AuraDefinition,
|
||||
targetId: string,
|
||||
now: number,
|
||||
): readonly ActiveAura[] {
|
||||
return applyAura(auras, { definition, sourceId: "source", targetId, now }).auras;
|
||||
}
|
||||
|
||||
function ordinaryCreatureSelfTargetProof(id = "ordinary-creature-47294"): EnemyNpcCriticalBlockImportProof {
|
||||
return {
|
||||
defenderId: id,
|
||||
casterId: id,
|
||||
targetId: id,
|
||||
defenderKind: "ordinary-creature",
|
||||
isNativeDefender: false,
|
||||
isSummonedDefender: false,
|
||||
isCharacterDefender: false,
|
||||
aura107Applicability: "azerothcore-e822d718-default-spellmod-path",
|
||||
};
|
||||
}
|
||||
|
||||
describe("source-bound enemy NPC block auras", () => {
|
||||
it("pins the exact profiles and preserves their aura types, amounts, and durations", () => {
|
||||
expect(ENEMY_BLOCK_AURA_SOURCE_PINS.wow335.spellDbcSha256)
|
||||
.toBe("57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c");
|
||||
expect(ENEMY_BLOCK_AURA_SOURCE_PINS.ascension.spellDbcSha256)
|
||||
.toBe("2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce");
|
||||
expect(ENEMY_BLOCK_AURA_SOURCE_PINS.epoch.spellDbcSha256)
|
||||
.toBe("d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3");
|
||||
|
||||
for (const profile of ["wow335", "ascension", "epoch"] as const) {
|
||||
expect(enemyBlockAuraContract(3419, profile)).toMatchObject({
|
||||
durationMs: 6_000,
|
||||
effects: [{ effectType: 6, auraType: SPELL_AURA_MOD_BLOCK_PERCENT, basePoints: 75 }],
|
||||
blockInputs: { blockChanceAuraPercent: 75 },
|
||||
});
|
||||
}
|
||||
|
||||
for (const [profile, chance] of [["wow335", 20], ["epoch", 20], ["ascension", 100]] as const) {
|
||||
const criticalBlock = enemyBlockAuraContract(47294, profile)!;
|
||||
expect(criticalBlock).toMatchObject({
|
||||
durationMs: null,
|
||||
signature: { durationMs: -1 },
|
||||
blockInputs: { criticalBlockChancePercent: chance },
|
||||
});
|
||||
expect(criticalBlock.effects.map(({ auraType, basePoints, miscValue }) => (
|
||||
[auraType, basePoints, miscValue]
|
||||
))).toEqual(profile === "ascension"
|
||||
? [[SPELL_AURA_MOD_BLOCK_CRIT_CHANCE, 100, 0], [107, 4, 7], [107, 8, 3]]
|
||||
: [[SPELL_AURA_MOD_BLOCK_CRIT_CHANCE, chance, 0], [107, 5, 7]]);
|
||||
expect(criticalBlock.unsupportedEffects.map(({ auraType, basePoints, miscValue }) => (
|
||||
[auraType, basePoints, miscValue]
|
||||
))).toEqual(profile === "ascension" ? [[107, 4, 7], [107, 8, 3]] : [[107, 5, 7]]);
|
||||
}
|
||||
|
||||
const wowDeterrence = enemyBlockAuraContract(67801, "wow335")!;
|
||||
expect(wowDeterrence).toMatchObject({
|
||||
durationMs: 5_000,
|
||||
blockInputs: { ignoresHitDirection: true },
|
||||
});
|
||||
expect(wowDeterrence.effects.map(({ auraType, basePoints }) => [auraType, basePoints]))
|
||||
.toEqual([[SPELL_AURA_IGNORE_HIT_DIRECTION, 100], [185, -100]]);
|
||||
expect(enemyBlockAuraContract(67801, "ascension")?.durationMs).toBe(60_000);
|
||||
expect(enemyBlockAuraContract(667801, "ascension")?.durationMs).toBe(5_000);
|
||||
expect(enemyBlockAuraContract(1167801, "ascension")?.effects[0]).toMatchObject({
|
||||
auraType: SPELL_AURA_IGNORE_HIT_DIRECTION,
|
||||
basePoints: 100,
|
||||
});
|
||||
expect(enemyBlockAuraContract(47929, "wow335")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("only imports complete aura definitions and keeps input-only siblings explicit", () => {
|
||||
const improvedBlocking = enemyBlockAuraContract(3419, "epoch")!;
|
||||
expect(supportedEnemyBlockAuraDefinition(improvedBlocking)).toMatchObject({
|
||||
id: "enemy-source-spell-3419",
|
||||
utilityTags: ["enemy-npc-block-aura:51:75"],
|
||||
});
|
||||
for (const profile of ["wow335", "ascension", "epoch"] as const) {
|
||||
expect(supportedEnemyBlockAuraDefinition(enemyBlockAuraContract(47294, profile)!)).toBeUndefined();
|
||||
}
|
||||
expect(supportedEnemyBlockAuraDefinition(enemyBlockAuraContract(67801, "wow335")!)).toBeUndefined();
|
||||
|
||||
const definition = enemyBlockAuraInputDefinition(enemyBlockAuraContract(47295, "epoch")!);
|
||||
expect(definition).toMatchObject({
|
||||
id: "enemy-source-spell-47295",
|
||||
name: "Critical Block",
|
||||
durationMs: null,
|
||||
disposition: "buff",
|
||||
utilityTags: ["enemy-npc-block-aura:253:40"],
|
||||
});
|
||||
expect(enemyBlockAuraInputDefinition(enemyBlockAuraContract(67801, "epoch")!).utilityTags)
|
||||
.toContain("enemy-npc-block-aura:288:0");
|
||||
});
|
||||
|
||||
it("imports reviewed Critical Block rows only for an ordinary Creature self-target proof", () => {
|
||||
const expectedChances = {
|
||||
wow335: [20, 40, 60],
|
||||
ascension: [100, 100, 100],
|
||||
epoch: [20, 40, 60],
|
||||
} as const;
|
||||
|
||||
for (const profile of ["wow335", "ascension", "epoch"] as const) {
|
||||
for (const [rankIndex, spellId] of [47294, 47295, 47296].entries()) {
|
||||
const contract = enemyBlockAuraContract(spellId, profile)!;
|
||||
const imported = ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
contract,
|
||||
ordinaryCreatureSelfTargetProof(),
|
||||
);
|
||||
expect(imported).toMatchObject({
|
||||
id: `enemy-source-spell-${spellId}`,
|
||||
name: "Critical Block",
|
||||
durationMs: null,
|
||||
disposition: "buff",
|
||||
utilityTags: [`enemy-npc-block-aura:${SPELL_AURA_MOD_BLOCK_CRIT_CHANCE}:${expectedChances[profile][rankIndex]}`],
|
||||
});
|
||||
// The generic complete-spell importer remains closed for these rows.
|
||||
expect(supportedEnemyBlockAuraDefinition(contract)).toBeUndefined();
|
||||
}
|
||||
}
|
||||
|
||||
const proof = ordinaryCreatureSelfTargetProof();
|
||||
const validContract = enemyBlockAuraContract(47294, "wow335")!;
|
||||
const invalidProofs: readonly unknown[] = [
|
||||
null,
|
||||
{},
|
||||
{ ...proof, defenderKind: "player" },
|
||||
{ ...proof, isNativeDefender: true },
|
||||
{ ...proof, isSummonedDefender: true },
|
||||
{ ...proof, isCharacterDefender: true },
|
||||
{ ...proof, aura107Applicability: "custom-server-script" },
|
||||
{ ...proof, defenderId: "" },
|
||||
{ ...proof, casterId: "different-caster" },
|
||||
{ ...proof, targetId: "different-target" },
|
||||
];
|
||||
for (const invalidProof of invalidProofs) {
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
validContract,
|
||||
invalidProof as EnemyNpcCriticalBlockImportProof,
|
||||
)).toBeUndefined();
|
||||
}
|
||||
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(undefined, proof)).toBeUndefined();
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(null, proof)).toBeUndefined();
|
||||
const invalidContracts: readonly unknown[] = [
|
||||
{},
|
||||
{ ...validContract, profile: "unreviewed-profile" },
|
||||
{ ...validContract, blockInputs: null },
|
||||
{ ...validContract, signature: null },
|
||||
];
|
||||
for (const invalidContract of invalidContracts) {
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
invalidContract as typeof validContract,
|
||||
proof,
|
||||
)).toBeUndefined();
|
||||
}
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
enemyBlockAuraContract(67801, "wow335"),
|
||||
proof,
|
||||
)).toBeUndefined();
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
enemyBlockAuraContract(3419, "wow335"),
|
||||
proof,
|
||||
)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("fails closed when a Critical Block raw source signature drifts", () => {
|
||||
const contract = enemyBlockAuraContract(47294, "ascension")!;
|
||||
const proof = ordinaryCreatureSelfTargetProof();
|
||||
const changedRawSignature = {
|
||||
...contract,
|
||||
signature: {
|
||||
...contract.signature,
|
||||
effects: contract.signature.effects.map((sourceEffect, index) => (
|
||||
index === 2 ? { ...sourceEffect, miscValue: 7 } : sourceEffect
|
||||
)),
|
||||
},
|
||||
};
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
changedRawSignature,
|
||||
proof,
|
||||
)).toBeUndefined();
|
||||
|
||||
const changedContractEffects = {
|
||||
...contract,
|
||||
effects: contract.effects.map((sourceEffect, index) => (
|
||||
index === 1 ? { ...sourceEffect, basePoints: 99 } : sourceEffect
|
||||
)),
|
||||
};
|
||||
expect(ordinaryCreatureSelfTargetCriticalBlockAuraDefinition(
|
||||
changedContractEffects,
|
||||
proof,
|
||||
)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("sums target-local active aura inputs and ignores expired or unrelated auras", () => {
|
||||
let auras: readonly ActiveAura[] = [];
|
||||
auras = addAura(auras, enemyBlockAuraInputDefinition(enemyBlockAuraContract(3419, "epoch")!), "mob-a", 100);
|
||||
auras = addAura(auras, enemyBlockAuraInputDefinition(enemyBlockAuraContract(47294, "epoch")!), "mob-a", 100);
|
||||
auras = addAura(auras, enemyBlockAuraInputDefinition(enemyBlockAuraContract(67801, "epoch")!), "mob-a", 100);
|
||||
auras = addAura(auras, enemyBlockAuraInputDefinition(enemyBlockAuraContract(47296, "epoch")!), "mob-b", 100);
|
||||
|
||||
const expiry = enemyBlockAuraInputDefinition({
|
||||
...enemyBlockAuraContract(47295, "epoch")!,
|
||||
durationMs: 10,
|
||||
});
|
||||
auras = addAura(auras, expiry, "mob-a", 100);
|
||||
|
||||
expect(resolveEnemyNpcBlockAuraInputs({ auras, targetId: "mob-a", now: 111 })).toEqual({
|
||||
blockChanceAuraPercent: 75,
|
||||
criticalBlockChancePercent: 20,
|
||||
ignoresHitDirection: true,
|
||||
});
|
||||
expect(resolveEnemyNpcBlockAuraInputs({ auras, targetId: "mob-a", now: 109 })?.criticalBlockChancePercent)
|
||||
.toBe(60);
|
||||
});
|
||||
|
||||
it("adapts critical-block chance to integer roll_chance_i and doubles only a successful block value", () => {
|
||||
expect(enemyNpcCriticalBlockChanceForRoll(19.9)).toBe(19);
|
||||
expect(enemyNpcCriticalBlockChanceForRoll(-2.7)).toBe(-2);
|
||||
expect(enemyNpcCriticalBlockChanceForRoll(Number.NaN)).toBeNull();
|
||||
expect(enemyNpcBlockValueAfterCritical(39, false)).toBe(39);
|
||||
expect(enemyNpcBlockValueAfterCritical(39, true)).toBe(78);
|
||||
expect(enemyNpcBlockValueAfterCritical(Number.MAX_SAFE_INTEGER, true)).toBeNull();
|
||||
expect(enemyNpcBlockValueAfterCritical(-1, true)).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user