Files
rebirthlife/test/tickLoop.test.js

246 lines
5.7 KiB
JavaScript

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();