import { tick, startGameLoop, stopGameLoop, setSpeed, } from '../src/engine/tickLoop.js'; // ==================== 测试配置 ==================== const careerConfig = { careers: [ { id: 'student', name: '学童', type: 'scholar', unlockConditions: { type: 'age', op: '>=', value: 6 }, dailyIncome: 1, expCurve: { base: 10, factor: 1.15 }, }, { id: 'soldier', name: '士兵', type: 'military', unlockConditions: { type: 'and', conditions: [ { type: 'age', op: '>=', value: 14 }, { type: 'stat', op: '>=', stat: 'body', value: 10 }, ], }, dailyIncome: 2, expCurve: { base: 20, factor: 1.18 }, }, ], }; const eventConfig = { events: [ { id: 'invasion_military_40', name: '蛮族入侵', trigger: { type: 'age', value: 40 }, isChoice: true, choices: [ { id: 'resist', text: '率军抵抗', requirements: { type: 'careerLevel', careerId: 'soldier', op: '>=', value: 50, }, effects: [{ type: 'addLog', text: '你率领大军击退了蛮族入侵!' }], }, { id: 'flee', text: '弃城逃跑', effects: [{ type: 'addLog', text: '你选择了弃城逃跑。' }], }, ], }, { id: 'daily_training', name: '日常修炼', trigger: { type: 'random', pool: 'normal' }, weight: 50, effects: [{ type: 'addStat', stat: 'body', value: 1 }], }, ], }; const shopConfig = { artifacts: [], }; // ==================== 测试辅助函数 ==================== function assertEqual(actual, expected, message) { const actualStr = JSON.stringify(actual); const expectedStr = JSON.stringify(expected); if (actualStr !== expectedStr) { throw new Error( `${message}\n 期望: ${expectedStr}\n 实际: ${actualStr}` ); } } function assertTrue(value, message) { if (!value) { throw new Error(message || `期望为 true,实际为 ${value}`); } } // ==================== 测试用例 ==================== function testTickAdvancesDay() { const state = { alive: true, paused: false, day: 0, year: 0, age: 5, stats: {}, careers: {}, money: 0, worldFlags: {}, }; tick(state, 1, careerConfig, eventConfig, shopConfig); assertEqual(state.day, 1, 'day should advance by 1'); } function testTickUnlocksCareer() { const state = { alive: true, paused: false, day: 0, year: 0, age: 5, stats: {}, careers: {}, money: 0, worldFlags: {}, }; // Age 5 -> 6 after 365 days tick(state, 365, careerConfig, eventConfig, shopConfig); assertEqual(state.age, 6, 'age should be 6 after 365 days'); assertTrue(state.careers.student !== undefined, 'student should unlock at age 6'); } function testTickIncome() { const state = { alive: true, paused: false, day: 0, year: 0, age: 10, stats: {}, careers: { student: { level: 0, exp: 0 } }, money: 0, worldFlags: {}, }; tick(state, 10, careerConfig, eventConfig, shopConfig); assertEqual(state.money, 10, 'money should increase by 10 (1 per day from student)'); } function testTickExp() { const state = { alive: true, paused: false, day: 0, year: 0, age: 10, stats: { wisdom: 0 }, careers: { student: { level: 0, exp: 0 } }, money: 0, metaExp: {}, worldFlags: {}, }; tick(state, 1, careerConfig, eventConfig, shopConfig); assertEqual(state.careers.student.level, 1, 'student should level up to 1 after 1 day'); assertEqual(state.careers.student.exp, 0, 'remaining exp should be 0 after level up'); // Test level up: need 10 exp for level 1, 11.5 for level 2 const state2 = { alive: true, paused: false, day: 0, year: 0, age: 10, stats: { wisdom: 0 }, careers: { student: { level: 0, exp: 0 } }, money: 0, metaExp: {}, worldFlags: {}, }; tick(state2, 2, careerConfig, eventConfig, shopConfig); assertEqual(state2.careers.student.level, 1, 'student should level up to 1'); assertEqual(state2.careers.student.exp, 10, 'remaining exp should be 10 (20 - 10)'); } function testAgeEventTriggers() { const state = { alive: true, paused: false, day: 0, year: 0, age: 39, stats: {}, careers: {}, money: 0, worldFlags: {}, triggeredEvents: new Set(), }; // 365 ticks to go from age 39 to 40 tick(state, 365, careerConfig, eventConfig, shopConfig); assertEqual(state.age, 40, 'age should be 40'); assertEqual(state.paused, true, 'game should pause on choice event'); assertTrue(state.currentEvent !== undefined, 'currentEvent should be set'); assertEqual(state.currentEvent.id, 'invasion_military_40', 'should trigger invasion event at 40'); } // ==================== 运行测试 ==================== function runTests() { const tests = [ { name: 'testTickAdvancesDay', fn: testTickAdvancesDay }, { name: 'testTickUnlocksCareer', fn: testTickUnlocksCareer }, { name: 'testTickIncome', fn: testTickIncome }, { name: 'testTickExp', fn: testTickExp }, { name: 'testAgeEventTriggers', fn: testAgeEventTriggers }, ]; let passed = 0; let failed = 0; for (const test of tests) { try { test.fn(); console.log(` PASS: ${test.name}`); passed++; } catch (err) { console.log(` FAIL: ${test.name}`); console.log(` ${err.message}`); failed++; } } console.log(`\n${passed} passed, ${failed} failed`); if (failed === 0) { console.log('All tickLoop tests PASS'); process.exit(0); } else { process.exit(1); } } runTests();