v0.1.11: 全源码审计 + 缺陷歼灭 + UI/UX 打磨
【引擎审计修复】 - P0:大比 once(原整年刷 12 场、奖励通胀);flag 年份键 3 年剪枝(长线膨胀) - P1:飞升离世累加 feishengCount(飞升之资称号可达);圣者护族接消费(原死代码); 大比/传薪挂能力卡门控;pending 抢渡劫时不再重设 - P2:version 硬编码统一 0.1.11;yearaxis 飞升归类;MonumentList 挂载 【UI 审计修复】 - P0:已故成员卡显示「已殁」(原秀活动 status);空队迎战禁用+提示(原静默失效) - P1:指婚候选去截断(滚动列表);终局出口(回卷/主菜单按钮);saveNow 反馈; 事件来临写入 feed(k-event 使用);遣队「最强 N 人/清空」一键;寻衅确认+联姻原因提示; 未建建筑视觉 uc 类 - P2:speed 死代码;Modal 分层 z-index;FamilyPanel 在世/先人分隔 【UX 三件套】 - 警讯徽章(瓶颈/重伤/在外/媒缘/孤嗣之忧)顶栏一屏秒答「我该干嘛」 - 首启引导任务条(四步目标 + 完成推进,可跳不强制) - 顶栏丹药瘦身(4 资源);数字千/万化;瓶颈卡红框高亮 【测试】905→923(urgency/guide/format 三模块 + 审计修复回归 6 项) 金钟罩三档重固化(0.1.11),typecheck/build 通过
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
export function fmt(n: number): string {
|
||||
const abs = Math.abs(n)
|
||||
if (abs >= 10000) return `${(n / 10000).toFixed(1)}万`
|
||||
if (abs >= 1000 && abs < 10000) {
|
||||
// 1.2千
|
||||
const t = Math.floor(abs / 1000)
|
||||
const rem = Math.floor((abs % 1000) / 100)
|
||||
return rem > 0 ? `${n < 0 ? '-' : ''}${t}.${rem}千` : `${n < 0 ? '-' : ''}${t}千`
|
||||
}
|
||||
return String(n)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { World } from '../engine/world'
|
||||
|
||||
export interface GuideStep {
|
||||
id: string
|
||||
title: string
|
||||
hint: string
|
||||
reward: string
|
||||
}
|
||||
|
||||
export const GUIDE_STEPS: GuideStep[] = [
|
||||
{ id: 'intro', title: '认识你的族人', hint: '点开「宗族」页中任意成员,看看他的灵根、境界与禀性。', reward: '感悟 +20 灵石' },
|
||||
{ id: 'cultivate', title: '点一人闭关', hint: '在成员详情中点「闭关」,让他专心致志地修行。', reward: '修为小成' },
|
||||
{ id: 'build', title: '营建一项产业', hint: '到「领地」页营建一座【灵田】或【坊市】,让家中有进项。', reward: '家族起步' },
|
||||
{ id: 'progress', title: '推进一个月', hint: '点顶部「推进一月」,看族人锻、金堂响、家书至。', reward: '正式开族' }
|
||||
]
|
||||
|
||||
export interface GuideState {
|
||||
step: number
|
||||
done: boolean
|
||||
}
|
||||
|
||||
export function computeGuide(w: World): GuideState {
|
||||
const step = w.state.family.flag['guideStep'] as number | undefined ?? 0
|
||||
return { step, done: step >= GUIDE_STEPS.length }
|
||||
}
|
||||
|
||||
export function guideAdvance(w: World, targetStep: number): number {
|
||||
const cur = w.state.family.flag['guideStep'] as number | undefined ?? 0
|
||||
if (targetStep > cur) {
|
||||
w.state.family.flag['guideStep'] = Math.min(GUIDE_STEPS.length, targetStep)
|
||||
}
|
||||
return w.state.family.flag['guideStep'] as number
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { World } from '../engine/world'
|
||||
|
||||
export interface Urgency {
|
||||
blockedCount: number
|
||||
injuredCount: number
|
||||
missionCount: number
|
||||
marriageReady: number
|
||||
noHeir: boolean
|
||||
headFrail: boolean
|
||||
}
|
||||
|
||||
export function computeUrgency(w: World): Urgency {
|
||||
const alive = w.aliveMembers()
|
||||
const blockedCount = alive.filter((c) => c.realmProgress >= 100 && c.realm.major !== 'spirit').length
|
||||
const injuredCount = alive.filter((c) => c.state === 'wounded' || c.health < 30).length
|
||||
const missionCount = w.state.missions.filter((m) => !m.done).length
|
||||
const marriageReady = alive.filter(
|
||||
(c) => c.state !== 'expedition' && c.state !== 'apprentice' && (!c.spouseId || w.isWidowed(c)) && w.ageOf(c) >= 16 && w.ageOf(c) <= 46
|
||||
).length
|
||||
const head = w.state.members[w.state.family.headId]
|
||||
const headFrail = !!head && head.alive && w.ageOf(head) > 55
|
||||
const adultHeir = alive.some((c) => c.id !== head?.id && w.ageOf(c) >= 16)
|
||||
const noHeir = !adultHeir || !head?.alive
|
||||
return { blockedCount, injuredCount, missionCount, marriageReady, noHeir, headFrail }
|
||||
}
|
||||
@@ -36,7 +36,7 @@ export function yearAxis(s: GameState, decadeSize = 10): AxisCell[] {
|
||||
: e.category === 'birth'
|
||||
? null
|
||||
: e.category === 'death'
|
||||
? '殇'
|
||||
? /飞升/.test(e.text) ? '飞升' : '殇'
|
||||
: e.category === 'marriage'
|
||||
? '婚'
|
||||
: e.category === 'battle'
|
||||
|
||||
@@ -136,7 +136,7 @@ export class GameFacade {
|
||||
about(): { title: string; version: string; modules: number; systems: number; plugins: number; packFingerprint: string } {
|
||||
return {
|
||||
title: '仙途家族志',
|
||||
version: '0.1.8',
|
||||
version: '0.1.11',
|
||||
modules: this.world.systemList().length,
|
||||
systems: this.world.systemList().filter((s) => s.enabled).length,
|
||||
plugins: this.world.pluginList().length,
|
||||
|
||||
@@ -63,6 +63,7 @@ export function dynamicEventFor(id: string, w?: World): EventDef | undefined {
|
||||
name: '太虚大比',
|
||||
category: 'major',
|
||||
weight: 0,
|
||||
once: true,
|
||||
text: `太虚仙盟五年一会,新一期大比于祖庭开擂。观礼之众云集,百族竞锋——可遣嫡系赴赛,亦可称病让席。`,
|
||||
options: [
|
||||
{ label: '点将赴赛', hint: '战三关,位次定声望', eff: { tournament: true, flag: { [`tournamentYear-${year}`]: true } } },
|
||||
@@ -321,7 +322,7 @@ export function eventRoll(w: World): void {
|
||||
|
||||
// 五年一会的太虚大比(该年任一时刻优先;其他年次要事件避让)
|
||||
const tourneyNext = Math.ceil(s.year / 5) * 5
|
||||
if (s.year >= 10 && s.year === tourneyNext && !s.completedEvents.includes(`ev-tournament-${tourneyNext}`)) {
|
||||
if (s.year >= 10 && s.year === tourneyNext && w.sysEnabled('tournament') && !s.completedEvents.includes(`ev-tournament-${tourneyNext}`)) {
|
||||
const tk = `tourneyPending-${tourneyNext}`
|
||||
if (w.state.pendingEvent) {
|
||||
// 另有事件在档:加入等待队列(事件优先)——用 flag 标记,防重复入队
|
||||
@@ -335,7 +336,7 @@ export function eventRoll(w: World): void {
|
||||
return
|
||||
}
|
||||
// 名宿传薪(每八年一掷)
|
||||
if (s.year % 8 === 4 && !s.completedEvents.includes('ev-legacypass')) {
|
||||
if (s.year % 8 === 4 && w.sysEnabled('apprentice') && !s.completedEvents.includes('ev-legacypass')) {
|
||||
const elder = w.aliveMembers().some((c) => w.ageOf(c) >= 66 && c.realm.major !== 'mortal')
|
||||
if (elder) {
|
||||
fire(w, 'ev-legacypass')
|
||||
@@ -581,6 +582,7 @@ export function applyEffect(w: World, eff: EffectDef, squad?: string[]): void {
|
||||
immortal.alive = false
|
||||
immortal.deathYear = s2.year
|
||||
immortal.deathCause = '云游飞升'
|
||||
s2.stats.feishengCount = (s2.stats.feishengCount ?? 0) + 1
|
||||
s2.family.flag['fengFeiBless'] = true
|
||||
w.chronicle('event', `${immortal.name} 于月首孤身东去,驾鹤而飞。天地留一缕仙风,庇佑宗族。`, immortal.id, true)
|
||||
w.log('good', `${immortal.name} 飞升而去,宗族蒙庇。`)
|
||||
|
||||
@@ -295,6 +295,17 @@ export class World {
|
||||
s.finance.accum += stonesEnd - stonesStart
|
||||
this.trackStats()
|
||||
this.clampState()
|
||||
this.pruneYearFlags()
|
||||
}
|
||||
|
||||
/** 年度清理:剔除 3 年以前的年份前缀 flag 键(防长线膨胀) */
|
||||
private pruneYearFlags(): void {
|
||||
const fam = this.state.family
|
||||
const cutoff = this.state.year - 3
|
||||
for (const key of Object.keys(fam.flag)) {
|
||||
const m = /^(auction-|prayerDone-|echoDone-|recruitDone-)(\d+)$/.exec(key)
|
||||
if (m && Number(m[2]) < cutoff) delete fam.flag[key]
|
||||
}
|
||||
}
|
||||
|
||||
/** 月底统一数值钳制:修为/气血/库存/金钱永不越界 */
|
||||
|
||||
Reference in New Issue
Block a user