v0.1.1: 养成闭环 + 管理自主 + 存档安全

- 指婚/续弦:成员详情可主动找人结亲(血亲自动排除、鳏寡可再醮)
- 装备 UI:法宝从府库装备/替换,战力实时反馈
- 御敌点将:劫掠事件可自选迎战阵容(默认 Top4 可改)
- 宗祠祭祖:每两年一次,灵石150 → 声望+6/全族修为小升
- 回档时间轴:每季快照列表,一键回卷(回卷前自动保当前档)
- 战报匣子:史书页全文战报留存可翻阅
- 年度族簿纸笺:每年初弹收支/人丁/战力简报
- 媒人提示条 + 寻衅一年冷却 + 出生率与劫掠频率微调
- 单测 19→29(storage mock roundtrip/回档/指婚血亲/祭祖/寻衅/装备/账本)
This commit is contained in:
Hermes Agent
2026-08-23 08:16:40 +08:00
parent ebef6c1609
commit de491c997f
24 changed files with 734 additions and 26 deletions
+38 -2
View File
@@ -2,7 +2,7 @@ import { create } from 'zustand'
import { World, WorldEventBus } from '../game/engine/world'
import { EventDef } from '../game/data/events'
import { findEvent, applyEventChoice } from '../game/engine/systems/events'
import { BattleLog, ChronicleEntry, GameState, LogItem, SaveMeta } from '../game/types/domain'
import { BattleLog, ChronicleEntry, GameState, LogItem, SaveMeta, YearlyReport, SnapshotMeta } from '../game/types/domain'
import { getSlotManager, getSaveSlot } from '../game/storage/db'
import { metaFromState, updateSlotMeta } from './storeHelper'
@@ -26,6 +26,8 @@ export interface GameStore {
revision: number
toast?: string
gameOverReason?: string
paperReport?: YearlyReport
snapshots: SnapshotMeta[]
init: () => Promise<void>
go: (screen: Screen) => void
@@ -48,6 +50,10 @@ export interface GameStore {
importSave: (slot: number) => Promise<void>
deleteSave: (slot: number) => Promise<void>
refreshSlots: () => Promise<void>
restoreSnapshot: (snapshotId: string) => Promise<void>
refreshSnapshots: () => Promise<void>
onYearPaper: (report: YearlyReport) => void
closePaper: () => void
}
const LOG_CAP = 260
@@ -70,6 +76,8 @@ export const useGameStore = create<GameStore>((set, get) => ({
revision: 0,
toast: undefined,
gameOverReason: undefined,
paperReport: undefined,
snapshots: [],
init: async () => {
const manager = getSlotManager()
@@ -166,6 +174,32 @@ export const useGameStore = create<GameStore>((set, get) => ({
onGameOver: (reason) => set({ gameOverReason: reason, speed: 0, revision: get().revision + 1 }),
onYearPaper: (report) => {
if (report.year >= 2) {
set({ paperReport: report, speed: 0 })
}
},
closePaper: () => set({ paperReport: undefined }),
restoreSnapshot: async (snapshotId: string) => {
const st = get()
const file = await getSaveSlot(st.slot)
await file.open()
await st.saveNow('回档前')
const state = await file.loadState(snapshotId)
if (!state) throw new Error('找不到快照')
openState(state, st.slot)
},
refreshSnapshots: async () => {
const st = get()
const file = await getSaveSlot(st.slot)
await file.open()
const snapshots = await file.listSnapshots()
set({ snapshots })
},
saveNow: async (label = '手动') => {
await Stash.save(get(), label)
},
@@ -239,6 +273,7 @@ export const useGameStore = create<GameStore>((set, get) => ({
const manager = getSlotManager()
const slots = await manager.listSlotMetas()
set({ slots })
void get().refreshSnapshots()
}
}))
@@ -273,7 +308,8 @@ function makeBus(st: GameStore): WorldEventBus {
},
onBattle: (log) => st.onBattle(log),
onPendingEvent: (id) => st.onPendingEvent(id),
onGameOver: (reason) => st.onGameOver(reason)
onGameOver: (reason) => st.onGameOver(reason),
onYearPaper: (entry) => st.onYearPaper(entry)
}
}