Files
healer-man/src/game/romNativeNpcEquipment.test.ts
T
2026-10-04 13:13:35 -04:00

95 lines
4.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
resolveRomNativeNpcEquipment,
romNativeNpcEquipmentRecord,
} from "./romNativeNpcEquipment";
describe("native RoM NPC source equipment", () => {
it("preserves the five weighted Barren Caves choices and resolves their exact item rows", () => {
const sources = [101_459, 101_460, 101_461].map((npcId) => romNativeNpcEquipmentRecord(npcId));
expect(sources.every(Boolean)).toBe(true);
expect(sources[0]?.mainHandCandidates.map((candidate) => candidate.sourceItemId)).toEqual([
210_056, 210_056, 210_056, 210_056, 210_056,
]);
expect(sources[1]?.mainHandCandidates.map((candidate) => candidate.sourceItemId)).toEqual([
210_061, 210_061, 210_061, 210_061, 210_061,
]);
expect(sources[2]?.offHandCandidates.map((candidate) => candidate.sourceItemId)).toEqual([
210_666, 210_666, 210_666, 210_666, 210_666,
]);
for (const source of sources) {
expect(source?.mainHandCandidates.map((candidate) => candidate.selectionWeightPercent)).toEqual([20, 20, 20, 20, 20]);
expect(source?.offHandCandidates.map((candidate) => candidate.selectionWeightPercent)).toEqual([20, 20, 20, 20, 20]);
}
const caveGuard = resolveRomNativeNpcEquipment(101_459, { selectionSeed: "actor-cave-1" });
const caveArcher = resolveRomNativeNpcEquipment(101_460, { selectionSeed: "actor-cave-1" });
const caveWarden = resolveRomNativeNpcEquipment(101_461, { selectionSeed: "actor-cave-1" });
expect(caveGuard.status).toBe("supported");
expect(caveArcher.status).toBe("supported");
expect(caveWarden.status).toBe("supported");
if (caveGuard.status !== "supported" || caveArcher.status !== "supported" || caveWarden.status !== "supported") return;
expect(caveGuard.value.mainHand).toMatchObject({
sourceItemId: 210_056,
sourceCatalog: "weaponobject.db",
durable: 70,
refineLevel: 0,
attackRange: 20,
attackSpeed: 20,
eqTypeValuePairs: Array.from({ length: 10 }, (_, slot) => ({ slot, eqType: 0, value: 0 })),
dropAbilityIdRatePairs: Array.from({ length: 6 }, (_, slot) => ({ slot, attributeId: 0, rate: 0 })),
});
expect(caveArcher.value.mainHand).toMatchObject({ sourceItemId: 210_061, durable: 55, attackSpeed: 20 });
expect(caveWarden.value.offHand).toMatchObject({ sourceItemId: 210_666, durable: 1426, gearPosition: 2, attackSpeed: 20 });
expect(caveGuard.value.wornItems[0]).toMatchObject({ fieldQuality: 100, fieldDurability: 10_000, fieldPowerQuality: 10, durabilityPowerRate: 1.2, wearPower: 1.2 });
expect(caveWarden.value.wornItems[0]).toMatchObject({ slot: "offHand", durabilityPowerRate: 0.2, wearPower: 0.2 });
});
it("selects deterministically from source weights without averaging or discarding candidate slots", () => {
const source = romNativeNpcEquipmentRecord(100_052);
expect(source?.mainHandCandidates.map((candidate) => candidate.sourceItemId)).toEqual([
210_059, 0, 210_059, 0, 210_059,
]);
expect(source?.mainHandCandidates.map((candidate) => candidate.selectionWeightPercent)).toEqual([20, 20, 20, 20, 20]);
const first = resolveRomNativeNpcEquipment(100_052, { selectionSeed: "same-actor" });
const repeated = resolveRomNativeNpcEquipment(100_052, { selectionSeed: "same-actor" });
expect(first.status).toBe("supported");
expect(repeated.status).toBe("supported");
if (first.status !== "supported" || repeated.status !== "supported") return;
expect(first.value.selectedCandidateIndices).toEqual(repeated.value.selectedCandidateIndices);
expect(first.value.selectedCandidateIndices.mainHand).toBeGreaterThanOrEqual(0);
expect(first.value.selectedCandidateIndices.mainHand).toBeLessThan(5);
const selected = resolveRomNativeNpcEquipment(100_052, {
mainHandCandidateIndex: 0,
offHandCandidateIndex: 1,
selectionSeed: "ignored-where-index-is-explicit",
});
expect(selected.status).toBe("supported");
if (selected.status !== "supported") return;
expect(selected.value.mainHand?.sourceItemId).toBe(210_059);
expect(selected.value.offHand).toBeNull();
expect(selected.value.selectedCandidateIndices).toEqual({ mainHand: 0, offHand: 1 });
});
it("resolves fixed BowEQ rows as source metadata while retaining exact ability pairs", () => {
const source = romNativeNpcEquipmentRecord(102_425);
expect(source?.bowEquipmentId).toBe(212_011);
const result = resolveRomNativeNpcEquipment(102_425, {
mainHandCandidateIndex: 0,
offHandCandidateIndex: 0,
});
expect(result.status).toBe("supported");
if (result.status !== "supported") return;
expect(result.value.bow).toMatchObject({
sourceItemId: 212_011,
sourceCatalog: "weaponobject.db",
eqTypeValuePairs: expect.arrayContaining([
{ slot: 0, eqType: 25, value: 19 },
{ slot: 1, eqType: 191, value: 7 },
]),
});
});
});