95 lines
4.9 KiB
TypeScript
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 },
|
|
]),
|
|
});
|
|
});
|
|
});
|