feat: add tactical initiative commands
This commit is contained in:
@@ -51,6 +51,77 @@ try {
|
||||
}
|
||||
};
|
||||
assert(isValidBattleSaveState(validSortieStatsState, options), 'Expected sortie and counterplay contribution stats to pass validation.');
|
||||
const tacticalOptions = {
|
||||
...options,
|
||||
expectedBattleId: 'second-battle-yellow-turban-pursuit',
|
||||
allowTacticalCommand: true
|
||||
};
|
||||
const validTacticalBaseState = {
|
||||
...validState,
|
||||
battleId: tacticalOptions.expectedBattleId,
|
||||
campaignStep: 'second-battle',
|
||||
enemyUsableUseKeys: [],
|
||||
battleStats: {
|
||||
...validState.battleStats,
|
||||
'liu-bei': {
|
||||
...validState.battleStats['liu-bei'],
|
||||
intentDefeats: 3
|
||||
}
|
||||
}
|
||||
};
|
||||
const validFrontCommandState = {
|
||||
...validTacticalBaseState,
|
||||
tacticalCommand: {
|
||||
role: 'front',
|
||||
actorId: 'guan-yu',
|
||||
usedTurn: 2,
|
||||
effectPending: true,
|
||||
effectValue: 0,
|
||||
statusesCleared: 0,
|
||||
effectLost: false
|
||||
}
|
||||
};
|
||||
const validFlankCommandState = {
|
||||
...validFrontCommandState,
|
||||
tacticalCommand: { ...validFrontCommandState.tacticalCommand, role: 'flank', effectPending: false, effectValue: 4 }
|
||||
};
|
||||
const validSupportCommandState = {
|
||||
...validFrontCommandState,
|
||||
tacticalCommand: {
|
||||
...validFrontCommandState.tacticalCommand,
|
||||
role: 'support',
|
||||
actorId: 'liu-bei',
|
||||
effectPending: false,
|
||||
effectValue: 6,
|
||||
statusesCleared: 1
|
||||
}
|
||||
};
|
||||
const validLostFrontCommandState = {
|
||||
...validFrontCommandState,
|
||||
units: validFrontCommandState.units.map((unit) => (unit.id === 'guan-yu' ? { ...unit, hp: 0 } : unit)),
|
||||
tacticalCommand: {
|
||||
...validFrontCommandState.tacticalCommand,
|
||||
effectPending: false,
|
||||
effectLost: true
|
||||
}
|
||||
};
|
||||
assert(isValidBattleSaveState(validFrontCommandState, tacticalOptions), 'Expected pending front tactical command to pass validation.');
|
||||
assert(isValidBattleSaveState(validFlankCommandState, tacticalOptions), 'Expected resolved flank tactical command to pass validation.');
|
||||
assert(isValidBattleSaveState(validSupportCommandState, tacticalOptions), 'Expected immediate support tactical command to pass validation.');
|
||||
assert(isValidBattleSaveState(validLostFrontCommandState, tacticalOptions), 'Expected a lost tactical command to retain its result record.');
|
||||
assert(!isValidBattleSaveState(validFrontCommandState, options), 'Expected tactical commands to be rejected when disabled for the battle.');
|
||||
const tacticalRoleOptions = {
|
||||
...tacticalOptions,
|
||||
validTacticalCommandRolesByActor: { 'guan-yu': 'front', 'liu-bei': 'support' }
|
||||
};
|
||||
assert(isValidBattleSaveState(validFrontCommandState, tacticalRoleOptions), 'Expected the assigned front actor to pass validation.');
|
||||
assert(isValidBattleSaveState(validSupportCommandState, tacticalRoleOptions), 'Expected the assigned support actor to pass validation.');
|
||||
assert(!isValidBattleSaveState(validFlankCommandState, tacticalRoleOptions), 'Expected a role and actor assignment mismatch to be rejected.');
|
||||
const parsedTacticalCommand = parseBattleSaveState(JSON.stringify(validFrontCommandState), tacticalOptions)?.tacticalCommand;
|
||||
assert(
|
||||
JSON.stringify(parsedTacticalCommand) === JSON.stringify(validFrontCommandState.tacticalCommand),
|
||||
'Expected every tactical command field to round-trip.'
|
||||
);
|
||||
assert(parseBattleSaveState(JSON.stringify(validState), options)?.battleId === options.expectedBattleId, 'Expected valid JSON save to parse.');
|
||||
assert(parseBattleSaveState('{', options) === undefined, 'Expected malformed JSON to be ignored.');
|
||||
assert(parseBattleSaveState('', options) === undefined, 'Expected empty save payload to be ignored.');
|
||||
@@ -162,6 +233,34 @@ try {
|
||||
assert(!isValidBattleSaveState(candidate, options), `Expected invalid battle save to be rejected: ${label}`);
|
||||
});
|
||||
|
||||
const tacticalRejectedCases = [
|
||||
['invalid tactical command shape', { tacticalCommand: 'front' }],
|
||||
['invalid tactical command role', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, role: 'reserve' } }],
|
||||
['unknown tactical command actor', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, actorId: 'ghost-unit' } }],
|
||||
['enemy tactical command actor', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, actorId: 'rebel-1' } }],
|
||||
['invalid tactical command turn', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, usedTurn: 0 } }],
|
||||
['future tactical command turn', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, usedTurn: 3 } }],
|
||||
['fractional tactical command turn', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, usedTurn: 1.5 } }],
|
||||
['invalid tactical command pending flag', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, effectPending: 'yes' } }],
|
||||
['invalid tactical command lost flag', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, effectLost: 'yes' } }],
|
||||
['support tactical command cannot remain pending', { tacticalCommand: { ...validSupportCommandState.tacticalCommand, effectPending: true } }],
|
||||
['invalid tactical command effect value', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, effectValue: -1 } }],
|
||||
['pending tactical command cannot have effect value', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, effectValue: 1 } }],
|
||||
['pending tactical command cannot be lost', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, effectLost: true } }],
|
||||
['front tactical command cannot clear statuses', { tacticalCommand: { ...validFlankCommandState.tacticalCommand, role: 'front', statusesCleared: 1 } }],
|
||||
['lost tactical command cannot retain effect value', { tacticalCommand: { ...validFlankCommandState.tacticalCommand, effectLost: true } }],
|
||||
['support tactical command heal exceeds limit', { tacticalCommand: { ...validSupportCommandState.tacticalCommand, effectValue: 7 } }],
|
||||
['support tactical command statuses exceed limit', { tacticalCommand: { ...validSupportCommandState.tacticalCommand, statusesCleared: 3 } }],
|
||||
['invalid tactical command cleared status count', { tacticalCommand: { ...validFrontCommandState.tacticalCommand, statusesCleared: 1.5 } }],
|
||||
['pending tactical command actor defeated', { units: validFrontCommandState.units.map((unit) => (unit.id === 'guan-yu' ? { ...unit, hp: 0 } : unit)) }],
|
||||
['tactical command without enough counterplay', { battleStats: validState.battleStats }]
|
||||
];
|
||||
|
||||
tacticalRejectedCases.forEach(([label, patch]) => {
|
||||
const candidate = { ...validFrontCommandState, ...patch };
|
||||
assert(!isValidBattleSaveState(candidate, tacticalOptions), `Expected invalid tactical command save to be rejected: ${label}`);
|
||||
});
|
||||
|
||||
assert(
|
||||
!isValidBattleSaveState(validState, { ...options, validUnitIds: new Set(['liu-bei', 'guan-yu', 'rebel-1', 'zhang-fei']) }),
|
||||
'Expected save missing a current battle unit to be rejected.'
|
||||
|
||||
Reference in New Issue
Block a user