Guard source gear namespaces and retain recoverable legacy records (#9)
This commit is contained in:
1 parent
ab37006932
commit
e567910c04
23 files changed
+1203
-66
No files matched your search
@@ -30,6 +30,8 @@ import { subscribeCombatPresentation, type CombatPresentationEvent } from "./com
|
||||
import { loadCanonicalBenchmarkBuilds } from "./benchmark/benchmarkBuilds";
|
||||
import { runtimePartyTalentRanksForLevel } from "./partyTalentRuntime";
|
||||
import { talentModifiersForRanks } from "./talentModifiers";
|
||||
import type { InventoryItem } from "./lootTypes";
|
||||
import { resolvedEquipmentStats } from "./heirloomEquipment";
|
||||
import {
|
||||
ROGUE_DEADLY_POISON_DOSE_TAG,
|
||||
ROGUE_ENVENOM_BUFF_TAG,
|
||||
@@ -63,6 +65,31 @@ function stableUnit(seed: string): number {
|
||||
return (hash >>> 0) / 0x1_0000_0000;
|
||||
}
|
||||
|
||||
function categoryGearFixture(
|
||||
instanceId: string,
|
||||
contentCategory: InventoryItem["contentCategory"],
|
||||
romNative?: InventoryItem["stats"]["romNative"],
|
||||
): InventoryItem {
|
||||
return {
|
||||
contentCategory,
|
||||
instanceId,
|
||||
itemId: 900001,
|
||||
itemKey: instanceId,
|
||||
name: instanceId,
|
||||
quality: "rare",
|
||||
inventorySlot: "back",
|
||||
armorType: null,
|
||||
weaponType: null,
|
||||
itemLevel: 40,
|
||||
sourceItemLevel: 40,
|
||||
stats: { ...EMPTY_ITEM_STATS, stamina: 100, ...(romNative ? { romNative } : {}) },
|
||||
quantity: 1,
|
||||
sourceBossKey: "test-source",
|
||||
sourceBossName: "Test Source",
|
||||
acquiredAt: 1,
|
||||
};
|
||||
}
|
||||
|
||||
function paladinVindicationProcTime(
|
||||
sourceActorId: string,
|
||||
abilityId: string,
|
||||
@@ -1215,6 +1242,52 @@ describe("combat store", () => {
|
||||
expect(useCombatStore.getState().bossCards.counts["wow:lady anacondra"]?.normal).toBe(1);
|
||||
});
|
||||
|
||||
it("derives the owner namespace from the source class and accepts only validated native gear rewards", () => {
|
||||
const foreignWow = categoryGearFixture("foreign-wow", "wow");
|
||||
const missingNative = categoryGearFixture("rom-without-native", "rom");
|
||||
const missingCategory = categoryGearFixture("legacy-without-category", undefined);
|
||||
const nullCategory = categoryGearFixture("explicit-null-category", null);
|
||||
const nativeRom = categoryGearFixture("rom-native", "rom", { stamina: 4 });
|
||||
const sourceProfile = {
|
||||
classId: "rom-priest",
|
||||
categoryId: "wow",
|
||||
level: 40,
|
||||
inventory: [foreignWow, missingNative, missingCategory, nullCategory, nativeRom],
|
||||
equipment: { player: { back: foreignWow.instanceId, chest: missingNative.instanceId } },
|
||||
} as const;
|
||||
useCombatStore.getState().initializeCharacter(sourceProfile);
|
||||
|
||||
expect(useCombatStore.getState().contentCategoryId).toBe("rom");
|
||||
expect(useCombatStore.getState().inventory.map((item) => item.instanceId)).toEqual([nativeRom.instanceId]);
|
||||
expect(useCombatStore.getState().equipment).toEqual({});
|
||||
expect(sourceProfile.inventory.map((item) => item.contentCategory)).toEqual(["wow", "rom", undefined, null, "rom"]);
|
||||
const expectedTrainingOnlyStats = resolvedEquipmentStats({}, [], {
|
||||
ownerId: "player",
|
||||
ownerKind: "player",
|
||||
classId: "rom-priest",
|
||||
secondaryClassId: null,
|
||||
specializationId: null,
|
||||
role: "healer",
|
||||
level: 40,
|
||||
});
|
||||
expect(useCombatStore.getState().gearStats).toEqual(expectedTrainingOnlyStats);
|
||||
|
||||
useCombatStore.getState().registerMob("gear-boundary", { name: "Gear Boundary", maxHealth: 1, hasLoot: true });
|
||||
const nativeLoot = categoryGearFixture("rom-loot", "rom", { agility: 2 });
|
||||
useCombatStore.setState((state) => {
|
||||
const mob = state.mobs["gear-boundary"]!;
|
||||
return { mobs: { ...state.mobs, "gear-boundary": {
|
||||
...mob,
|
||||
dead: true,
|
||||
health: 0,
|
||||
pendingLoot: [foreignWow, missingNative, missingCategory, nullCategory, nativeLoot],
|
||||
} } };
|
||||
});
|
||||
expect(useCombatStore.getState().lootMob("gear-boundary", 10_000)).toBe(true);
|
||||
expect(useCombatStore.getState().inventory.map((item) => item.instanceId))
|
||||
.toEqual([nativeRom.instanceId, nativeLoot.instanceId]);
|
||||
});
|
||||
|
||||
it("aggros every surviving packmate even when the pulled mob dies to the opening hit", () => {
|
||||
for (const [id, maxHealth] of [["one-shot:a", 1], ["one-shot:b", 100], ["outsider", 100]] as const) {
|
||||
useCombatStore.getState().registerMob(id, { name: id, maxHealth, xpReward: 0 });
|
||||
|
||||
Reference in new issue
Block a user