v0.1.15: 深度审计加固(7 P0 + 20+ P1 歼灭)
【引擎层 P0】 - GameEngine.restore 双重时钟注册(回档后整月双跑)→ restore 重建内核+回置 rng 状态 - engineFromSnapshot 必崩(globalThis.__state 从未设)→ 修正带 seed 重建 - DEV 性能分支二次执行整月管线 → 只读告警(绝不重跑) - 引擎 advance 遇待决事件死锁 → resolvePending(idx) 通道(自动化/测试推进) 【WorldSim 大修】 - NPC 换代文案垃圾(n-danxin行情降50%)→ 换代快讯专属文案 - secretQi 假闭环(纯写无读)→ 全秘境初始化+missions 统一 consumeSecretQi - 快讯节流自锁(lastNewsMonth 恒 1 月)→ totalTicks%24 - power 月度收敛坍塌(1400±3)→ 换代/年首化+年度成长 - relation 双重拉零(4 家全 0)→ 交还外交年度漂移 - 市场基准 5 处重复 → POOL_BASE 单一权威;灾年 stale 清理;drift 各池独立噪声 - worldsim 能力卡补全 + normalize 兜底(worldSim/stats 子字段) 【UI/动效/存储】 - ModalShell 三条 CSS 规则真正落地(close 定位/body 滚动/footer 独立底排)——0.1.12 声明未实施项 - fx-canvas:resize 监听移除/mistTimer 清零/reduced 联动/soft 档无雾 + drift 走 gate(过滤器) - 档位 density 脱钩修复;顶栏“止”钮补 onClick;版本号三处统一 0.1.15 - importAll 清 chronicle 表;自动推进季度落盘(手动逐次) - 性能:LogFeed memo / Genealogy computeGenealogy memo / Chronicle deps 修正;死码清除(lastPhaseStats/clockFromKernel/哨兵函数等 12 处) - 删除误入库的“p”游离文件 【测试】979 全绿(36 套件);金钟罩三档 0.1.15 基线固化; typecheck/build 通过
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/** WorldSim —— 世界自进化引擎(game/engine/sim/WorldSim.ts) */
|
||||
import { World } from '../runtime/World'
|
||||
import { WorldSimState, NpcDynamics, WORLDSIM, CALAMITY_EFFECT, CalamityName } from './worldsim-data'
|
||||
import { WorldSimState, NpcDynamics, WORLDSIM, CALAMITY_EFFECT, CalamityName, POOL_BASE } from './worldsim-data'
|
||||
import { pack } from '../../data/registry'
|
||||
import { ITEMS } from '../../data/items'
|
||||
import { npcById } from '../../data/npcs'
|
||||
import { MAJORS, MAJOR_ORDER } from '../../data/realms'
|
||||
@@ -13,7 +14,13 @@ export class WorldSim {
|
||||
private s(): WorldSimState {
|
||||
const w = this.w
|
||||
if (!w.state.worldSim) w.state.worldSim = initSim(w) as never
|
||||
return w.state.worldSim as WorldSimState
|
||||
const ws = w.state.worldSim as WorldSimState
|
||||
if (!ws.secretQi || Object.keys(ws.secretQi).length === 0) {
|
||||
const defs = pack().missions
|
||||
ws.secretQi = {}
|
||||
for (const m of defs) ws.secretQi[m.id] = 50
|
||||
}
|
||||
return ws
|
||||
}
|
||||
|
||||
tick(): void {
|
||||
@@ -37,6 +44,8 @@ export class WorldSim {
|
||||
s.calamityYear = this.w.state.year
|
||||
applyCalamityToMarket(s, cl as CalamityName)
|
||||
this.w.log('bad', `【天下灾年】${cl}——灵植减产,市价将行。`)
|
||||
} else {
|
||||
s.calamity = undefined
|
||||
}
|
||||
|
||||
// ---- A. 资源循环市场(库存自然流向 + 再平衡 + 价格信号) ----
|
||||
@@ -46,7 +55,7 @@ export class WorldSim {
|
||||
evolveNpc(this.w, s, rng.next())
|
||||
|
||||
// ---- E. 天下快讯(节流) ----
|
||||
if (this.w.state.month !== s.lastNewsMonth && this.w.state.totalTicks % WORLDSIM.newsEvery === 0) {
|
||||
if ((this.w.state.totalTicks % WORLDSIM.newsEvery) === 0) {
|
||||
pushNews(this.w, s, MARKET_IDS)
|
||||
}
|
||||
|
||||
@@ -54,13 +63,19 @@ export class WorldSim {
|
||||
if (s.newsFeed.length > WORLDSIM.newsKeep) s.newsFeed.splice(0, s.newsFeed.length - WORLDSIM.newsKeep)
|
||||
}
|
||||
|
||||
/** 秘境探索消耗灵气(missions 调用) */
|
||||
consumeSecretQi(id: string, amount: number): void {
|
||||
/** 秘境探索消耗灵气(missions 调用;统一入口,默认 6 点) */
|
||||
consumeSecretQi(id: string, amount = 6): void {
|
||||
const s = this.s()
|
||||
if (s.secretQi[id] === undefined) s.secretQi[id] = 50
|
||||
s.secretQi[id] = clamp(s.secretQi[id] - amount, 0, 100)
|
||||
}
|
||||
|
||||
/** 秘境灵气对探索收益的门槛(低灵气收益衰减提示) */
|
||||
secretQiOf(id: string): number {
|
||||
const s = this.s()
|
||||
return s.secretQi[id] ?? 50
|
||||
}
|
||||
|
||||
/** 灵气系数(修炼/掉落市场乘子) */
|
||||
tideMult(): number {
|
||||
return this.s().tide
|
||||
@@ -99,8 +114,6 @@ function initSim(w: World): WorldSimState {
|
||||
relationsWithOthers: {}
|
||||
}
|
||||
}
|
||||
for (const sid of Object.keys(w.state.missions ?? {})) void sid
|
||||
// 秘境灵气初始(从 mission 定义 id)
|
||||
s.secretQi = {}
|
||||
return s
|
||||
}
|
||||
@@ -121,12 +134,15 @@ function empty(): WorldSimState {
|
||||
}
|
||||
|
||||
function driftMarket(s: WorldSimState, noise: number): void {
|
||||
let n = noise
|
||||
for (const id of MARKET_IDS) {
|
||||
const per = n; n += 0.13
|
||||
const base = poolBase(id)
|
||||
const cur = s.marketPool[id] ?? base
|
||||
// 向基准再平衡 + 噪声漂移(价格弹性)
|
||||
const rebalance = (base - cur) * WORLDSIM.marketRebalance
|
||||
const drift = (noise - 0.5) * WORLDSIM.marketDriftRate * base
|
||||
const drift = ((per % 1) - 0.5) * WORLDSIM.marketDriftRate * base
|
||||
|
||||
s.marketPool[id] = Math.max(base * 0.3, cur + rebalance + drift)
|
||||
}
|
||||
}
|
||||
@@ -139,9 +155,8 @@ function applyCalamityToMarket(s: WorldSimState, cl: CalamityName): void {
|
||||
}
|
||||
|
||||
function poolBase(id: string): number {
|
||||
return MARKET_BASE[id] ?? 100
|
||||
return POOL_BASE[id] ?? 100
|
||||
}
|
||||
const MARKET_BASE: Record<string, number> = { lingcao: 600, lingkuang: 300, beastcore: 80, 'pill-qiyuan': 90, 'pill-ningyuan': 40 }
|
||||
|
||||
function evolveNpc(w: World, s: WorldSimState, noise: number): void {
|
||||
void noise
|
||||
@@ -149,15 +164,18 @@ function evolveNpc(w: World, s: WorldSimState, noise: number): void {
|
||||
for (const [id, npc] of Object.entries(w.state.npcFamilies)) {
|
||||
const dyn = s.npcDyn[id] ?? initDynFor(id)
|
||||
s.npcDyn[id] = dyn
|
||||
dyn.leaderAge++
|
||||
// 宗主换代:寿终(年龄>预期)
|
||||
const def = npcById(id)
|
||||
const lifespan = MAJORS[def.leaderRealm].lifespan
|
||||
if (dyn.leaderAge > lifespan * 0.9 || w.rng.chance(0.006)) {
|
||||
if (!w.rng.chance(0.25)) {
|
||||
const curRealm = MAJOR_ORDER[dyn.leaderRealmIdx] ?? def.leaderRealm
|
||||
const lifespan = MAJORS[curRealm].lifespan
|
||||
if (w.state.month === 1) {
|
||||
dyn.leaderAge++
|
||||
// 换代评估:寿终阈值 或 年首小概率(退隐/遇害)——约 50 年一代
|
||||
const chanceNow = dyn.leaderAge > lifespan * 0.9 ? 0.5 : 0.02
|
||||
if (w.rng.chance(chanceNow) && !w.rng.chance(0.25)) {
|
||||
dyn.leaderAge = 30 + w.rng.int(0, 25)
|
||||
dyn.leaderRealmIdx = Math.min(dyn.leaderRealmIdx + 1, 5)
|
||||
dyn.leaderName = `${def.name.replace('氏', '')}氏新主`
|
||||
npc.power = Math.round(Math.max(40, npc.power + 15))
|
||||
dyn.lastEvent = '宗祧更替'
|
||||
dyn.lastEventYear = year
|
||||
s.npcSuccessions++
|
||||
@@ -165,11 +183,7 @@ function evolveNpc(w: World, s: WorldSimState, noise: number): void {
|
||||
w.log('info', `【天下】${def.name} 更易宗主,气象一新。`)
|
||||
}
|
||||
}
|
||||
// 势力聚合:境界+财力+兵员(前有 power 为基础)
|
||||
npc.power = Math.max(40, Math.round(npc.power * 0.95 + (dyn.leaderRealmIdx * 20 + 40) * 0.5))
|
||||
if (Math.abs(npc.relation) > 2) {
|
||||
npc.relation += w.rng.chance(0.5) ? 0 : (npc.relation > 0 ? -0.3 : 0.3)
|
||||
}
|
||||
void npc
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,18 +203,28 @@ function pushNews(w: World, s: WorldSimState, about: string[]): void {
|
||||
const rng = w.rng
|
||||
const idx = rng.int(0, about.length - 1)
|
||||
const id = about[idx]
|
||||
const pool = s.marketPool[id] ?? 50
|
||||
const base = poolBase(id)
|
||||
const pct = Math.round(((pool - base) / base) * 100)
|
||||
const itemName = ITEMS[id]?.name ?? id
|
||||
const tide = s.tide > 1.0 ? '灵潮上涨' : s.tide < 0.75 ? '灵潮回落' : '汐平'
|
||||
const row = {
|
||||
year: w.state.year,
|
||||
month: w.state.month,
|
||||
src: id.startsWith('n-') ? npcById(id).name : `世界·${itemName}`,
|
||||
text: id.startsWith('n-')
|
||||
? `${npcById(id).name} 世务维系(宗主更替率);${tide}。${pct !== 0 ? `${itemName}行情${pct > 0 ? '升' : '降'}${Math.abs(pct)}%` : ''}`
|
||||
: `${tide}·${itemName}行情${pct > 0 ? '升' : '降'}${Math.abs(pct)}%`
|
||||
let row: { year: number; month: number; src: string; text: string }
|
||||
if (id.startsWith('n-')) {
|
||||
const def = npcById(id)
|
||||
const dyn = s.npcDyn[id]
|
||||
row = {
|
||||
year: w.state.year,
|
||||
month: w.state.month,
|
||||
src: def.name,
|
||||
text: dyn ? `灵潮气象:${dyn.leaderName} 宗主更替,势力重排。` : `${def.name} 世务新张。`
|
||||
}
|
||||
} else {
|
||||
const pool = clamp(s.marketPool[id] ?? poolBase(id), POOL_BASE[id] * 0.5, POOL_BASE[id] * 1.8)
|
||||
const base = poolBase(id)
|
||||
const pct = Math.round(((pool - base) / base) * 100)
|
||||
const itemName = ITEMS[id]?.name ?? id
|
||||
row = {
|
||||
year: w.state.year,
|
||||
month: w.state.month,
|
||||
src: `世界·${itemName}`,
|
||||
text: pct !== 0 ? `${itemName}行情${pct > 0 ? '升' : '降'}${Math.abs(pct)}% (${tide})` : `${itemName}行情平稳 (${tide})`
|
||||
}
|
||||
}
|
||||
s.newsFeed.push(row)
|
||||
s.lastNewsMonth = w.state.month
|
||||
|
||||
@@ -50,6 +50,15 @@ export function makeWorldSimState(): WorldSimState {
|
||||
}
|
||||
}
|
||||
|
||||
/** 市场基准库存(单一权威:WorldSim 再平衡 / Market 行情 / brief 图标 三方共用) */
|
||||
export const POOL_BASE: Record<string, number> = {
|
||||
lingcao: 600,
|
||||
lingkuang: 300,
|
||||
beastcore: 80,
|
||||
'pill-qiyuan': 90,
|
||||
'pill-ningyuan': 40
|
||||
}
|
||||
|
||||
/** 世界演化参数表(全部可调) */
|
||||
export const WORLDSIM = {
|
||||
marketDriftRate: 0.03,
|
||||
|
||||
Reference in New Issue
Block a user