v0.1.2: 宗族气韵(职事/悟道/谱系/碑录/庆典/飞升/音效)

- 职事任命:长老(+修炼)/供奉(+战力)/执事(+坊市)/掌教(+闭关) 每人加成叠加,上限管理
- 功法悟道:修习积悟性点,小成/大成逐级+战力,大境界突破传道于直系晚辈
- 宗族谱系页:世代分带 + 夫妻同卷 + 子孙连枝,点节点开详情,先人簿可查
- 功德碑:宗主辞世即勒石,宗祠页碑录永存
- 百年庆典 + 飞升之路事件链(留世坐镇/仙风入体 或 云游飞升/宗族蒙荫)
- 合成音效(WebAudio):鼓点/钟鸣/纸韵/磬响,设置页开关
- 单测 29→38;typecheck/build 通过;GUI 冒烟受限于 WSLg 掉线(SMOKE-TIMEOUT 优雅退出)
This commit is contained in:
Hermes Agent
2026-08-23 08:28:49 +08:00
parent de491c997f
commit 839adc24a6
22 changed files with 864 additions and 8 deletions
+17 -1
View File
@@ -5,9 +5,10 @@ import { findEvent, applyEventChoice } from '../game/engine/systems/events'
import { BattleLog, ChronicleEntry, GameState, LogItem, SaveMeta, YearlyReport, SnapshotMeta } from '../game/types/domain'
import { getSlotManager, getSaveSlot } from '../game/storage/db'
import { metaFromState, updateSlotMeta } from './storeHelper'
import { setSoundEnabled, sPaper, sGood, sBad, sWar, sBell, sGong, sClick, sTick } from './sound'
export type Screen = 'boot' | 'newgame' | 'game'
export type PanelId = 'family' | 'territory' | 'market' | 'diplomacy' | 'expedition' | 'chronicle' | 'settings'
export type PanelId = 'family' | 'genealogy' | 'territory' | 'market' | 'diplomacy' | 'expedition' | 'chronicle' | 'settings'
export interface GameStore {
screen: Screen
@@ -28,6 +29,7 @@ export interface GameStore {
gameOverReason?: string
paperReport?: YearlyReport
snapshots: SnapshotMeta[]
soundOn: boolean
init: () => Promise<void>
go: (screen: Screen) => void
@@ -54,6 +56,7 @@ export interface GameStore {
refreshSnapshots: () => Promise<void>
onYearPaper: (report: YearlyReport) => void
closePaper: () => void
toggleSound: () => void
}
const LOG_CAP = 260
@@ -78,6 +81,7 @@ export const useGameStore = create<GameStore>((set, get) => ({
gameOverReason: undefined,
paperReport: undefined,
snapshots: [],
soundOn: true,
init: async () => {
const manager = getSlotManager()
@@ -145,6 +149,7 @@ export const useGameStore = create<GameStore>((set, get) => ({
try {
w.advanceMonth()
w.syncRng()
sTick()
set((s) => ({ revision: s.revision + 1 }))
await Stash.save(st, '自动')
} catch (e) {
@@ -176,12 +181,19 @@ export const useGameStore = create<GameStore>((set, get) => ({
onYearPaper: (report) => {
if (report.year >= 2) {
sPaper()
set({ paperReport: report, speed: 0 })
}
},
closePaper: () => set({ paperReport: undefined }),
toggleSound: () => {
const on = !get().soundOn
set({ soundOn: on })
setSoundEnabled(on)
},
restoreSnapshot: async (snapshotId: string) => {
const st = get()
const file = await getSaveSlot(st.slot)
@@ -299,6 +311,10 @@ function openState(state: GameState, slot: number): void {
function makeBus(st: GameStore): WorldEventBus {
return {
onLog: (kind, text) => {
if (kind === 'good') sGood()
else if (kind === 'bad') sBad()
else if (kind === 'war') sWar()
else if (kind === 'chronicle') sBell()
const w = st.world
st.addLog({ id: logSeq++, kind, text, year: w?.state.year ?? 0, month: w?.state.month ?? 0 })
},