feat(0.1.14-P3): 世界自进化 WorldSim(五大闭环)+ 引擎时钟合一

- WorldSim(engine/sim/WorldSim.ts + worldsim-data.ts):
  A 资源循环市场(库存池/再平衡/价格弹性——Market 行情联动 sim.mult)
  B NPC 聚合演化(宗主换代/境界成长/势力=境界+财力+兵员;换代计数)
  C 秘境灵气(探索消耗/恢复)+ 灵气潮汐(6年周期×修炼倍率)
  D 灾年签(旱涝蝗疫兽寒,联动市场池)
  E 天下快讯(节流 24 月滚动 120 条,世界动态 feed)
- 相位:新增 worldsim(diplomacy 后 epilogue 前);capabilities 加「天下演序」卡可停用
- 时钟合一:World.clock = Kernel.clock(单一时钟驱动,消除双时钟漂移)
- 发现并修复:worldsim 注册被文件搬迁覆盖丢失(修改纪律验证中招——已补回);
  WorldSim 内 Math.random 根除(改 w.rng)
- fingerprint 纳入 worldSim 概要(市场/灵脉/潮汐/换代/快讯数)
- 金钟罩三档重固化(0.1.14 正式基线,受控变更)
- 验证:35 套件/967 测试全绿;typecheck 0 error
This commit is contained in:
2026-08-23 13:31:34 +08:00
parent 8dfdaf843a
commit 5dd5d6b558
16 changed files with 370 additions and 45 deletions
@@ -53,6 +53,9 @@ export function monthlyRate(w: World, c: Character): number {
if (w.ageOf(c) < 8) rate *= 0.4
if (w.ageOf(c) > 65) rate *= 0.72
rate *= masteryRateOfMajor(c.realm.major)
// 世界灵气潮汐
const tide = w.state.worldSim?.tide ?? 1
rate *= tide
return rate
}
@@ -138,6 +138,15 @@ export function sendMission(w: World, defId: string, members: string[], formatio
const c = w.memberById(id)
c.state = 'expedition'
})
// 世界秘境灵气消耗(有 sim 时)
if (w.state.worldSim?.secretQi) {
const qi = w.state.worldSim.secretQi[def.id] as number | undefined
if (qi !== undefined) {
w.state.worldSim.secretQi[def.id] = Math.max(0, qi - 6)
} else {
w.state.worldSim.secretQi[def.id] = 44
}
}
w.state.missions.push(m)
w.state.family.missionIds.push(m.id)
w.log('info', `队伍出发探索【${def.name}】。`)
+8 -2
View File
@@ -45,6 +45,12 @@ export interface WorldEventBus {
onPluginChange?(id: string, action: string): void
}
import { WorldSim } from '../sim/WorldSim'
export function worldSimOf(w: World): WorldSim {
return new WorldSim(w)
}
export function normalizeGameState(state: GameState): GameState {
// 老版本存档(<0.1.1)缺少新增字段,加载时补齐,避免运行期 undefined 崩溃
if (!state.finance) state.finance = { accum: 0 }
@@ -99,12 +105,12 @@ export class World {
normalizeGameState(state)
this.state = state
this.out = out
this.clock = emptyClock()
if (kernel) {
this.clock = kernel.clock
this.kernel = kernel
this.rng = kernel.rng
clockFromKernel(this.clock, kernel.clock)
} else {
this.clock = emptyClock()
this.rng = new Rng(state.rng)
}
this.systems = Object.fromEntries(SYSTEM_DEFS.map((d) => [d.id, { enabled: true }]))
@@ -8,6 +8,7 @@ import { missionTick } from './Systems/missions'
import { eventRoll } from './Systems/events'
import { diplomacyTick } from './Systems/diplomacy'
import { yearStartMarriage } from './Systems/marriage'
import { WorldSim } from '../sim/WorldSim'
/** 原语义保留:满门凋零后仅存生产/寿元与收尾 */
function ifAlive(fn: (w: World) => void): (w: World) => void {
@@ -55,6 +56,11 @@ export function installCoreSystems(ctx: PluginContext): Array<() => void> {
unsubs.push(clock.register('missions', viaCap('missions', ifAlive((w: World) => missionTick(w)))))
unsubs.push(clock.register('events', viaCap('events', ifAlive((w: World) => eventRoll(w)))))
unsubs.push(clock.register('diplomacy', viaCap('diplomacy', ifAlive((w: World) => diplomacyTick(w)))))
unsubs.push(clock.register('worldsim', (w: World) => {
if (w.sysEnabled('worldsim')) {
new WorldSim(w).tick()
}
}))
unsubs.push(clock.register('epilogue', (w: World) => w.epilogueTick()))
return unsubs