feat: add selectable core resonance pairs

This commit is contained in:
2026-07-11 22:05:33 +09:00
parent 7d3c49ac0b
commit 51529e51c2
9 changed files with 1693 additions and 100 deletions

View File

@@ -7,7 +7,7 @@ const server = await createServer({
});
try {
const { isValidBattleSaveState, normalizeBattleSaveSlot, parseBattleSaveState } = await server.ssrLoadModule(
const { isValidBattleSaveState, normalizeBattleSaveSlot, normalizeBattleSaveState, parseBattleSaveState } = await server.ssrLoadModule(
'/src/game/state/battleSaveState.ts'
);
@@ -61,6 +61,88 @@ try {
isValidBattleSaveState(legacyStateWithoutSortieOrder, options),
'Expected legacy battle saves without a sortie order to remain valid.'
);
const validCoreResonanceState = {
...validState,
sortieResonanceBondId: 'taoyuan',
bonds: validState.bonds.map((bond) => ({ ...bond, unitIds: [...bond.unitIds], level: 30 })),
coreResonanceStats: {
attempts: 3,
successes: 1,
failures: 2,
additionalDamage: 9
}
};
assert(
isValidBattleSaveState(validCoreResonanceState, options),
'Expected a deployed level-30 core resonance pair and its pursuit totals to pass validation.'
);
const parsedCoreResonanceState = parseBattleSaveState(JSON.stringify(validCoreResonanceState), options);
assert(
parsedCoreResonanceState?.sortieResonanceBondId === 'taoyuan' &&
JSON.stringify(parsedCoreResonanceState.coreResonanceStats) === JSON.stringify(validCoreResonanceState.coreResonanceStats),
'Expected core resonance selection and pursuit totals to round-trip.'
);
const deepClonedCoreResonanceState = normalizeBattleSaveState(validCoreResonanceState, options);
assert(
deepClonedCoreResonanceState &&
deepClonedCoreResonanceState !== validCoreResonanceState &&
deepClonedCoreResonanceState.bonds !== validCoreResonanceState.bonds &&
deepClonedCoreResonanceState.bonds[0].unitIds !== validCoreResonanceState.bonds[0].unitIds &&
deepClonedCoreResonanceState.coreResonanceStats !== validCoreResonanceState.coreResonanceStats,
'Expected battle-save normalization to return a deep clone.'
);
deepClonedCoreResonanceState.coreResonanceStats.additionalDamage = 99;
deepClonedCoreResonanceState.bonds[0].unitIds[0] = 'mutated-unit';
assert(
validCoreResonanceState.coreResonanceStats.additionalDamage === 9 &&
validCoreResonanceState.bonds[0].unitIds[0] === 'liu-bei',
'Expected normalized core resonance state mutations not to leak into the source state.'
);
const normalizedUnsafeCoreStats = parseBattleSaveState(JSON.stringify({
...validCoreResonanceState,
coreResonanceStats: {
attempts: 3.8,
successes: 1.9,
failures: -4,
additionalDamage: -9.5
}
}), options);
assert(
JSON.stringify(normalizedUnsafeCoreStats?.coreResonanceStats) === JSON.stringify({
attempts: 3,
successes: 1,
failures: 2,
additionalDamage: 0
}),
'Expected negative and fractional core resonance totals to normalize to safe integers.'
);
const normalizedUnknownCoreBond = parseBattleSaveState(JSON.stringify({
...validCoreResonanceState,
sortieResonanceBondId: 'missing-bond'
}), options);
assert(
normalizedUnknownCoreBond &&
normalizedUnknownCoreBond.sortieResonanceBondId === undefined &&
normalizedUnknownCoreBond.coreResonanceStats === undefined,
'Expected an unknown core resonance bond and its unrelated totals to be removed safely.'
);
const normalizedUnderleveledCoreBond = parseBattleSaveState(JSON.stringify({
...validCoreResonanceState,
bonds: validState.bonds.map((bond) => ({ ...bond, unitIds: [...bond.unitIds], level: 29 }))
}), options);
assert(
normalizedUnderleveledCoreBond &&
normalizedUnderleveledCoreBond.sortieResonanceBondId === undefined &&
normalizedUnderleveledCoreBond.coreResonanceStats === undefined,
'Expected an underleveled core resonance pair to be cleared during normalization.'
);
assert(
!isValidBattleSaveState({
...validCoreResonanceState,
coreResonanceStats: { attempts: 2, successes: 1.5, failures: 1, additionalDamage: -1 }
}, options),
'Expected direct validation to reject unsafe core resonance totals before normalization.'
);
const validSortieStatsState = {
...validState,
battleStats: {