diff --git a/scripts/verify-battle-save-normalization.mjs b/scripts/verify-battle-save-normalization.mjs index 521cf3e..388b467 100644 --- a/scripts/verify-battle-save-normalization.mjs +++ b/scripts/verify-battle-save-normalization.mjs @@ -16,7 +16,8 @@ try { mapWidth: 12, mapHeight: 8, validUnitIds: new Set(['liu-bei', 'guan-yu', 'rebel-1']), - validUsableIds: new Set(['roar', 'fireTactic', 'aid']) + validUsableIds: new Set(['roar', 'fireTactic', 'aid', 'bean', 'salve', 'wine']), + validItemIds: new Set(['bean', 'salve', 'wine']) }; const validState = createValidBattleSaveState(); const patchUnit = (index, patch) => validState.units.map((unit, unitIndex) => (unitIndex === index ? { ...unit, ...patch } : unit)); @@ -51,6 +52,7 @@ try { ['unknown bond unit id', { bonds: [{ ...validState.bonds[0], unitIds: ['liu-bei', 'ghost-unit'] }] }], ['invalid item stock count', { itemStocks: { 'liu-bei': { bean: -1 } } }], ['unknown item stock unit id', { itemStocks: { 'ghost-unit': { bean: 1 } } }], + ['unknown item stock item id', { itemStocks: { 'liu-bei': { phantomItem: 1 } } }], ['invalid buff turns', { battleBuffs: [{ ...validState.battleBuffs[0], turns: 0 }] }], ['unknown buff unit id', { battleBuffs: [{ ...validState.battleBuffs[0], unitId: 'ghost-unit' }] }], ['invalid status kind', { battleStatuses: [{ ...validState.battleStatuses[0], kind: 'poison' }] }], diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index e6a305f..319687b 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -11350,7 +11350,12 @@ export class BattleScene extends Phaser.Scene { mapWidth: battleMap.width, mapHeight: battleMap.height, validUnitIds: new Set(battleUnits.map((unit) => unit.id)), - validUsableIds: new Set(Object.keys(usableCatalog)) + validUsableIds: new Set(Object.keys(usableCatalog)), + validItemIds: new Set( + Object.values(usableCatalog) + .filter((usable) => usable.command === 'item') + .map((usable) => usable.id) + ) }); } diff --git a/src/game/state/battleSaveState.ts b/src/game/state/battleSaveState.ts index bedcd0f..c053a67 100644 --- a/src/game/state/battleSaveState.ts +++ b/src/game/state/battleSaveState.ts @@ -73,6 +73,7 @@ type BattleSaveValidationOptions = { mapHeight?: number; validUnitIds?: ReadonlySet; validUsableIds?: ReadonlySet; + validItemIds?: ReadonlySet; }; const unitDirections = new Set(['south', 'east', 'north', 'west']); @@ -127,7 +128,7 @@ export function isValidBattleSaveState(state: unknown, options: BattleSaveValida } if ( - !isOptionalNestedCountRecord(state.itemStocks, options) || + !isOptionalItemStockRecord(state.itemStocks, options) || !isOptionalBuffArray(state.battleBuffs, options) || !isOptionalStatusArray(state.battleStatuses, options) || !isOptionalStatsRecord(state.battleStats, options) || @@ -267,7 +268,7 @@ function isBondArray(value: unknown, options: BattleSaveValidationOptions) { ); } -function isOptionalNestedCountRecord(value: unknown, options: BattleSaveValidationOptions) { +function isOptionalItemStockRecord(value: unknown, options: BattleSaveValidationOptions) { if (value === undefined) { return true; } @@ -280,7 +281,10 @@ function isOptionalNestedCountRecord(value: unknown, options: BattleSaveValidati ([unitId, stocks]) => isKnownUnitId(unitId, options) && isRecord(stocks) && - Object.values(stocks).every((count) => Number.isInteger(count) && Number(count) >= 0) + Object.entries(stocks).every( + ([itemId, count]) => + (!options.validItemIds || options.validItemIds.has(itemId)) && Number.isInteger(count) && Number(count) >= 0 + ) ); }