v0.1.5: 人物志(志向/渡劫/列传/契合/回声)

- 志向系统:七向(求道/镇族/承宗/商略/兵略/耕读/云游)成年礼自动定志,
  量化加成入修炼/战力/坊市/灵田/添丁/声望,云游减修但际遇更频
- 大境界渡劫:炼气→筑基起,晋升改走劫难事件三选——硬渡/请护法(100灵石)/
  压制来年;护法失败或受牵连;渡劫成败与心性、气血挂勾,高阶有小陨落率
- 灵根本命契合:功法元素×主灵根,契合者修炼+6%/战力+4%,详情页「本命」徽章
- 人物列传:自动列传生成器(生平/修行脉络/历险/姻缘/子嗣/大比/墓志铭),
  成员详情小传分页 + 春秋原列传长卷
- 四邻回声:每两年一桩——友好赠礼/敌视暗桩/中立传闻三态动态事件
- 修复:回声事件 npcId 解析错误、事件优先级(惯例>传闻)
- 测试 176→197(志向加成/契合/渡劫三轨/压制通道/列传结构/回声三态)
This commit is contained in:
2026-08-23 09:08:16 +08:00
parent 98b60076f0
commit 106db18017
17 changed files with 791 additions and 7 deletions
@@ -8,6 +8,24 @@ import { ITEMS, ARTIFACT_POWER } from '../../game/data/items'
import { combatPowerOf } from '../../game/engine/systems/combat'
import { lifespanOf } from '../../game/engine/systems/lifecycle'
import { POSTS, POST_ORDER } from '../../game/data/posts'
import { buildBiography } from '../../game/core/biography'
function aspName(c: Character): string {
const map: Record<string, string> = {
dao: '志向·求道', zhen: '志向·镇族', cheng: '志向·承宗', shang: '志向·商略', bing: '志向·兵略', geng: '志向·耕读', yun: '志向·云游'
}
return map[c.aspiration ?? ''] ?? '志向·未定'
}
function fitTag(c: Character): string | null {
const t = TECHNIQUES.find((x) => x.id === c.techniqueId)
if (!t) return null
return t.element === c.roots.primary ? `本命·${t.element}契合` : null
}
function deadish(c: Character): boolean {
return !c.alive
}
function pillCount(s: GameState, id: string): number {
return s.family.inventory[id] ?? 0
@@ -232,6 +250,28 @@ export function MemberModal({ member }: { member: Character }) {
</div>
)}
{member.alive && (
<div className="mm-sec">
<div className="dim" style={{ marginBottom: 4 }}></div>
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
<span className="tag">{aspName(member)}</span>
{fitTag(member) && <span className="tag gold-t">{fitTag(member)}</span>}
</div>
</div>
)}
<div className="mm-sec">
<div className="dim" style={{ marginBottom: 6 }}></div>
<div className="bio-box">
{buildBiography(w.state, member.id).map((l, i) => (
<div key={i} className={deadish(member) && l.label === '墓志' ? 'gold' : ''}>
{l.label && <b className="bio-label">{l.label} · </b>}
{l.text}
</div>
))}
</div>
</div>
{member.alive && w.canMarry(member.id) && (
<div className="mm-sec">
<div className="dim" style={{ marginBottom: 6 }}></div>