v0.1.6: 时轮与造化(GameClock/RngHub/时节/年轴/保护)

- 统一时轮 GameClock:七 phase 注册制(production/aging/cultivation/missions/
  events/diplomacy/epilogue) + 年首三钩子(婚配→岁贡→族簿);advanceMonth 化作薄壳;
  新增系统只注册不改本体;alive 守卫、随机序、族簿时序均与重构前逐一等价
- 金钟罩:3 枚 seed × 560 月指纹常驻(重构前后已验证同哈希;时节属有意变更后重固化)
- 统一随机 RngHub:开局播种(crypto UV)、音效白噪独立流、引擎 rng 带 nextCount 审计;
  全工程拔除逻辑侧 Math.random
- 时节系统:春夏秋冬乘子(春田+10%/夏修+5%/秋市+5%/冬闭+8%)入生产与修炼
- 崩溃保护:advance 异常自动存『出险前』档 + 停速提示回档
- 性能预算:dev-only 单 tick>60ms 报最慢 phase
- 横轴年表:十年一格大事/生殇聚合 + 春秋原年轴视图
- 测试 197→225(时钟/收集器/四季/年轴/效果全矩阵/死局链/残留防御)
This commit is contained in:
Hermes Agent
2026-08-23 09:20:52 +08:00
parent 5b40d9158c
commit e91fb6f5a4
29 changed files with 700 additions and 49 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { Character, BattleLog } from '../../types/domain'
import { basePower, describeRealm } from '../../data/realms'
import { ARTIFACT_POWER } from '../../data/items'
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { Character } from '../../types/domain'
import { ROOT_GRADES } from '../../data/elements'
import { masteryRateOfMajor } from '../../data/pacing'
@@ -10,6 +10,7 @@ import { traitBonuses } from '../pcgen'
import { newCharacter } from '../pcgen'
import { MALE_GIVEN, FEMALE_GIVEN } from '../../core/names'
import { ASPIRATION_IDS } from '../../data/aspirations'
import { seasonMod } from '../../data/season'
import { needsTribulation, tribulationEventId } from './tribulation'
export function monthlyRate(w: World, c: Character): number {
@@ -26,6 +27,7 @@ export function monthlyRate(w: World, c: Character): number {
const buildings = st.family.buildings
const juling = buildings['juling'] ?? 0
rate *= 1 + juling * 0.05
rate *= 1 + seasonMod(st.month, 'cult')
rate *= 1 + w.postBonus('expAll')
if (st.family.flag['fengFeiBless']) rate *= 1.05
if (c.traits.includes('fengxian')) rate *= 1.3
@@ -34,7 +36,7 @@ export function monthlyRate(w: World, c: Character): number {
if (fitBonusOf(c).cult) rate *= 1.06
if (c.state === 'meditation') {
rate *= 1.35
rate *= 1 + w.postBonus('meditation')
rate *= 1 + w.postBonus('meditation') + seasonMod(st.month, 'meditation')
const dongfu = buildings['dongfu'] ?? 0
rate *= 1 + dongfu * 0.08
} else if (c.state === 'expedition') {
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { npcById } from '../../data/npcs'
import { findEvent, fire } from './events'
+2 -2
View File
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { Character } from '../../types/domain'
import { Cond, EffectDef, EventDef, EVENTS, MemberEffect } from '../../data/events'
import { MAJOR_ORDER } from '../../data/realms'
@@ -348,7 +348,7 @@ export function rankPower(w: World, c: Character): number {
return order.indexOf(c.realm.major) * 10 + c.realm.minor
}
function applyEffect(w: World, eff: EffectDef, squad?: string[]): void {
export function applyEffect(w: World, eff: EffectDef, squad?: string[]): void {
const s = w.state
const fam = s.family
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { MAJORS } from '../../data/realms'
import { calcLifespan } from '../pcgen'
+1 -1
View File
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { Character } from '../../types/domain'
import { produceOffspring } from './cultivation'
import { yearGrowth } from './diplomacy'
+1 -1
View File
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { MissionState } from '../../types/domain'
import { missionById, MissionDef, ENEMIES } from '../../data/secrets'
import { resolveEncounter, rollWarbooty } from './combat'
@@ -1,5 +1,6 @@
import { World } from '../world'
import type { World } from '../world'
import { aspirationById } from '../../data/aspirations'
import { seasonMod } from '../../data/season'
export function productionTick(w: World): void {
const fam = w.state.family
@@ -15,8 +16,9 @@ export function productionTick(w: World): void {
const fielders = w.aliveMembers().filter((c) => aspirationById(c.aspiration)?.effect.type === 'field').length
const merchants = w.aliveMembers().filter((c) => aspirationById(c.aspiration)?.effect.type === 'market').length
const springMod = seasonMod(w.state.month, 'field')
if (lingtian > 0) {
const v = Math.round(10 * lingtian * (1 + fielders * 0.05))
const v = Math.round(10 * lingtian * (1 + fielders * 0.05 + springMod))
inv.lingcao = (inv.lingcao ?? 0) + v
parts.push(`灵田+${v}灵草`)
}
@@ -34,8 +36,9 @@ export function productionTick(w: World): void {
inv.lingkuang = (inv.lingkuang ?? 0) + v
parts.push(`灵矿+${v}灵矿`)
}
const autumnMod = seasonMod(w.state.month, 'market')
if (fangshi > 0) {
const v = Math.round(55 * fangshi * (1 + w.postBonus('marketIncome') + merchants * 0.03))
const v = Math.round(55 * fangshi * (1 + w.postBonus('marketIncome') + merchants * 0.03 + autumnMod))
fam.stones += v
parts.push(`坊市+${v}灵石`)
}
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { Character } from '../../types/domain'
import { ENEMIES, EnemyDef } from '../../data/secrets'
import { resolveEncounter } from './combat'
@@ -1,4 +1,4 @@
import { World } from '../world'
import type { World } from '../world'
import { Character } from '../../types/domain'
import { nextRealm, MAJOR_ORDER, realmDeathChance, describeRealm } from '../../data/realms'