174 lines
4.7 KiB
JavaScript
174 lines
4.7 KiB
JavaScript
|
|
// ==================== 死亡与结算 ====================
|
|||
|
|
|
|||
|
|
import { state, addLog, resetStateForRebirth } from './state.js';
|
|||
|
|
import { CAREERS } from './expSystem.js';
|
|||
|
|
import { checkNewEntries as checkNewEntriesFromTalents } from '../content/talents.js';
|
|||
|
|
|
|||
|
|
// 检查是否死亡
|
|||
|
|
export function checkDeath() {
|
|||
|
|
if (!state.alive) return true;
|
|||
|
|
|
|||
|
|
// 年龄死亡
|
|||
|
|
if (state.age >= 100) {
|
|||
|
|
die('寿终正寝');
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (state.age >= 50) {
|
|||
|
|
const deathChance = getAgeDeathChance(state.age);
|
|||
|
|
if (Math.random() < deathChance) {
|
|||
|
|
die('寿终正寝');
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 外敌死亡
|
|||
|
|
for (const [type, progress] of Object.entries(state.enemyProgress)) {
|
|||
|
|
if (progress >= 100 && Math.random() < 0.4) {
|
|||
|
|
const names = { military: '死于蛮族入侵', spiritual: '被天魔吞噬', political: '王朝覆灭,死于战乱' };
|
|||
|
|
die(names[type] || '死于外敌');
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 体质死亡
|
|||
|
|
if (state.stats.body <= 0) {
|
|||
|
|
die('体弱身亡');
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 危机感死亡(极端情况)
|
|||
|
|
if (state.crisisLevel >= 100 && Math.random() < 0.3) {
|
|||
|
|
die('在极度恐惧中精神崩溃');
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getAgeDeathChance(age) {
|
|||
|
|
if (age < 50) return 0;
|
|||
|
|
if (age < 60) return 0.02;
|
|||
|
|
if (age < 70) return 0.08;
|
|||
|
|
if (age < 80) return 0.20;
|
|||
|
|
if (age < 90) return 0.45;
|
|||
|
|
if (age < 100) return 0.80;
|
|||
|
|
return 1.0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 死亡结算
|
|||
|
|
function die(reason) {
|
|||
|
|
if (!state.alive) return;
|
|||
|
|
state.alive = false;
|
|||
|
|
addLog(`你死了。原因:${reason}`, 'death');
|
|||
|
|
|
|||
|
|
// 结算元经验
|
|||
|
|
const metaGains = {};
|
|||
|
|
for (const [id, career] of Object.entries(state.careers)) {
|
|||
|
|
const config = CAREERS[id];
|
|||
|
|
if (!config) continue;
|
|||
|
|
|
|||
|
|
let totalExp = career.exp;
|
|||
|
|
for (let i = 0; i < career.level; i++) {
|
|||
|
|
totalExp += Math.floor(config.baseExp * Math.pow(config.expCurve, i));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const gain = Math.floor(totalExp * 0.1);
|
|||
|
|
state.metaExp[id] = (state.metaExp[id] || 0) + gain;
|
|||
|
|
metaGains[id] = gain;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解锁新词条
|
|||
|
|
const newEntries = checkNewEntriesFromTalents(state);
|
|||
|
|
for (const entry of newEntries) {
|
|||
|
|
state.unlockedEntries.add(entry.id);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 外敌进度跨轮继承(保留30%)
|
|||
|
|
for (const key of Object.keys(state.enemyProgress)) {
|
|||
|
|
state.enemyProgress[key] = Math.min(100, state.enemyProgress[key] * 0.3 + 5);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 触发死亡结算界面
|
|||
|
|
if (typeof window !== 'undefined' && window.onDeath) {
|
|||
|
|
window.onDeath({
|
|||
|
|
reason,
|
|||
|
|
age: state.age,
|
|||
|
|
day: state.day,
|
|||
|
|
careers: Object.fromEntries(
|
|||
|
|
Object.entries(state.careers).map(([k, v]) => [k, { level: v.level, name: CAREERS[k]?.name }])
|
|||
|
|
),
|
|||
|
|
metaGains,
|
|||
|
|
newEntries,
|
|||
|
|
history: getHistoryComparison(),
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 历史对比
|
|||
|
|
function getHistoryComparison() {
|
|||
|
|
if (state.history.length === 0) return null;
|
|||
|
|
|
|||
|
|
const lastLife = state.history[state.history.length - 1];
|
|||
|
|
const bestLife = state.history.reduce((best, current) =>
|
|||
|
|
(current.age > best.age) ? current : best
|
|||
|
|
, state.history[0]);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
vsLast: {
|
|||
|
|
ageDiff: state.age - lastLife.age,
|
|||
|
|
levelDiff: compareLevels(state.careers, lastLife.careers),
|
|||
|
|
},
|
|||
|
|
vsBest: {
|
|||
|
|
ageDiff: state.age - bestLife.age,
|
|||
|
|
levelDiff: compareLevels(state.careers, bestLife.careers),
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function compareLevels(current, previous) {
|
|||
|
|
const result = {};
|
|||
|
|
const allIds = new Set([...Object.keys(current), ...Object.keys(previous)]);
|
|||
|
|
for (const id of allIds) {
|
|||
|
|
const curr = current[id]?.level || 0;
|
|||
|
|
const prev = previous[id]?.level || 0;
|
|||
|
|
result[id] = curr - prev;
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重生
|
|||
|
|
export function rebirth() {
|
|||
|
|
resetStateForRebirth();
|
|||
|
|
|
|||
|
|
// 随机出身
|
|||
|
|
state.family = Math.floor(Math.random() * 4) - 1; // -1 ~ 2
|
|||
|
|
state.stats = {
|
|||
|
|
body: Math.floor(Math.random() * 5) + 2, // 2~6,避免刚出生就死
|
|||
|
|
wisdom: Math.floor(Math.random() * 5) + 2,
|
|||
|
|
charm: Math.floor(Math.random() * 5) + 2,
|
|||
|
|
luck: Math.floor(Math.random() * 5) + 2,
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 应用记忆效果
|
|||
|
|
if (state.memories.includes('wisdom_boost')) state.stats.wisdom += 1;
|
|||
|
|
if (state.memories.includes('body_boost')) state.stats.body += 1;
|
|||
|
|
|
|||
|
|
// 从已解锁词条池中随机抽取
|
|||
|
|
const pool = Array.from(state.unlockedEntries);
|
|||
|
|
state.talents = [];
|
|||
|
|
const count = Math.min(3 + Math.floor(state.reincarnation / 10), 5);
|
|||
|
|
for (let i = 0; i < count && pool.length > 0; i++) {
|
|||
|
|
const idx = Math.floor(Math.random() * pool.length);
|
|||
|
|
state.talents.push({ id: pool[idx] });
|
|||
|
|
pool.splice(idx, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
addLog(`第${state.reincarnation}世开始。出身: ${state.family > 0 ? '富贵' : state.family < 0 ? '贫寒' : '普通'}人家。`);
|
|||
|
|
|
|||
|
|
// 触发重生事件
|
|||
|
|
if (typeof window !== 'undefined' && window.onRebirth) {
|
|||
|
|
window.onRebirth();
|
|||
|
|
}
|
|||
|
|
}
|