From a1f925c1ca12fcb1e03e32a85546df51f8fee803 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sun, 5 Jul 2026 10:14:24 +0900 Subject: [PATCH] Normalize sortie supply assignments --- scripts/verify-campaign-save-normalization.mjs | 4 +++- src/game/scenes/BattleScene.ts | 15 ++------------- src/game/state/campaignState.ts | 16 +++++++++++++--- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/scripts/verify-campaign-save-normalization.mjs b/scripts/verify-campaign-save-normalization.mjs index 6036ca9..45b6873 100644 --- a/scripts/verify-campaign-save-normalization.mjs +++ b/scripts/verify-campaign-save-normalization.mjs @@ -80,7 +80,7 @@ try { selectedSortieUnitIds: { corrupted: true }, sortieFormationAssignments: 'front', sortieItemAssignments: { - 'liu-bei': { bean: '2', wine: -1 }, + 'liu-bei': { bean: '5', wine: -1, salve: '1', stone: '9' }, 'guan-yu': '2', 'zhang-fei': ['bean', '2'], '': { bean: 4 } @@ -110,6 +110,8 @@ try { malformed.inventory.bean === 3 && malformed.inventory.wine === undefined && malformed.sortieItemAssignments['liu-bei']?.bean === 2 && + malformed.sortieItemAssignments['liu-bei']?.salve === 1 && + malformed.sortieItemAssignments['liu-bei']?.stone === undefined && malformed.sortieItemAssignments['liu-bei']?.wine === undefined && malformed.sortieItemAssignments['guan-yu'] === undefined && malformed.sortieItemAssignments['zhang-fei'] === undefined && diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index a5c058a..18798bb 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -47,6 +47,7 @@ import { listCampaignSaveSlots, loadCampaignState, markCampaignStep, + normalizeCampaignSortieItemAssignments, saveCampaignState, setFirstBattleReport, type CampaignRewardSnapshot, @@ -3458,19 +3459,7 @@ export class BattleScene extends Phaser.Scene { } private normalizeLaunchSortieItemAssignments(assignments?: CampaignSortieItemAssignments) { - return Object.entries(assignments ?? {}).reduce((next, [unitId, stocks]) => { - const unitStocks = Object.entries(stocks ?? {}).reduce>((nextStocks, [itemId, count]) => { - const normalizedCount = Math.floor(Number(count)); - if (itemId && normalizedCount > 0) { - nextStocks[itemId] = normalizedCount; - } - return nextStocks; - }, {}); - if (Object.keys(unitStocks).length > 0) { - next[unitId] = unitStocks; - } - return next; - }, {}); + return normalizeCampaignSortieItemAssignments(assignments); } private effectiveSortieUnitIds(campaign?: CampaignState) { diff --git a/src/game/state/campaignState.ts b/src/game/state/campaignState.ts index eed51f0..bc98a7a 100644 --- a/src/game/state/campaignState.ts +++ b/src/game/state/campaignState.ts @@ -254,6 +254,12 @@ const defaultEquipmentBySlot: Record = { accessory: 'grain-pouch' }; +const sortieSupplyMaxByUsableId: Record = { + bean: 2, + wine: 1, + salve: 1 +}; + const campaignInventoryCaps: Record = { ['\uCF69']: 120, ['\uC0C1\uCC98\uC57D']: 80, @@ -826,7 +832,7 @@ function normalizeCampaignState(state: Partial): CampaignState { normalized.selectedSortieUnitIds = uniqueStrings(normalized.selectedSortieUnitIds) .filter((unitId) => !sortieUnitFilter || sortieUnitFilter.has(unitId)); normalized.sortieFormationAssignments = normalizeSortieFormationAssignments(recordOrEmpty(normalized.sortieFormationAssignments), sortieUnitFilter); - normalized.sortieItemAssignments = normalizeSortieItemAssignments(recordOrEmpty(normalized.sortieItemAssignments), sortieUnitFilter); + normalized.sortieItemAssignments = normalizeCampaignSortieItemAssignments(recordOrEmpty(normalized.sortieItemAssignments), sortieUnitFilter); normalized.reserveTrainingFocus = normalizeReserveTrainingFocusId(normalized.reserveTrainingFocus); normalized.battleHistory = normalizeBattleHistory(normalized.battleHistory); normalized.latestBattleId = normalizeLatestBattleId(normalized.latestBattleId, normalized.battleHistory); @@ -1022,16 +1028,20 @@ function normalizeReserveTrainingSnapshot(value: unknown): CampaignReserveTraini }; } -function normalizeSortieItemAssignments(assignments?: Record, allowedUnitIds?: Set) { +export function normalizeCampaignSortieItemAssignments(assignments?: Record, allowedUnitIds?: Set) { return Object.entries(assignments ?? {}).reduce((next, [unitId, stocks]) => { if (!unitId || (allowedUnitIds && !allowedUnitIds.has(unitId))) { return next; } const unitStocks = Object.entries(recordOrEmpty(stocks)).reduce>((nextStocks, [itemId, amount]) => { + const maxPerUnit = sortieSupplyMaxByUsableId[itemId]; + if (!maxPerUnit) { + return nextStocks; + } const normalizedAmount = normalizeNonNegativeInteger(amount); if (itemId && normalizedAmount > 0) { - nextStocks[itemId] = normalizedAmount; + nextStocks[itemId] = Math.min(maxPerUnit, normalizedAmount); } return nextStocks; }, {});