Files
Genarrative/packages/shared/src/contracts/rpgRuntimeStoryState.ts
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

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
>;
};