v0.1.34a(修正): 新秘境改种子派生伪随机——零 rng 消耗(修复跨世界/跨跑分叉)

B0 原用 World.rng.chance/pick/int——序列漂移疑虑(实际为模块级全局 EXTRA_MISSIONS 残留污染);
现改为 seed 哈希派生(year/npcSuccessions 异或哈希——纯确定性零 rng),金钟罩序列零伤;
SecretQi/mission def 全走世界状态 s.wonders(每档独立),确定性复跑矩阵恢复绿;
金钟罩 0.1.34 基线固化(功法流派/时节共鸣/warFatigue/换代/断供受控变更——值变序列受控重算 62 例绿)
This commit is contained in:
2026-08-23 22:05:53 +08:00
parent a491b9c54a
commit 3fb64f6e78
7 changed files with 33 additions and 23 deletions
@@ -15,7 +15,8 @@ export function missionTick(w: World): void {
m.stageMonth++
if (m.stageMonth < 2) continue
const def = missionById(m.defId)
const wonderDef = w.state.worldSim?.wonders?.[m.defId] as MissionDef | undefined
const def = wonderDef ?? missionById(m.defId)
const stage = def.stages[m.stage]
if (!stage || m.stageMonth < stage.months) continue
+15 -10
View File
@@ -4,7 +4,7 @@ import { WorldSimState, NpcDynamics, WORLDSIM, ERA_CONF, makeWorldSimState, NpcS
import { pack } from '../../data/registry'
import { ITEMS } from '../../data/items'
import { npcById, getNpcDefs, registerNpcDef, unregisterNpcDef } from '../../data/npcs'
import { allMissions, addMission, WONDER_TEMPLATES, type MissionDef } from '../../data/secrets'
import { allMissions, WONDER_TEMPLATES, type MissionDef } from '../../data/secrets'
import { MAJORS, MAJOR_ORDER } from '../../data/realms'
const MARKET_IDS = ['lingcao', 'lingkuang', 'beastcore', 'lingyu', 'lingmu', 'shoupi', 'lingguo', 'pill-qiyuan', 'pill-ningyuan']
@@ -17,9 +17,9 @@ export class WorldSim {
if (!w.state.worldSim) w.state.worldSim = initSim(w)
const ws = w.state.worldSim as WorldSimState
if (!ws.secretQi || Object.keys(ws.secretQi).length === 0) {
const defs = allMissions()
const defs = [...allMissions(), ...Object.values(ws.wonders ?? {})]
ws.secretQi = {}
for (const m of defs) ws.secretQi[m.id] = 50
for (const m of defs) ws.secretQi[(m as { id: string }).id] = 50
}
return ws
}
@@ -130,18 +130,23 @@ export class WorldSim {
npcTrade(this.w, s, rng.next()) // A4NPC 按 sells/buys 与池交易
driftMarket(s, rng.next(), this.w) // 波动项(保留噪声弹性)
// ---- B0. 新秘境灵机(0.1.34 万象归元:年首机率——乱世×2) ----
// ---- B0. 新秘境灵机(0.1.34 万象归元:种子派生伪随机——零 rng 消耗,确定性天生) ----
if (this.w.state.month === 1) {
const era2 = s.era === 'luanshi' ? 2 : 1
if (rng.chance(worldNum('newSecretChance') * era2)) {
const tpl = rng.pick(WONDER_TEMPLATES)
const seedS = rng.int(1000, 9999)
const ch = worldNum('newSecretChance') * era2
let sh = 0
for (let i = 0; i < this.w.state.seed.length; i++) sh = (sh * 31 + this.w.state.seed.charCodeAt(i)) >>> 0
const pick = ((sh ^ (this.w.state.year * 2654435761) ^ (s.npcSuccessions * 40503)) >>> 0) % 1000 / 1000
if (pick < ch) {
const tpl = WONDER_TEMPLATES[(sh + this.w.state.year) % WONDER_TEMPLATES.length]
const def: MissionDef = {
...tpl,
id: `m-wonder-${seedS}`,
name: `${tpl.icon}地灵诏——${'古幽玄凌'}${rng.int(1, 9)}`
id: `m-wonder-${(sh + this.w.state.year * 7919) % 9000 + 1000}`,
name: `${tpl.icon}地灵诏——${['古', '幽', '玄', '凌'][(sh + this.w.state.year) % 4]}`
}
addMission(def)
s.wonders = s.wonders ?? {}
s.wonders[def.id] = def as unknown as Record<string, unknown>
s.secretQi[def.id] = Math.max(50, s.secretQi[def.id] ?? 50)
s.newsFeed.push({ year: this.w.state.year, month: 1, src: '天机', text: `${def.name} 现世——灵光冲霄,远近皆见。`, kind: 'annal' })
this.w.log('info', `【天下】有异宝出世:${def.name}`)
@@ -58,6 +58,8 @@ export interface WorldSimState {
shortage?: Record<string, number>
/** 断供已播年(id→年——仅始发广播,持续断供不刷屏) */
shortageWarned?: Record<string, number>
/** 0.1.34 新秘境定义(世界状态内——每档独立,绝无全局跨世界污染) */
wonders?: Record<string, unknown>
/** 天下史书(十年一鉴独立留档,免 newsFeed 裁剪;上限 80 页) */
worldAnnals?: { year: number; text: string }[]
/** 世鉴(50/100 年宏观:开局 vs 现在/era 路径/最强家更替——独立数组零漂) */
+2
View File
@@ -229,6 +229,8 @@ export interface GameState {
overfluxYear?: number
warFatigue?: number
shortage?: Record<string, number>
shortageWarned?: Record<string, number>
wonders?: Record<string, unknown>
distress?: { id: string; year: number; month: number }
worldAnnals?: { year: number; text: string }[]
newsFeed?: { year: number; month: number; src: string; text: string; itemId?: string; kind?: string }[]