Files
ChronicleOfTheImmortalClan/src/renderer/ui/screens/NewGame.tsx
T
thzxx ff6df8054c refactor(0.1.14-P1): 内核归位——game/ 按引擎架构重排(零行为漂移)
结构(旧 game/core+engine → 新 engine/ 域):
- engine/kernel/  时钟/随机/插件协议/fxqueue/timesense/format/urgency/guide/names(原 core)
- engine/narrative/  legacy/报告/列传/谱系/年轴(原 core 叙事族)
- engine/runtime/   World/creation/pcgen/ApiFacade/capabilities/pluginManager/boot/clocks + Systems/*(12 系统)
- engine/sim/     Market(未来 WorldSim 同行)
- 旧 game/core、engine/systems、engine/world.ts 等路径全部废弃(无 re-export 兼容层)

验证:35 套件/967 测试全绿(金钟罩三档零漂移=纯搬迁无行为变化)
typecheck 0 error
2026-08-23 13:23:25 +08:00

93 lines
3.6 KiB
TypeScript

import { useMemo, useState } from 'react'
import { useGameStore } from '../store'
import { SURNAME_POOL } from '../../game/engine/kernel/names'
import { RngHub } from '../../game/engine/kernel/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 idx = Math.floor(RngHub.audioNoise01() * SURNAME_POOL.length)
const s = SURNAME_POOL[Math.min(SURNAME_POOL.length - 1, idx)]
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>
)
}