- 统一时轮 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(时钟/收集器/四季/年轴/效果全矩阵/死局链/残留防御)
92 lines
3.5 KiB
TypeScript
92 lines
3.5 KiB
TypeScript
import { useMemo, useState } from 'react'
|
|
import { useGameStore } from '../store'
|
|
import { SURNAME_POOL } from '../../game/core/names'
|
|
import { RngHub } from '../../game/core/rng'
|
|
|
|
export default function NewGame() {
|
|
const go = useGameStore((s) => s.go)
|
|
const startNewGame = useGameStore((s) => s.startNewGame)
|
|
const [surname, setSurname] = useState('林')
|
|
const [familyName, setFamilyName] = useState('林家')
|
|
const [motto, setMotto] = useState('耕读传家,术法继世')
|
|
const [difficulty, setDifficulty] = useState<'easy' | 'normal' | 'hard'>('normal')
|
|
const [slot, setSlot] = useState(1)
|
|
const [randoming, setRandoming] = useState(false)
|
|
|
|
const seed = useMemo(() => RngHub.rollSeed(), [randoming])
|
|
|
|
const rollNames = () => {
|
|
setRandoming((r) => !r)
|
|
const s = SURNAME_POOL[Math.floor(Math.random() * SURNAME_POOL.length)]
|
|
setSurname(s)
|
|
setFamilyName(`${s}氏`)
|
|
}
|
|
|
|
return (
|
|
<div className="newgame">
|
|
<div className="newgame-box">
|
|
<div className="card-title" style={{ textAlign: 'center', fontSize: '1.4rem' }}>
|
|
— 创建家族 —
|
|
</div>
|
|
<div className="field">
|
|
<label>姓氏</label>
|
|
<input value={surname} onChange={(e) => setSurname(e.target.value)} maxLength={2} />
|
|
<button className="btn btn-sm" onClick={rollNames}>随机</button>
|
|
</div>
|
|
<div className="field">
|
|
<label>家号</label>
|
|
<input value={familyName} onChange={(e) => setFamilyName(e.target.value)} maxLength={10} placeholder="例如:林氏" />
|
|
</div>
|
|
<div className="field">
|
|
<label>祖训</label>
|
|
<input value={motto} onChange={(e) => setMotto(e.target.value)} maxLength={20} />
|
|
</div>
|
|
<div className="field">
|
|
<label>难度</label>
|
|
<div className="diff-grid">
|
|
{(
|
|
[
|
|
['easy', '顺境', '灵石丰足,时来运转'],
|
|
['normal', '中庸', '中规中矩,全靠经营'],
|
|
['hard', '逆境', '部曲拮据,波折不断']
|
|
] as const
|
|
).map(([k, label, desc]) => (
|
|
<div
|
|
key={k}
|
|
className={`diff-opt ${difficulty === k ? 'sel' : ''}`}
|
|
onClick={() => setDifficulty(k)}
|
|
>
|
|
<div>{label}</div>
|
|
<div className="dim2" style={{ fontSize: '0.78rem', marginTop: 2 }}>{desc}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div className="field">
|
|
<label>存档位</label>
|
|
<select value={slot} onChange={(e) => setSlot(Number(e.target.value))}>
|
|
<option value={1}>第一档</option>
|
|
<option value={2}>第二档</option>
|
|
<option value={3}>第三档</option>
|
|
<option value={4}>第四档</option>
|
|
</select>
|
|
</div>
|
|
<div style={{ display: 'flex', gap: 12, justifyContent: 'center', marginTop: 8 }}>
|
|
<button className="btn" onClick={() => go('boot')}>返回</button>
|
|
<button
|
|
className="btn btn-primary btn-lg"
|
|
onClick={() => {
|
|
void startNewGame({ seed, surname, familyName, motto, difficulty }, slot)
|
|
}}
|
|
>
|
|
缔 造 家 族
|
|
</button>
|
|
</div>
|
|
<div className="dim2" style={{ textAlign: 'center' }}>
|
|
你将扮演家主,经营一族兴衰:修炼突破、内外经营、结交应敌,直至百年之后。
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|