import { createServer } from 'vite'; const server = await createServer({ logLevel: 'error', server: { middlewareMode: true, hmr: false }, appType: 'custom' }); try { const { getUnitSignatureStrategy, getUnitStrategies, getUnitStrategyCoverage, strategyCoverageDefinitions, unitStrategyIds, usableCatalog } = await server.ssrLoadModule('/src/game/data/battleUsables.ts'); const signatures = [ { ownerId: 'liu-bei', usableId: 'benevolentCommand', name: '인덕의 호령', target: 'ally', effect: 'focus', range: 3, power: 0, attackBonus: 2, hitBonus: 10, duration: 2, accuracyBonus: 0, criticalBonus: 4, statusEffect: null, statusDuration: 0, statusPower: 0, coverageIds: ['buff'], expectedStrategies: ['aid', 'benevolentCommand'] }, { ownerId: 'guan-yu', usableId: 'azureDragonStrike', name: '청룡일섬', target: 'enemy', effect: 'damage', range: 1, power: 13, accuracyBonus: 6, criticalBonus: 10, statusEffect: null, statusDuration: 0, statusPower: 0, coverageIds: ['offense'], expectedStrategies: ['azureDragonStrike'] }, { ownerId: 'zhang-fei', usableId: 'changbanRoar', name: '장판교 대갈', target: 'enemy', effect: 'damage', range: 2, power: 8, accuracyBonus: 12, criticalBonus: 0, statusEffect: 'confusion', statusDuration: 1, statusPower: 1, coverageIds: ['offense', 'control'], expectedStrategies: ['changbanRoar'] }, { ownerId: 'zhao-yun', usableId: 'singleRiderRescue', name: '단기구원', target: 'ally', effect: 'heal', range: 3, power: 12, accuracyBonus: 0, criticalBonus: 0, statusEffect: null, statusDuration: 0, statusPower: 0, coverageIds: ['healing'], expectedStrategies: ['singleRiderRescue'] }, { ownerId: 'zhuge-liang', usableId: 'eastWindFire', name: '동남풍 화계', target: 'enemy', effect: 'damage', range: 3, power: 11, accuracyBonus: 6, criticalBonus: 0, statusEffect: 'burn', statusDuration: 3, statusPower: 3, coverageIds: ['offense'], expectedStrategies: ['aid', 'encourage', 'eastWindFire'] }, { ownerId: 'huang-zhong', usableId: 'hundredPacePierce', name: '백보천양', target: 'enemy', effect: 'damage', range: 4, power: 11, accuracyBonus: 18, criticalBonus: 12, statusEffect: null, statusDuration: 0, statusPower: 0, coverageIds: ['offense'], expectedStrategies: ['hundredPacePierce'] }, { ownerId: 'ma-chao', usableId: 'westernCavalryCharge', name: '서량철기', target: 'enemy', effect: 'damage', range: 2, power: 11, accuracyBonus: 8, criticalBonus: 6, statusEffect: 'confusion', statusDuration: 1, statusPower: 1, coverageIds: ['offense', 'control'], expectedStrategies: ['westernCavalryCharge', 'encourage'] }, { ownerId: 'jiang-wei', usableId: 'qilinStratagem', name: '기린지계', target: 'enemy', effect: 'damage', range: 3, power: 10, accuracyBonus: 10, criticalBonus: 2, statusEffect: 'confusion', statusDuration: 2, statusPower: 1, coverageIds: ['offense', 'control'], expectedStrategies: ['aid', 'encourage', 'qilinStratagem'] } ]; assert( JSON.stringify(strategyCoverageDefinitions.map(({ id, label }) => ({ id, label }))) === JSON.stringify([ { id: 'healing', label: '회복' }, { id: 'buff', label: '강화' }, { id: 'offense', label: '공격' }, { id: 'control', label: '제어' } ]), `Unexpected strategy coverage contract: ${JSON.stringify(strategyCoverageDefinitions)}` ); const signatureNames = new Set(); signatures.forEach((expected) => { const usable = usableCatalog[expected.usableId]; assert(usable, `Missing signature strategy ${expected.usableId}.`); assert(usable.id === expected.usableId, `Catalog key/id mismatch for ${expected.usableId}: ${usable.id}`); assert(usable.command === 'strategy', `Signature strategy must use the strategy command: ${expected.usableId}`); assert(usable.signatureOwnerId === expected.ownerId, `Unexpected signature owner for ${expected.usableId}: ${usable.signatureOwnerId}`); assert(usable.name === expected.name, `Unexpected signature name for ${expected.usableId}: ${usable.name}`); assert(usable.target === expected.target && usable.effect === expected.effect, `Unexpected target/effect for ${expected.usableId}.`); assert(usable.range === expected.range && usable.power === expected.power, `Unexpected range/power for ${expected.usableId}.`); assert((usable.attackBonus ?? 0) === (expected.attackBonus ?? 0), `Unexpected attack bonus for ${expected.usableId}.`); assert((usable.hitBonus ?? 0) === (expected.hitBonus ?? 0), `Unexpected hit bonus for ${expected.usableId}.`); assert((usable.duration ?? 0) === (expected.duration ?? 0), `Unexpected effect duration for ${expected.usableId}.`); assert((usable.accuracyBonus ?? 0) === expected.accuracyBonus, `Unexpected accuracy bonus for ${expected.usableId}.`); assert((usable.criticalBonus ?? 0) === expected.criticalBonus, `Unexpected critical bonus for ${expected.usableId}.`); assert((usable.statusEffect ?? null) === expected.statusEffect, `Unexpected status for ${expected.usableId}.`); assert((usable.statusDuration ?? 0) === expected.statusDuration, `Unexpected status duration for ${expected.usableId}.`); assert((usable.statusPower ?? 0) === expected.statusPower, `Unexpected status power for ${expected.usableId}.`); assert(JSON.stringify(usable.coverageIds ?? []) === JSON.stringify(expected.coverageIds), `Unexpected coverage for ${expected.usableId}.`); assert(typeof usable.description === 'string' && usable.description.trim().length >= 20, `Signature strategy needs a meaningful description: ${expected.usableId}`); assert(!signatureNames.has(usable.name), `Duplicate signature strategy name: ${usable.name}`); signatureNames.add(usable.name); assert( JSON.stringify(unitStrategyIds[expected.ownerId]) === JSON.stringify(expected.expectedStrategies), `Unexpected strategy loadout for ${expected.ownerId}: ${JSON.stringify(unitStrategyIds[expected.ownerId])}` ); assert( getUnitSignatureStrategy(expected.ownerId)?.id === expected.usableId, `Signature lookup did not resolve ${expected.ownerId} -> ${expected.usableId}.` ); assert( getUnitStrategies([expected.ownerId]).filter((candidate) => candidate.id === expected.usableId).length === 1, `Signature strategy must appear exactly once for ${expected.ownerId}.` ); Object.entries(unitStrategyIds) .filter(([unitId]) => unitId !== expected.ownerId) .forEach(([unitId, strategyIds]) => { assert(!strategyIds.includes(expected.usableId), `${expected.usableId} leaked into ${unitId}'s strategy loadout.`); }); }); const assignedStrategyIds = Object.values(unitStrategyIds).flat(); assignedStrategyIds.forEach((strategyId) => { assert(usableCatalog[strategyId]?.command === 'strategy', `Assigned strategy does not resolve to a strategy usable: ${strategyId}`); }); assert( Object.entries(usableCatalog) .filter(([, usable]) => usable.signatureOwnerId) .every(([usableId, usable]) => signatures.some((entry) => entry.usableId === usableId && entry.ownerId === usable.signatureOwnerId)), 'Every signature strategy must be covered by the eight-officer contract.' ); const brotherCoverage = getUnitStrategyCoverage(['liu-bei', 'guan-yu', 'zhang-fei', 'liu-bei']); assert( brotherCoverage.count === 4 && brotherCoverage.total === 4 && brotherCoverage.missing.length === 0, `The founding trio must retain full strategy coverage: ${JSON.stringify(brotherCoverage)}` ); assert( getUnitStrategyCoverage(['guan-yu', 'huang-zhong']).count === 1, 'Duplicate offense signatures must not inflate coverage.' ); assert( JSON.stringify(getUnitStrategyCoverage(['zhang-fei']).covered.map((definition) => definition.id)) === JSON.stringify(['offense', 'control']), `Zhang Fei's signature must expose offense and control coverage: ${JSON.stringify(getUnitStrategyCoverage(['zhang-fei']))}` ); console.log('Verified eight owner-exclusive signature strategies, their combat metadata, loadouts, and strategy coverage.'); } finally { await server.close(); } function assert(condition, message) { if (!condition) { throw new Error(message); } }