Harden sortie formation assignment recovery
This commit is contained in:
@@ -38,6 +38,7 @@ try {
|
|||||||
setFirstBattleReport
|
setFirstBattleReport
|
||||||
} = await server.ssrLoadModule('/src/game/state/campaignState.ts');
|
} = await server.ssrLoadModule('/src/game/state/campaignState.ts');
|
||||||
const { battleScenarios } = await server.ssrLoadModule('/src/game/data/battles.ts');
|
const { battleScenarios } = await server.ssrLoadModule('/src/game/data/battles.ts');
|
||||||
|
const { normalizeSortieFormationAssignments } = await server.ssrLoadModule('/src/game/data/sortieDeployment.ts');
|
||||||
|
|
||||||
storage.clear();
|
storage.clear();
|
||||||
const empty = loadCampaignState();
|
const empty = loadCampaignState();
|
||||||
@@ -73,6 +74,35 @@ try {
|
|||||||
cappedLaunchSupplies['unit-96'] === undefined,
|
cappedLaunchSupplies['unit-96'] === undefined,
|
||||||
`Expected launch sortie supplies without a roster filter to stay capped: ${JSON.stringify(cappedLaunchSupplies)}`
|
`Expected launch sortie supplies without a roster filter to stay capped: ${JSON.stringify(cappedLaunchSupplies)}`
|
||||||
);
|
);
|
||||||
|
const normalizedLaunchFormation = normalizeSortieFormationAssignments(
|
||||||
|
{
|
||||||
|
'liu-bei': 'front',
|
||||||
|
' liu-bei ': 'support',
|
||||||
|
'guan-yu': 'flank',
|
||||||
|
'ghost-unit': 'reserve',
|
||||||
|
'zhang-fei': 'broken',
|
||||||
|
['x'.repeat(97)]: 'front',
|
||||||
|
'': 'front'
|
||||||
|
},
|
||||||
|
new Set(['liu-bei', 'guan-yu'])
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
normalizedLaunchFormation['liu-bei'] === 'front' &&
|
||||||
|
normalizedLaunchFormation['guan-yu'] === 'flank' &&
|
||||||
|
normalizedLaunchFormation['ghost-unit'] === undefined &&
|
||||||
|
normalizedLaunchFormation['zhang-fei'] === undefined &&
|
||||||
|
normalizedLaunchFormation['x'.repeat(97)] === undefined,
|
||||||
|
`Expected launch sortie formation assignments to trim, filter, and preserve first valid roles: ${JSON.stringify(normalizedLaunchFormation)}`
|
||||||
|
);
|
||||||
|
const cappedLaunchFormation = normalizeSortieFormationAssignments(
|
||||||
|
Object.fromEntries(Array.from({ length: 120 }, (_, index) => [`unit-${index}`, 'front']))
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
Object.keys(cappedLaunchFormation).length === 96 &&
|
||||||
|
cappedLaunchFormation['unit-95'] === 'front' &&
|
||||||
|
cappedLaunchFormation['unit-96'] === undefined,
|
||||||
|
`Expected launch sortie formation assignments without a roster filter to stay capped: ${JSON.stringify(cappedLaunchFormation)}`
|
||||||
|
);
|
||||||
|
|
||||||
resetCampaignState();
|
resetCampaignState();
|
||||||
const firstScenario = battleScenarios['first-battle-zhuo-commandery'];
|
const firstScenario = battleScenarios['first-battle-zhuo-commandery'];
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ export type SortieFormationAssignments = Partial<Record<string, SortieFormationR
|
|||||||
|
|
||||||
export const sortieFormationRoles: SortieFormationRole[] = ['front', 'flank', 'support', 'reserve'];
|
export const sortieFormationRoles: SortieFormationRole[] = ['front', 'flank', 'support', 'reserve'];
|
||||||
|
|
||||||
|
const maxSortieFormationAssignmentUnits = 96;
|
||||||
|
const maxSortieFormationUnitIdLength = 96;
|
||||||
|
|
||||||
export type SortieDeploymentPlanEntry = {
|
export type SortieDeploymentPlanEntry = {
|
||||||
unitId: string;
|
unitId: string;
|
||||||
role: SortieFormationRole;
|
role: SortieFormationRole;
|
||||||
@@ -38,11 +41,30 @@ export function normalizeSortieFormationAssignments(
|
|||||||
assignments?: Record<string, unknown>,
|
assignments?: Record<string, unknown>,
|
||||||
allowedUnitIds?: Set<string>
|
allowedUnitIds?: Set<string>
|
||||||
): SortieFormationAssignments {
|
): SortieFormationAssignments {
|
||||||
return Object.fromEntries(
|
return Object.entries(assignments ?? {}).reduce<SortieFormationAssignments>((next, [unitId, role]) => {
|
||||||
Object.entries(assignments ?? {}).filter(([unitId, role]) => {
|
const normalizedUnitId = normalizeSortieFormationUnitId(unitId);
|
||||||
return (!allowedUnitIds || allowedUnitIds.has(unitId)) && isSortieFormationRole(role);
|
if (
|
||||||
})
|
!normalizedUnitId ||
|
||||||
) as SortieFormationAssignments;
|
next[normalizedUnitId] ||
|
||||||
|
(allowedUnitIds && !allowedUnitIds.has(normalizedUnitId)) ||
|
||||||
|
(!allowedUnitIds && Object.keys(next).length >= maxSortieFormationAssignmentUnits) ||
|
||||||
|
!isSortieFormationRole(role)
|
||||||
|
) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
next[normalizedUnitId] = role;
|
||||||
|
return next;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSortieFormationUnitId(value: unknown) {
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = value.trim();
|
||||||
|
return text.length > 0 && text.length <= maxSortieFormationUnitIdLength ? text : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSortieDeploymentPlan(
|
export function createSortieDeploymentPlan(
|
||||||
|
|||||||
Reference in New Issue
Block a user