From cbce49b2981ccf74c55f320ac1f9dba3fd03341d Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sun, 5 Jul 2026 12:12:37 +0900 Subject: [PATCH] Filter campaign history roster references --- .../verify-campaign-save-normalization.mjs | 11 +++++---- src/game/state/campaignState.ts | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/scripts/verify-campaign-save-normalization.mjs b/scripts/verify-campaign-save-normalization.mjs index 25e5d6a..0d47d61 100644 --- a/scripts/verify-campaign-save-normalization.mjs +++ b/scripts/verify-campaign-save-normalization.mjs @@ -444,6 +444,7 @@ try { step: 'fourth-camp', activeSaveSlot: 1, gold: 320, + roster: alliedFirstBattleUnits, firstBattleReport: { battleId: 'first-battle-zhuo-commandery', battleTitle: ' ', @@ -607,6 +608,8 @@ try { updatedAt: '2026-07-04T01:00:00.000Z', step: 'fifth-camp', latestBattleId: 'missing-history-entry', + roster: alliedFirstBattleUnits, + bonds: firstScenario.bonds, battleHistory: { 'wrong-history-key': { battleId: 'first-battle-zhuo-commandery', @@ -655,7 +658,7 @@ try { })) ], bonds: [ - { id: 'oath-bond', title: 'Oath Bond', level: '2', exp: '22', battleExp: '4' }, + { id: firstScenario.bonds[0].id, title: firstScenario.bonds[0].title, level: '2', exp: '22', battleExp: '4' }, { id: '', title: 'Broken Bond' }, ...Array.from({ length: 120 }, (_, index) => ({ id: `history-bond-${index}`, @@ -745,14 +748,14 @@ try { malformedHistory.battleHistory['first-battle-zhuo-commandery']?.objectives[0].rewardGold === 80 && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.objectives[0].targetTile?.x === 4 && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.objectives[0].status === undefined && - malformedHistory.battleHistory['first-battle-zhuo-commandery']?.units.length === 96 && + malformedHistory.battleHistory['first-battle-zhuo-commandery']?.units.length === 1 && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.units[0].level === 4 && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.units[0].equipment.weapon.itemId === 'training-sword' && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.units[0].equipment.armor.itemId === 'cloth-armor' && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.units[0].equipment.accessory.itemId === 'grain-pouch' && - malformedHistory.battleHistory['first-battle-zhuo-commandery']?.bonds.length === 96 && + malformedHistory.battleHistory['first-battle-zhuo-commandery']?.bonds.length === 1 && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.bonds[0].battleExp === 4 && - malformedHistory.battleHistory['first-battle-zhuo-commandery']?.reserveTraining?.length === 96 && + malformedHistory.battleHistory['first-battle-zhuo-commandery']?.reserveTraining?.length === 1 && malformedHistory.battleHistory['first-battle-zhuo-commandery']?.reserveTraining?.[0].focusId === 'balanced', `Expected nested battle history progress arrays to filter invalid entries and normalize numbers: ${JSON.stringify(malformedHistory)}` ); diff --git a/src/game/state/campaignState.ts b/src/game/state/campaignState.ts index 4fb9042..c68fdda 100644 --- a/src/game/state/campaignState.ts +++ b/src/game/state/campaignState.ts @@ -864,6 +864,13 @@ function normalizeCampaignState(state: Partial): CampaignState { normalized.sortieItemAssignments = normalizeCampaignSortieItemAssignments(recordOrEmpty(normalized.sortieItemAssignments), sortieUnitFilter); normalized.reserveTrainingFocus = normalizeReserveTrainingFocusId(normalized.reserveTrainingFocus); normalized.battleHistory = normalizeBattleHistory(normalized.battleHistory); + if (sortieUnitFilter) { + normalized.battleHistory = filterBattleHistoryRosterReferences( + normalized.battleHistory, + sortieUnitFilter, + new Set(normalized.bonds.map((bond) => bond.id)) + ); + } normalized.latestBattleId = normalizeLatestBattleId(normalized.latestBattleId, normalized.battleHistory); normalized.firstBattleReport = normalizeFirstBattleReport(normalized.firstBattleReport); if (normalized.firstBattleReport && sortieUnitFilter) { @@ -993,6 +1000,7 @@ function normalizeLatestBattleId(value: unknown, battleHistory: Record): FirstBattleReport { const filtered = { ...report, + units: report.units.filter((unit) => unit.faction !== 'ally' || rosterUnitIds.has(unit.id)), bonds: report.bonds.filter((bond) => bond.unitIds.every((unitId) => rosterUnitIds.has(unitId))) }; if (filtered.mvp && !rosterUnitIds.has(filtered.mvp.unitId)) { @@ -1001,6 +1009,22 @@ function filterFirstBattleReportRosterReferences(report: FirstBattleReport, rost return filtered; } +function filterBattleHistoryRosterReferences( + history: Record, + rosterUnitIds: Set, + bondIds: Set +): Record { + return Object.entries(history).reduce>((filteredHistory, [battleId, settlement]) => { + filteredHistory[battleId] = { + ...settlement, + units: settlement.units.filter((unit) => rosterUnitIds.has(unit.unitId)), + bonds: bondIds.size > 0 ? settlement.bonds.filter((bond) => bondIds.has(bond.id)) : settlement.bonds, + reserveTraining: settlement.reserveTraining?.filter((entry) => rosterUnitIds.has(entry.unitId)) + }; + return filteredHistory; + }, {}); +} + function normalizeCampaignBattleSettlement(value: unknown): CampaignBattleSettlement | undefined { if (!isPlainObject(value)) { return undefined;