forked from phenom/healer-man
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
adaptRunewakerEnemyDamage,
|
|
resolveRunewakerNativeResolvedPower,
|
|
runewakerAttackDefenseRate,
|
|
runewakerOrgPower,
|
|
type RunewakerDamageFormulaSource,
|
|
} from "./runewakerCombatFormula";
|
|
|
|
function formula(
|
|
overrides: Partial<RunewakerDamageFormulaSource> = {},
|
|
): RunewakerDamageFormulaSource {
|
|
return {
|
|
schemaVersion: 1,
|
|
spellId: 492_289,
|
|
componentId: 502_503,
|
|
spellLevel: 6,
|
|
calculationPath: "physical",
|
|
powerKind: "source-ratio",
|
|
damagePower: -0.7,
|
|
fixedValue: 0,
|
|
dotBase: 0,
|
|
runtimeBaselineMultiplier: 0.85,
|
|
provenance: {
|
|
sourceFile: "MagicProcess.cpp",
|
|
physicalFunctionLine: 3366,
|
|
magicFunctionLine: 3651,
|
|
magicObjectDatabase: "magicobject.db",
|
|
},
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("RuneWaker combat formula adapter", () => {
|
|
it("preserves source ratio powers against HealerMan's explicit baseline", () => {
|
|
expect(adaptRunewakerEnemyDamage({ formula: formula(), baselineDamage: 100 })).toMatchObject({
|
|
amount: 70,
|
|
fidelity: "source-ratio-adapter",
|
|
appliedMultiplier: 0.7,
|
|
});
|
|
});
|
|
|
|
it("labels point-valued powers as scaled adapters instead of native damage", () => {
|
|
const result = adaptRunewakerEnemyDamage({
|
|
formula: formula({ powerKind: "source-points", damagePower: -300 }),
|
|
baselineDamage: 100,
|
|
});
|
|
expect(result).toMatchObject({ amount: 85, fidelity: "scaled-point-adapter" });
|
|
expect(result.unavailableSourceInputs).toContain("RuneWaker ATK or MATK");
|
|
expect(result.unavailableSourceInputs).toContain("RuneWaker global NPC/PvP/AoE/target damage rates");
|
|
});
|
|
|
|
it("fails closed when no damage family was proven", () => {
|
|
expect(adaptRunewakerEnemyDamage({
|
|
formula: formula({ powerKind: "unresolved", runtimeBaselineMultiplier: 0 }),
|
|
baselineDamage: 100,
|
|
})).toMatchObject({ amount: 0, fidelity: "unsupported" });
|
|
});
|
|
|
|
it("implements the preserved org-power and attack-defense expressions", () => {
|
|
expect(runewakerOrgPower(-100, 5, 10)).toBe(-150);
|
|
expect(runewakerAttackDefenseRate(400, 300)).toBe(1);
|
|
expect(runewakerAttackDefenseRate(0, 10_000)).toBe(0.2);
|
|
});
|
|
|
|
it("requires every native rate in the source-shaped resolved-power path", () => {
|
|
expect(resolveRunewakerNativeResolvedPower({
|
|
power: -100,
|
|
fixedValue: -0.5,
|
|
fixedAttributeValue: 20,
|
|
fixedDamageSkillLevelPercent: 10,
|
|
spellLevel: 5,
|
|
attackerPower: 400,
|
|
defenderPower: 300,
|
|
criticalMultiplier: 2,
|
|
levelRate: 1,
|
|
resistanceRate: 0.8,
|
|
pvpOrNpcDamageRate: 1,
|
|
areaPowerRate: 1,
|
|
areaDefenseRate: 1,
|
|
attackTargetRate: 1,
|
|
attackerOriginDefenseRate: 1,
|
|
sharedDamageRate: 1,
|
|
})).toBe(184);
|
|
});
|
|
});
|