226 lines
5.4 KiB
TypeScript
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;
|
|
};
|