From 11e42fd54f5c391690cfa9ddcfd63a4d278e5bab Mon Sep 17 00:00:00 2001 From: Wickedness Date: Sun, 5 Jul 2026 13:57:44 +0900 Subject: [PATCH] Validate battle save bond state --- scripts/verify-battle-save-normalization.mjs | 2 ++ src/game/state/battleSaveState.ts | 8 +++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/verify-battle-save-normalization.mjs b/scripts/verify-battle-save-normalization.mjs index 308ba2f..680c560 100644 --- a/scripts/verify-battle-save-normalization.mjs +++ b/scripts/verify-battle-save-normalization.mjs @@ -83,12 +83,14 @@ try { ['duplicate bond id', { bonds: [validState.bonds[0], { ...validState.bonds[0], unitIds: ['guan-yu', 'liu-bei'] }] }], ['too many bonds', { bonds: Array.from({ length: 129 }, (_, index) => ({ ...validState.bonds[0], id: `bond-${index}` })) }], ['unknown bond unit id', { bonds: [{ ...validState.bonds[0], unitIds: ['liu-bei', 'ghost-unit'] }] }], + ['self bond unit ids', { bonds: [{ ...validState.bonds[0], unitIds: ['liu-bei', 'liu-bei'] }] }], ['invalid bond level', { bonds: [{ ...validState.bonds[0], level: 0 }] }], ['too high bond level', { bonds: [{ ...validState.bonds[0], level: 101 }] }], ['invalid bond exp', { bonds: [{ ...validState.bonds[0], exp: -1 }] }], ['invalid bond exp threshold', { bonds: [{ ...validState.bonds[0], level: 1, exp: 100 }] }], ['invalid max-level bond exp threshold', { bonds: [{ ...validState.bonds[0], level: 100, exp: 101 }] }], ['invalid bond battle exp', { bonds: [{ ...validState.bonds[0], battleExp: 1.5 }] }], + ['too high bond battle exp', { bonds: [{ ...validState.bonds[0], battleExp: 1000000 }] }], ['invalid item stock count', { itemStocks: { 'liu-bei': { bean: -1 } } }], ['too many item stock count', { itemStocks: { 'liu-bei': { bean: 4, wine: 2 } } }], ['unknown item stock unit id', { itemStocks: { 'ghost-unit': { bean: 1 } } }], diff --git a/src/game/state/battleSaveState.ts b/src/game/state/battleSaveState.ts index 3dfd549..e008cf3 100644 --- a/src/game/state/battleSaveState.ts +++ b/src/game/state/battleSaveState.ts @@ -95,6 +95,7 @@ const maxBattleUnitStatValue = 999999; const maxBattleUnitHp = 9999; const maxBattleUnitAttack = 9999; const maxBattleUnitMove = 99; +const maxBattleBondBattleExp = 999999; const maxStatusKindsPerUnit = 2; const maxBattleItemStockById: Record = { bean: 3, @@ -181,10 +182,6 @@ function isNonNegativeFiniteNumber(value: unknown) { return typeof value === 'number' && Number.isFinite(value) && value >= 0; } -function isNonNegativeInteger(value: unknown) { - return Number.isInteger(value) && Number(value) >= 0; -} - function isFiniteNumber(value: unknown) { return typeof value === 'number' && Number.isFinite(value); } @@ -352,9 +349,10 @@ function isBondArray(value: unknown, options: BattleSaveValidationOptions) { bond.id.length > 0 && Array.isArray(bond.unitIds) && bond.unitIds.length === 2 && + bond.unitIds[0] !== bond.unitIds[1] && bond.unitIds.every((unitId) => typeof unitId === 'string' && isKnownUnitId(unitId, options)) && isValidBondProgress(bond.level, bond.exp) && - isNonNegativeInteger(bond.battleExp) + isIntegerInRange(bond.battleExp, 0, maxBattleBondBattleExp) ) ); }