111 lines
5.1 KiB
JavaScript
111 lines
5.1 KiB
JavaScript
import { createServer } from 'vite';
|
|
|
|
const server = await createServer({
|
|
logLevel: 'error',
|
|
server: { middlewareMode: true },
|
|
appType: 'custom'
|
|
});
|
|
|
|
try {
|
|
const {
|
|
compareSortieSynergy,
|
|
evaluateSortieSynergy,
|
|
firstPursuitSynergyBattleId,
|
|
sortieBondBonusForLevel
|
|
} = await server.ssrLoadModule('/src/game/data/sortieSynergy.ts');
|
|
|
|
const boundaryCases = [
|
|
[19, 0, 0],
|
|
[20, 3, 0],
|
|
[39, 3, 0],
|
|
[40, 6, 0],
|
|
[49, 6, 0],
|
|
[50, 6, 8],
|
|
[69, 9, 8],
|
|
[70, 9, 18],
|
|
[100, 15, 18]
|
|
];
|
|
boundaryCases.forEach(([level, damageBonus, chainRate]) => {
|
|
const actual = sortieBondBonusForLevel(level);
|
|
assert(
|
|
actual.damageBonus === damageBonus && actual.chainRate === chainRate,
|
|
`Unexpected Lv${level} bond bonus: ${JSON.stringify(actual)}`
|
|
);
|
|
});
|
|
|
|
const members = [
|
|
{ id: 'liu-bei', name: '유비', role: 'support', terrainScore: 101 },
|
|
{ id: 'guan-yu', name: '관우', role: 'front', terrainScore: 105 },
|
|
{ id: 'zhang-fei', name: '장비', role: 'flank', terrainScore: 98 },
|
|
{ id: 'jian-yong', name: '간옹', role: 'support', terrainScore: 104 }
|
|
];
|
|
const bonds = [
|
|
{ id: 'oath', title: '도원결의', unitIds: ['liu-bei', 'guan-yu'], level: 72, exp: 4 },
|
|
{ id: 'brothers', title: '의형제', unitIds: ['guan-yu', 'zhang-fei'], level: 68, exp: 3 },
|
|
{ id: 'vow', title: '맹세', unitIds: ['liu-bei', 'zhang-fei'], level: 64, exp: 2 },
|
|
{ id: 'records', title: '군영 기록', unitIds: ['liu-bei', 'jian-yong'], level: 51, exp: 1 },
|
|
{ id: 'self', title: '잘못된 관계', unitIds: ['liu-bei', 'liu-bei'], level: 99, exp: 0 },
|
|
{ id: 'unknown', title: '알 수 없음', unitIds: ['liu-bei', 'ghost'], level: 99, exp: 0 }
|
|
];
|
|
const frozenInputs = JSON.stringify({ members, bonds });
|
|
|
|
const trio = evaluateSortieSynergy({
|
|
members,
|
|
bonds,
|
|
selectedUnitIds: ['liu-bei', 'guan-yu', 'zhang-fei', 'guan-yu'],
|
|
battleId: firstPursuitSynergyBattleId
|
|
});
|
|
assert(trio.selectedUnitIds.length === 3, `Expected duplicate selections to collapse: ${JSON.stringify(trio.selectedUnitIds)}`);
|
|
assert(trio.activeBondCount === 3, `Expected three active brother bonds: ${JSON.stringify(trio.activeBonds)}`);
|
|
assert(trio.strongestBond?.id === 'oath', `Expected Lv72 oath to be strongest: ${JSON.stringify(trio.strongestBond)}`);
|
|
assert(trio.strongestBond?.damageBonus === 9 && trio.strongestBond?.chainRate === 18, 'Expected strongest combat preview to match BattleScene rules.');
|
|
assert(trio.coveredRoleCount === 3 && trio.firstPursuitTrinityConfigured, `Expected full role coverage and trinity: ${JSON.stringify(trio)}`);
|
|
|
|
const withoutGuan = evaluateSortieSynergy({
|
|
members,
|
|
bonds,
|
|
selectedUnitIds: ['liu-bei', 'zhang-fei'],
|
|
battleId: firstPursuitSynergyBattleId
|
|
});
|
|
assert(withoutGuan.activeBondCount === 1 && withoutGuan.activeBonds[0]?.id === 'vow', `Expected only the Liu-Zhang bond after Guan Yu leaves: ${JSON.stringify(withoutGuan.activeBonds)}`);
|
|
assert(withoutGuan.coveredRoleCount === 2 && !withoutGuan.firstPursuitTrinityConfigured, 'Expected removing Guan Yu to break role coverage and trinity.');
|
|
|
|
const removal = compareSortieSynergy(trio, withoutGuan);
|
|
assert(removal.activeBondDelta === -2 && removal.lostBonds.length === 2, `Expected two lost bonds: ${JSON.stringify(removal)}`);
|
|
assert(removal.roleCoverageDelta === -1 && removal.lostRoles[0] === 'front', `Expected the front role to be lost: ${JSON.stringify(removal.lostRoles)}`);
|
|
const addition = compareSortieSynergy(withoutGuan, trio);
|
|
assert(addition.activeBondDelta === 2 && addition.gainedBonds.length === 2, `Expected adding Guan Yu to restore two bonds: ${JSON.stringify(addition)}`);
|
|
assert(addition.roleCoverageDelta === 1 && addition.gainedRoles[0] === 'front', `Expected adding Guan Yu to restore the front role: ${JSON.stringify(addition.gainedRoles)}`);
|
|
|
|
const restoredRoles = evaluateSortieSynergy({
|
|
members: members.map((member) => member.id === 'guan-yu' ? { ...member, role: 'support' } : member),
|
|
bonds,
|
|
selectedUnitIds: ['liu-bei', 'guan-yu', 'zhang-fei'],
|
|
battleId: firstPursuitSynergyBattleId
|
|
});
|
|
assert(restoredRoles.activeBondCount === 3, 'Expected role changes not to alter active bonds.');
|
|
assert(restoredRoles.coveredRoleCount === 2 && !restoredRoles.firstPursuitTrinityConfigured, 'Expected duplicate support roles to disable trinity.');
|
|
|
|
const reordered = evaluateSortieSynergy({
|
|
members: [...members].reverse(),
|
|
bonds: [...bonds].reverse(),
|
|
selectedUnitIds: ['zhang-fei', 'guan-yu', 'liu-bei'],
|
|
battleId: firstPursuitSynergyBattleId
|
|
});
|
|
assert(
|
|
reordered.activeBonds.map((bond) => bond.id).join(',') === trio.activeBonds.map((bond) => bond.id).join(','),
|
|
`Expected deterministic bond ordering: ${JSON.stringify(reordered.activeBonds)}`
|
|
);
|
|
assert(JSON.stringify({ members, bonds }) === frozenInputs, 'Expected synergy evaluation not to mutate its inputs.');
|
|
|
|
console.log('Verified sortie synergy previews, bond thresholds, role coverage, and first-pursuit trinity.');
|
|
} finally {
|
|
await server.close();
|
|
}
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) {
|
|
throw new Error(message);
|
|
}
|
|
}
|