Files
ChronicleOfTheImmortalClan/src/renderer/game/core/biography.ts
T
Hermes Agent 967ef1240d v0.1.8: 万物皆是插件 + 全应用审计修复(60+ 缺陷歼灭)
插件协议:
- CotycPlugin Manifest(dependencies/conflicts/protected/install/uninstall)
- PluginManager:安装序确定性/依赖拒绝/异常回滚/追踪型上下文(卸载全摘钩子)
- 三核心插件常驻(Systems/Data/Events);插件清单/安装移除/启停广播
- EventPoolRegistry 多池合并;facade about/query('plugins')/plugin 订阅
- 设置页插件清单(含卸载按钮、核心保护);examplePlugin 开发范本入仓

全应用审计修复(引擎 39 + UI/主进程 40 双路清单,P0→P2 歼灭):
- P0:单亲 rollRoots 崩/插件事件软锁(findEvent 查池)/fire 覆盖幸存事件/
  facade 未赋值(act 目录 6/24 生效→全量接通)/packOverride 死实现真接管/
  4 能力卡无接线(trib/apprentice/tournament/season)/读档 rowid 方言崩溃/
  buildApprentice 空候选崩/插件安装无回滚/trait 加成从未消费/DEV 双跑破坏时序
- P1:定时器幸存/advance in-flight 闸/battle 暂停/tournament 点将真传/
  史书 memo 依赖/面板 hooks 顺序违规/远征 squad 残留 id/跨档状态残留/
  toast 自清除/读档错误提示/导入后重载世界/pendingEvent 读档回填
- P2:版本三处统一/NewGame 随机收编/学费错误文案/姓氏池去重/
  功法品阶错位(凡阶哨兵)/功法定价对齐/market 白名单校验/
  战利功法去重/回声漏封缄/clock 迭代快照/core 事件池保护/
  渡劫陨落走真突破/寄读 desc 诚实化/doas 死代码清理等 30 项

测试 239→256;金钟罩复验(防御批零漂移)
2026-08-23 09:58:15 +08:00

78 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { GameState } from '../types/domain'
import { TECHNIQUES } from '../data/techniques'
import { describeRealm } from '../data/realms'
import { aspirationById } from '../data/aspirations'
import { postById } from '../data/posts'
export interface BioLine {
at?: number
label: string
text: string
}
export function buildBiography(s: GameState, memberId: string): BioLine[] {
const c = s.members[memberId]
if (!c) return []
const lines: BioLine[] = []
const tech = TECHNIQUES.find((t) => t.id === c.techniqueId)
const asp = aspirationById(c.aspiration)
const post = postById(c.post)
lines.push({
label: '生平',
text: `${c.name},第${c.generation}代子孙${c.gender === 'male' ? '男' : '女'},生于${c.bornYear}${
c.deathYear ? `,殁于${c.deathYear}年(${c.deathCause ?? '寿终'}` : ',今尚在世'
}${post ? `曾居族中「${post.name}」之位。` : ''}${asp ? `平生志向:${asp.name}。` : ''}${
tech ? `主修《${tech.name}》。` : ''
}`
})
// 突破脉络
const breaks = s.chronicle.filter((e) => e.category === 'breakthrough' && e.memberId === c.id)
const trials = s.chronicle.filter((e) => e.text.includes(c.name) && (e.category === 'battle' || e.category === 'exploration'))
for (const e of breaks) {
lines.push({ at: e.year, label: '修行', text: `${e.year}${e.month}月,${e.text.replace(new RegExp(`^${c.name}\\s*`), '')}`})
}
if (trials.length > 0) {
lines.push({ at: trials[0].year, label: '历险', text: `${trials[0].year}年·${trials[0].text}` })
}
// 婚育
const marriages = s.chronicle.filter((e) => e.category === 'marriage' && e.memberId === c.id)
for (const m of marriages) {
lines.push({ at: m.year, label: '姻缘', text: m.text })
}
if (c.children.length > 0) {
const kids = c.children.map((id) => s.members[id]?.name ?? '?').join('、')
lines.push({ label: '子嗣', text: `抚育子女${c.children.length}人:${kids}。` })
}
// 大比
const hisTourneys = s.stats.tourneyHistory.filter((t) => {
const battle = s.battles.find((b) => b.year === t.year && b.title.includes('大比'))
return battle?.lines.some((l) => l.includes(c.name))
})
for (const t of hisTourneys) {
lines.push({ at: t.year, label: '大比', text: `${t.year}年,随队参加太虚大比,列第${t.rank}名。` })
}
// 墓碑铭文
if (!c.alive) {
const epitaph = EPITAPH[c.deathCause ?? '寿终'] ?? '一尘一土,终归青山。'
lines.push({ label: '墓志', text: `${c.name}之墓。${epitaph}` })
}
return lines
}
const EPITAPH: Record<string, string> = {
寿终: '一尘一土,终归青山。子孙焚香,岁岁在此。',
'寿元将尽': '一尘一土,终归青山。子孙焚香,岁岁在此。',
幼夭: '稚子长眠,天地垂爱。家人悬灯,常照归路。',
'伤势不治': '壮士折戟,魂兮归来。家祠之下,与祖同列。',
'突破走火': '一念求道,九死未悔。灵前法灯,为君长明。',
'渡劫陨落': '雷霆战天,其志未竟。遗骨归山,英风尚在。',
'战殁': '马革裹尸,归葬桑梓。长剑挂壁,子孙相传。',
'云游飞升': '此去云深不知处,魂同列宿游太虚。'
}