feat: rewrite main.js with config-driven initialization
This commit is contained in:
+128
@@ -0,0 +1,128 @@
|
|||||||
|
// ==================== 游戏入口 ====================
|
||||||
|
|
||||||
|
import { createInitialState, resetForRebirth } from './engine/state.js';
|
||||||
|
import { setCareerConfig } from './engine/careerEngine.js';
|
||||||
|
import { setEventConfig } from './engine/eventEngine.js';
|
||||||
|
import { setShopConfig } from './engine/shopEngine.js';
|
||||||
|
import { startGameLoop, stopGameLoop, setSpeed } from './engine/tickLoop.js';
|
||||||
|
import { applyEffect } from './engine/effectApplier.js';
|
||||||
|
import { processDeath } from './engine/deathEngine.js';
|
||||||
|
import { evaluateCondition } from './engine/conditionEvaluator.js';
|
||||||
|
import { initRenderer, renderAll, showDeathScreen, hideChoiceEvent } from './ui/renderer.js';
|
||||||
|
|
||||||
|
const state = createInitialState();
|
||||||
|
|
||||||
|
// ==================== 配置加载 ====================
|
||||||
|
|
||||||
|
async function loadConfigs() {
|
||||||
|
const [careers, events, shop, identities, talents] = await Promise.all([
|
||||||
|
fetch('./src/config/careers.json').then(r => r.json()),
|
||||||
|
fetch('./src/config/events.json').then(r => r.json()),
|
||||||
|
fetch('./src/config/shop.json').then(r => r.json()),
|
||||||
|
fetch('./src/config/identities.json').then(r => r.json()),
|
||||||
|
fetch('./src/config/talents.json').then(r => r.json()),
|
||||||
|
]);
|
||||||
|
setCareerConfig(careers);
|
||||||
|
setEventConfig(events);
|
||||||
|
setShopConfig(shop);
|
||||||
|
return { careers, events, shop, identities, talents };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 新游戏 ====================
|
||||||
|
|
||||||
|
function startNewGame(configs) {
|
||||||
|
resetForRebirth(state);
|
||||||
|
|
||||||
|
// 随机选择可用身份
|
||||||
|
const available = configs.identities.identities.filter(id => {
|
||||||
|
if (!id.unlockConditions || id.unlockConditions.length === 0) return true;
|
||||||
|
return id.unlockConditions.every(c => evaluateCondition(c, state));
|
||||||
|
});
|
||||||
|
const identity = available[Math.floor(Math.random() * available.length)];
|
||||||
|
state.identity = identity.id;
|
||||||
|
|
||||||
|
if (identity.startingStats) Object.assign(state.stats, identity.startingStats);
|
||||||
|
if (identity.startingItems) {
|
||||||
|
for (const itemId of identity.startingItems) {
|
||||||
|
applyEffect({ type: 'addItem', itemId }, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从已解锁词条池抽取(简化:先不实现)
|
||||||
|
|
||||||
|
startGameLoop(state, configs.careers, configs.events, configs.shop, () => {
|
||||||
|
renderAll(state, configs.careers, configs.shop);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 选择事件处理 ====================
|
||||||
|
|
||||||
|
function handleChoice(choiceIndex) {
|
||||||
|
if (!state.currentEvent) return;
|
||||||
|
const choice = state.currentEvent.choices[choiceIndex];
|
||||||
|
if (!choice) return;
|
||||||
|
if (choice.effects) {
|
||||||
|
for (const effect of choice.effects) applyEffect(effect, state);
|
||||||
|
}
|
||||||
|
state.paused = false;
|
||||||
|
state.currentEvent = null;
|
||||||
|
hideChoiceEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== UI事件绑定 ====================
|
||||||
|
|
||||||
|
function bindUIEvents() {
|
||||||
|
// 速度按钮
|
||||||
|
document.querySelectorAll('.speed-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const level = parseInt(btn.dataset.speed, 10);
|
||||||
|
setSpeed(state, level);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 暂停按钮
|
||||||
|
const pauseBtn = document.getElementById('pause-btn');
|
||||||
|
if (pauseBtn) {
|
||||||
|
pauseBtn.addEventListener('click', () => {
|
||||||
|
state.paused = !state.paused;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择按钮委托
|
||||||
|
const eventChoices = document.getElementById('event-choices');
|
||||||
|
if (eventChoices) {
|
||||||
|
eventChoices.addEventListener('click', (e) => {
|
||||||
|
const btn = e.target.closest('[data-index]');
|
||||||
|
if (!btn) return;
|
||||||
|
const idx = parseInt(btn.dataset.index, 10);
|
||||||
|
if (!isNaN(idx)) {
|
||||||
|
handleChoice(idx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重生按钮(死亡界面)
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (e.target.id === 'rebirth-btn') {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 主流程 ====================
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
const configs = await loadConfigs();
|
||||||
|
initRenderer();
|
||||||
|
bindUIEvents();
|
||||||
|
startNewGame(configs);
|
||||||
|
setInterval(() => {
|
||||||
|
if (!state.alive && state.deathReason) {
|
||||||
|
stopGameLoop();
|
||||||
|
processDeath(state, configs.careers, configs.talents);
|
||||||
|
showDeathScreen(state, configs.careers);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
init().catch(console.error);
|
||||||
Reference in New Issue
Block a user