Files
Genarrative/packages/shared/src/contracts/rpgRuntimeStoryState.ts

226 lines
5.4 KiB
TypeScript

/**
* RPG runtime story 状态与响应共享契约。
* 该文件只负责 view model、presentation、patch 与 snapshot 回包结构。
*/
import type { JsonObject } from './common';
import type {
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' | 'fight_defeat' | 'spar_complete' | null;
};
export type RuntimeStoryInventoryActionView = {
functionId: string;
actionText: string;
payload?: JsonObject;
enabled: boolean;
reason?: string | null;
};
export type RuntimeStoryInventoryItemActionsView = {
use: RuntimeStoryInventoryActionView;
equip: RuntimeStoryInventoryActionView;
dismantle: RuntimeStoryInventoryActionView;
reforge: RuntimeStoryInventoryActionView;
};
export type RuntimeStoryInventoryItemView = {
item: JsonObject;
actions: RuntimeStoryInventoryItemActionsView;
};
export type RuntimeStoryEquipmentSlotView = {
slotId: string;
label: string;
item?: JsonObject | null;
unequip: RuntimeStoryInventoryActionView;
};
export type RuntimeStoryForgeRequirementView = {
id: string;
label: string;
quantity: number;
owned: number;
};
export type RuntimeStoryForgeRecipeView = {
id: string;
name: string;
kind: string;
description: string;
resultLabel: string;
currencyCost: number;
currencyText: string;
requirements: RuntimeStoryForgeRequirementView[];
canCraft: boolean;
disabledReason?: string | null;
action: RuntimeStoryInventoryActionView;
};
export type RuntimeStoryInventoryViewModel = {
playerCurrency: number;
currencyText: string;
inBattle: boolean;
backpackItems: RuntimeStoryInventoryItemView[];
equipmentSlots: RuntimeStoryEquipmentSlotView[];
forgeRecipes: RuntimeStoryForgeRecipeView[];
};
export type RuntimeNpcTradeMode = 'buy' | 'sell';
export type RuntimeNpcTradeItemView = {
itemId: string;
item: JsonObject;
mode: RuntimeNpcTradeMode;
unitPrice: number;
maxQuantity: number;
canSubmit: boolean;
reason?: string | null;
};
export type RuntimeNpcGiftItemView = {
itemId: string;
item: JsonObject;
affinityGain: number;
canSubmit: boolean;
reason?: string | null;
};
export type RuntimeNpcInteractionView = {
npcId: string;
npcName: string;
playerCurrency: number;
currencyName: string;
trade: {
buyItems: RuntimeNpcTradeItemView[];
sellItems: RuntimeNpcTradeItemView[];
};
gift: {
items: RuntimeNpcGiftItemView[];
};
};
export type RuntimeBattlePresentation = {
targetId?: string;
targetName?: string;
damageDealt?: number;
damageTaken?: number;
outcome?: 'ongoing' | 'victory' | 'spar_complete' | 'defeat' | 'escaped';
};
export type RuntimeStoryViewModel = {
player: RuntimeStoryPlayerViewModel;
encounter: RuntimeStoryEncounterViewModel | null;
companions: RuntimeStoryCompanionViewModel[];
inventory: RuntimeStoryInventoryViewModel;
availableOptions: RuntimeStoryOptionView[];
status: RuntimeStoryStatusViewModel;
npcInteraction?: RuntimeNpcInteractionView | null;
};
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' | 'defeat' | 'escaped';
}
| {
type: 'status_changed';
inBattle: boolean;
npcInteractionActive: boolean;
currentNpcBattleMode: 'fight' | 'spar' | null;
currentNpcBattleOutcome: 'fight_victory' | 'fight_defeat' | 'spar_complete' | null;
}
| {
type: 'encounter_changed';
encounterId: string | null;
};
export type RuntimeStoryActionRequest =
{
sessionId: string;
clientVersion?: number;
action: RuntimeStoryChoiceAction;
};
export type RuntimeStoryAiRequestOptions = {
availableOptions?: JsonObject[];
optionCatalog?: JsonObject[];
};
export type RuntimeStoryAiRequest = {
sessionId: string;
clientVersion?: number;
choice?: string;
lastFunctionId?: string | null;
observeSignsRequested?: boolean;
recentActionResult?: string | null;
requestOptions?: RuntimeStoryAiRequestOptions;
};