91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
import { type GameDefinition } from './gameDefinition'
|
|
import { type GameEvent } from './gameEvent'
|
|
import { type GameResult } from './gameResult'
|
|
import { type GameSessionState } from './gameSessionState'
|
|
import { EMPTY_GAME_PRESENTATION_STATE, type GamePresentationState } from '../presentation/presentationState'
|
|
import { ClassicSequentialRule } from '../rules/classicSequentialRule'
|
|
import { type RulePlugin } from '../rules/rulePlugin'
|
|
|
|
export class GameRuntime {
|
|
definition: GameDefinition | null
|
|
plugin: RulePlugin | null
|
|
state: GameSessionState | null
|
|
presentation: GamePresentationState
|
|
lastResult: GameResult | null
|
|
|
|
constructor() {
|
|
this.definition = null
|
|
this.plugin = null
|
|
this.state = null
|
|
this.presentation = EMPTY_GAME_PRESENTATION_STATE
|
|
this.lastResult = null
|
|
}
|
|
|
|
clear(): void {
|
|
this.definition = null
|
|
this.plugin = null
|
|
this.state = null
|
|
this.presentation = EMPTY_GAME_PRESENTATION_STATE
|
|
this.lastResult = null
|
|
}
|
|
|
|
loadDefinition(definition: GameDefinition): GameResult {
|
|
this.definition = definition
|
|
this.plugin = this.resolvePlugin(definition)
|
|
this.state = this.plugin.initialize(definition)
|
|
const result: GameResult = {
|
|
nextState: this.state,
|
|
presentation: this.plugin.buildPresentation(definition, this.state),
|
|
effects: [],
|
|
}
|
|
this.presentation = result.presentation
|
|
this.lastResult = result
|
|
return result
|
|
}
|
|
|
|
startSession(startAt = Date.now()): GameResult {
|
|
return this.dispatch({ type: 'session_started', at: startAt })
|
|
}
|
|
|
|
dispatch(event: GameEvent): GameResult {
|
|
if (!this.definition || !this.plugin || !this.state) {
|
|
const emptyState: GameSessionState = {
|
|
status: 'idle',
|
|
startedAt: null,
|
|
endedAt: null,
|
|
completedControlIds: [],
|
|
currentTargetControlId: null,
|
|
inRangeControlId: null,
|
|
score: 0,
|
|
guidanceState: 'searching',
|
|
}
|
|
const result: GameResult = {
|
|
nextState: emptyState,
|
|
presentation: EMPTY_GAME_PRESENTATION_STATE,
|
|
effects: [],
|
|
}
|
|
this.lastResult = result
|
|
this.presentation = result.presentation
|
|
return result
|
|
}
|
|
|
|
const result = this.plugin.reduce(this.definition, this.state, event)
|
|
this.state = result.nextState
|
|
this.presentation = result.presentation
|
|
this.lastResult = result
|
|
return result
|
|
}
|
|
|
|
getPresentation(): GamePresentationState {
|
|
return this.presentation
|
|
}
|
|
|
|
resolvePlugin(definition: GameDefinition): RulePlugin {
|
|
if (definition.mode === 'classic-sequential') {
|
|
return new ClassicSequentialRule()
|
|
}
|
|
|
|
throw new Error(`未支持的玩法模式: ${definition.mode}`)
|
|
}
|
|
}
|