147 lines
3.6 KiB
TypeScript
147 lines
3.6 KiB
TypeScript
/**
|
|
* RPG runtime story 状态与响应共享契约。
|
|
* 该文件只负责 view model、presentation、patch 与 snapshot 回包结构。
|
|
*/
|
|
import type { JsonObject } from './common';
|
|
import type { SavedGameSnapshot, SavedGameSnapshotInput } from './runtime';
|
|
import type {
|
|
RuntimeActionRequest,
|
|
RuntimeActionResponse,
|
|
RuntimeStoryChoiceAction,
|
|
RuntimeStoryChoicePayload,
|
|
RuntimeStoryOptionInteraction,
|
|
Task5RuntimeOptionScope,
|
|
} from './rpgRuntimeStoryAction';
|
|
|
|
export type RuntimeStoryOptionView = {
|
|
functionId: string;
|
|
actionText: string;
|
|
detailText?: string;
|
|
scope: Task5RuntimeOptionScope;
|
|
interaction?: RuntimeStoryOptionInteraction;
|
|
payload?: RuntimeStoryChoicePayload;
|
|
disabled?: boolean;
|
|
reason?: string;
|
|
};
|
|
|
|
export type RuntimeStoryPlayerViewModel = {
|
|
hp: number;
|
|
maxHp: number;
|
|
mana: number;
|
|
maxMana: number;
|
|
};
|
|
|
|
export type RuntimeStoryCompanionViewModel = {
|
|
npcId: string;
|
|
characterId?: string;
|
|
joinedAtAffinity: number;
|
|
};
|
|
|
|
export type RuntimeStoryEncounterViewModel = {
|
|
id: string;
|
|
kind: 'npc' | 'treasure';
|
|
npcName: string;
|
|
hostile: boolean;
|
|
affinity?: number;
|
|
recruited?: boolean;
|
|
interactionActive: boolean;
|
|
battleMode?: 'fight' | 'spar' | null;
|
|
};
|
|
|
|
export type RuntimeStoryStatusViewModel = {
|
|
inBattle: boolean;
|
|
npcInteractionActive: boolean;
|
|
currentNpcBattleMode: 'fight' | 'spar' | null;
|
|
currentNpcBattleOutcome: 'fight_victory' | 'spar_complete' | null;
|
|
};
|
|
|
|
export type RuntimeBattlePresentation = {
|
|
targetId?: string;
|
|
targetName?: string;
|
|
damageDealt?: number;
|
|
damageTaken?: number;
|
|
outcome?: 'ongoing' | 'victory' | 'spar_complete' | 'escaped';
|
|
};
|
|
|
|
export type RuntimeStoryViewModel = {
|
|
player: RuntimeStoryPlayerViewModel;
|
|
encounter: RuntimeStoryEncounterViewModel | null;
|
|
companions: RuntimeStoryCompanionViewModel[];
|
|
availableOptions: RuntimeStoryOptionView[];
|
|
status: RuntimeStoryStatusViewModel;
|
|
};
|
|
|
|
export type RuntimeStoryPresentation = {
|
|
actionText: string;
|
|
resultText: string;
|
|
storyText: string;
|
|
options: RuntimeStoryOptionView[];
|
|
toast?: string | null;
|
|
battle?: RuntimeBattlePresentation | null;
|
|
};
|
|
|
|
export type RuntimeStoryPatch =
|
|
| {
|
|
type: 'story_history_append';
|
|
actionText: string;
|
|
resultText: string;
|
|
}
|
|
| {
|
|
type: 'npc_affinity_changed';
|
|
npcId: string;
|
|
previousAffinity: number;
|
|
nextAffinity: number;
|
|
}
|
|
| {
|
|
type: 'battle_resolved';
|
|
functionId: string;
|
|
targetId?: string;
|
|
damageDealt?: number;
|
|
damageTaken?: number;
|
|
outcome: 'ongoing' | 'victory' | 'spar_complete' | 'escaped';
|
|
}
|
|
| {
|
|
type: 'status_changed';
|
|
inBattle: boolean;
|
|
npcInteractionActive: boolean;
|
|
currentNpcBattleMode: 'fight' | 'spar' | null;
|
|
currentNpcBattleOutcome: 'fight_victory' | 'spar_complete' | null;
|
|
}
|
|
| {
|
|
type: 'encounter_changed';
|
|
encounterId: string | null;
|
|
};
|
|
|
|
export type RuntimeStoryActionRequest =
|
|
RuntimeActionRequest<RuntimeStoryChoiceAction> & {
|
|
snapshot?: SavedGameSnapshotInput;
|
|
};
|
|
|
|
export type RuntimeStoryStateRequest<
|
|
TSnapshotGameState = JsonObject,
|
|
TSnapshotCurrentStory = JsonObject,
|
|
> = {
|
|
sessionId: string;
|
|
clientVersion?: number;
|
|
snapshot?: SavedGameSnapshotInput<
|
|
TSnapshotGameState,
|
|
string,
|
|
TSnapshotCurrentStory
|
|
>;
|
|
};
|
|
|
|
export type RuntimeStoryActionResponse<
|
|
TSnapshotGameState = JsonObject,
|
|
TSnapshotCurrentStory = JsonObject,
|
|
> = RuntimeActionResponse<
|
|
RuntimeStoryViewModel,
|
|
RuntimeStoryPresentation,
|
|
RuntimeStoryPatch
|
|
> & {
|
|
snapshot: SavedGameSnapshot<
|
|
TSnapshotGameState,
|
|
string,
|
|
TSnapshotCurrentStory
|
|
>;
|
|
};
|