import { useState } from 'react' import { useGameStore } from '../store' import { computeLegacy, resolveLegacy } from '../../game/engine/narrative/legacy' import { ResolveModal } from '../components/ResolveModal' import { buildBiography } from '../../game/engine/narrative/biography' import { yearAxis, decadeLabel } from '../../game/engine/narrative/yearaxis' import { buildReport, verdictLine } from '../../game/engine/narrative/legacyreport' import { buildSaga, sagaKindName, sagaKindClass } from '../../game/engine/narrative/saga' import { buildChronicleScroll, scrollKindName, scrollKindClass } from '../../game/engine/narrative/chronicle-scroll' import type { WorldSimState } from '../../game/engine/sim/worldsim-data' export default function LegacyPanel() { const world = useGameStore((s) => s.world) const revision = useGameStore((s) => s.revision) void revision const [showResolve, setShowResolve] = useState(false) const [view, setView] = useState<'dims' | 'chronicle' | 'report' | 'scroll' | 'axis' | 'legacy' | 'cscroll'>('dims') if (!world) return null const w = world const s = w.state const dims = computeLegacy(s) const arch = resolveLegacy(s) const resolved = !!s.family.flag['resolved'] const yearly = s.yearlyReports.slice().sort((a, b) => a.year - b.year) const births = Object.values(s.members).filter((c) => c.bornYear >= 0) const genMin = Math.min(...Object.values(s.members).map((c) => c.bornYear)) const genMax = Math.max(...Object.values(s.members).map((c) => c.deathYear ?? s.year)) return (
春秋原:家族百年气数之图。望气可预演四维,落印后方入青册(不阻继续行旅)。
当前气数 · 预演称号 {arch.title} {resolved && 已定局}
存续{s.year}年 · {s.family.generation}代 · 声望峰值{s.stats.repPeak} · 丁口峰值{s.stats.popPeak} {s.stats.tourneyBest ? ` · 大比最佳第${s.stats.tourneyBest}名` : ''}
{!resolved && ( )}
{view === 'dims' && (
气数四维
{Object.entries(dims) .filter(([k]) => k !== 'total') .map(([k, v]) => (
{dimName(k)}
{v}
))}
总评
{dims.total}
人兴=代数·丁口峰值 · 道兴=最高境界·功法大成 · 威名=声望峰·大比最佳 · 香火=存续·飞升 · 因果=功德善恶
)} {view === 'report' && (
岁末族簿汇编(逐年)
{yearly.slice(-20).map((r) => ( ))}
灵石盈亏诞辰辞世声望宗族战力
{r.year}年 = 0 ? 'good' : 'bad'}>{r.nets >= 0 ? `+${r.nets}` : r.nets} +{r.births} -{r.deaths} {r.rep} {r.power}
共 {yearly.length} 年度账册。
)} {view === 'legacy' && } {view === 'axis' && } {view === 'scroll' && } {view === 'cscroll' && } {view === 'chronicle' && (
生卒与突破年表
族人生卒带(首倡 {genMin + s.year - s.year} 年 ~ 卒 {genMax} 年,区间 {genMax - genMin} 载)
大比记录:{s.stats.tourneyHistory.length === 0 ? '尚无参赛记录' : s.stats.tourneyHistory.map((t) => `${t.year}年第${t.rank}名`).join('、')}
突破年表(按年份计数): {breakdown(s).length === 0 ? '暂无' : breakdown(s).map((b) => `${b.year}年×${b.n}`).join(' · ')}
)} {showResolve && setShowResolve(false)} />}
) } function LegacyReportView() { const world = useGameStore((s) => s.world) if (!world) return null const r = buildReport(world.state) const span = r.years.length return (
百年族史报告
{span < 4 ? (
开卷尚浅,待岁月沉淀后再启此卷。
) : ( <>
死因榜:{Object.entries(r.deathCauses).filter(([k]) => k !== '').sort((a, b) => b[1] - a[1]).slice(0, 4).map(([k, v]) => `${k}×${v}`).join(' · ') || '尚无记录'}
突破之劲:{r.breakthroughs.slice(-6).map((b) => `${b.year}年×${b.count}`).join(' · ')}
{verdictLine(r)}
{/* 0.1.40 天下大事记摘要 */} {(() => { const ws = world.state.worldSim as WorldSimState | undefined if (!ws) return null const saga = buildSaga(ws).slice(0, 12) if (saga.length === 0) return null return (
天下大事记摘要:
{saga.map((e, i) => (
{e.year}年 {sagaKindName(e.kind)} {e.text}
))}
) })()} )}
) } function Sparklines({ r }: { r: ReturnType }) { const width = 640 const height = 150 const pts = (seq: number[], color: string) => { const max = Math.max(...seq, 1) const step = seq.length > 1 ? width / (seq.length - 1) : width return seq.map((v, i) => `${(i * step).toFixed(1)},${(height - 20 - (v / max) * (height - 40)).toFixed(1)}`).join(' ') } return ( 人口 声望 战力 ) } function AxisView() { const world = useGameStore((s) => s.world) if (!world) return null const cells = yearAxis(world.state) return (
横轴年表(十年一格)
{cells.map((c) => (
{decadeLabel(c.from, c.to)}
生 {c.births} 殇 {c.deaths} {c.events.slice(0, 6).map((e, i) => ( {e.kind}·{e.year}年 {e.label} ))} {c.events.length > 6 && …还有{c.events.length - 6}件}
))}
) } function ScrollScroll() { const world = useGameStore((s) => s.world) if (!world) return null const mem = Object.values(world.state.members).sort((a, b) => b.generation - a.generation || b.bornYear - a.bornYear) return (
列传长卷
{mem.slice(0, 40).map((c) => { const bio = buildBiography(world.state, c.id) const isAscended = c.deathCause === '飞升太虚' || c.deathCause === '云游飞升' const isAscensionFall = c.deathCause === '飞升劫陨' const isFengxian = c.traits.includes('fengxian') && c.alive return (
{c.name} {isAscended && 飞升} {isAscensionFall && 劫陨} {isFengxian && 留仙} {bio.map((l) => l.text).join(' ').slice(0, 90)}{bio.map((l) => l.text).join(' ').length > 90 ? '……' : ''}
) })}
) } function ChronicleScrollView() { const world = useGameStore((s) => s.world) if (!world) return null const ws = world.state.worldSim as WorldSimState | undefined const scroll = buildChronicleScroll(world.state, ws) return (
族史卷(天命·族事·天下 串联)
{scroll.length === 0 ? (
开卷尚浅,待岁月沉淀后再启此卷。
) : (
{scroll.map((e, i) => (
{e.year}年 {scrollKindName(e.kind)} {e.text}
))}
)}
族史卷将天命决策、族中大事与天下大事记串联展示——以时间为经、以事件为纬。
) } function dimName(k: string): string { const map: Record = { renXing: '人兴', daoXing: '道兴', weiMing: '威名', xiangHuo: '香火', yinGuo: '因果' } return map[k] ?? k } function breakdown(s: { chronicle: { category: string; year: number }[] }): { year: number; n: number }[] { const counts = new Map() for (const e of s.chronicle) { if (e.category === 'breakthrough') { const cur = counts.get(e.year) ?? 0 counts.set(e.year, cur + 1) } } return [...counts.entries()].map(([year, n]) => ({ year, n })).sort((a, b) => a.year - b.year) }