From 65de2b30a3086872ae68a8df64a9623ef674a38d Mon Sep 17 00:00:00 2001 From: hided62 Date: Wed, 5 Aug 2026 03:04:25 +0000 Subject: [PATCH] fix: clone item inventory before nation level rewards --- .../src/turn/monthlyNationLevelAction.ts | 11 +++++++++-- .../test/monthlyNationLevelAction.test.ts | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/game-engine/src/turn/monthlyNationLevelAction.ts b/app/game-engine/src/turn/monthlyNationLevelAction.ts index f70781d..3880661 100644 --- a/app/game-engine/src/turn/monthlyNationLevelAction.ts +++ b/app/game-engine/src/turn/monthlyNationLevelAction.ts @@ -3,8 +3,10 @@ import { LogCategory, LogFormat, LogScope, + cloneItemInventory, countOccupiedUniqueItems, createItemModuleRegistry, + ensureItemInventory, equipNewItem, resolveUniqueConfig, type ItemModule, @@ -105,10 +107,15 @@ const giveRandomUniqueItem = (options: { } const item = options.rng.choiceUsingWeightPair(available); - const nextGeneral = options.world.getGeneralById(options.general.id); - if (!nextGeneral) { + const currentGeneral = options.world.getGeneralById(options.general.id); + if (!currentGeneral) { return false; } + const nextGeneral: TurnGeneral = { + ...currentGeneral, + role: { ...currentGeneral.role, items: { ...currentGeneral.role.items } }, + itemInventory: cloneItemInventory(ensureItemInventory(currentGeneral)), + }; equipNewItem(nextGeneral, item.slot, item.key, { ...(item.initialCharges === undefined ? {} : { charges: item.initialCharges }), }); diff --git a/app/game-engine/test/monthlyNationLevelAction.test.ts b/app/game-engine/test/monthlyNationLevelAction.test.ts index 0cfa575..8208cbf 100644 --- a/app/game-engine/test/monthlyNationLevelAction.test.ts +++ b/app/game-engine/test/monthlyNationLevelAction.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it, vi } from 'vitest'; import { + createItemInventoryFromSlots, ITEM_KEYS, LogCategory, LogScope, @@ -246,6 +247,19 @@ describe('UpdateNationLevel monthly action', () => { ); }); + it('rewards a unique item when the persisted inventory snapshot is frozen', async () => { + const { world, handler } = await buildHarness(0, 2); + world.updateGeneral(1, { + itemInventory: createItemInventoryFromSlots({ horse: null, weapon: null, book: null, item: null }), + }); + + await expect( + handler([], { year: 193, month: 2, startyear: 190, currentEventID: 1, turnTime: new Date() }, event) + ).resolves.toBeUndefined(); + + expect(world.getGeneralById(1)?.role.items.horse).toBe(uniqueHorse.key); + }); + it('does not downgrade or pay rewards when the qualifying city count is below the current level', async () => { const { world, reservedTurns, handler } = await buildHarness(3, 1);