1
This commit is contained in:
408
packages/shared/src/contracts/story.ts
Normal file
408
packages/shared/src/contracts/story.ts
Normal file
@@ -0,0 +1,408 @@
|
||||
import type { JsonObject } from './common';
|
||||
import type { SavedGameSnapshot } from './runtime';
|
||||
|
||||
export const QUEST_NARRATIVE_TYPES = [
|
||||
'bounty',
|
||||
'escort',
|
||||
'investigation',
|
||||
'retrieval',
|
||||
'relationship',
|
||||
'trial',
|
||||
] as const;
|
||||
export type SharedQuestNarrativeType =
|
||||
(typeof QUEST_NARRATIVE_TYPES)[number];
|
||||
|
||||
export const QUEST_OBJECTIVE_KINDS = [
|
||||
'defeat_hostile_npc',
|
||||
'inspect_treasure',
|
||||
'spar_with_npc',
|
||||
'talk_to_npc',
|
||||
'reach_scene',
|
||||
'deliver_item',
|
||||
] as const;
|
||||
export type SharedQuestObjectiveKind =
|
||||
(typeof QUEST_OBJECTIVE_KINDS)[number];
|
||||
|
||||
export const QUEST_URGENCY_LEVELS = ['low', 'medium', 'high'] as const;
|
||||
export type SharedQuestUrgency = (typeof QUEST_URGENCY_LEVELS)[number];
|
||||
|
||||
export const QUEST_INTIMACY_LEVELS = [
|
||||
'transactional',
|
||||
'cooperative',
|
||||
'trust_based',
|
||||
] as const;
|
||||
export type SharedQuestIntimacy = (typeof QUEST_INTIMACY_LEVELS)[number];
|
||||
|
||||
export const QUEST_REWARD_THEMES = [
|
||||
'currency',
|
||||
'resource',
|
||||
'relationship',
|
||||
'intel',
|
||||
'rare_item',
|
||||
] as const;
|
||||
export type SharedQuestRewardTheme =
|
||||
(typeof QUEST_REWARD_THEMES)[number];
|
||||
|
||||
export const RUNTIME_ITEM_FUNCTIONAL_BIAS_VALUES = [
|
||||
'heal',
|
||||
'mana',
|
||||
'cooldown',
|
||||
'guard',
|
||||
'damage',
|
||||
] as const;
|
||||
export type SharedRuntimeItemFunctionalBias =
|
||||
(typeof RUNTIME_ITEM_FUNCTIONAL_BIAS_VALUES)[number];
|
||||
|
||||
export const RUNTIME_ITEM_TONE_VALUES = [
|
||||
'grim',
|
||||
'mysterious',
|
||||
'martial',
|
||||
'ritual',
|
||||
'survival',
|
||||
] as const;
|
||||
export type SharedRuntimeItemTone =
|
||||
(typeof RUNTIME_ITEM_TONE_VALUES)[number];
|
||||
|
||||
export type StoryRequestOptionsPayload = {
|
||||
availableOptions?: JsonObject[];
|
||||
optionCatalog?: JsonObject[];
|
||||
};
|
||||
|
||||
export type StoryRequestPayload<TWorldType extends string = string> = {
|
||||
worldType: TWorldType;
|
||||
character: JsonObject;
|
||||
monsters?: JsonObject[];
|
||||
history?: JsonObject[];
|
||||
choice?: string;
|
||||
context: JsonObject;
|
||||
requestOptions?: StoryRequestOptionsPayload;
|
||||
};
|
||||
|
||||
export type PlainTextPromptRequest = {
|
||||
systemPrompt: string;
|
||||
userPrompt: string;
|
||||
};
|
||||
|
||||
export type PlainTextResponse = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type CharacterChatReplyRequest<
|
||||
TCharacter = unknown,
|
||||
TStoryMoment = unknown,
|
||||
TContext = unknown,
|
||||
TConversationTurn = unknown,
|
||||
TTargetStatus = unknown,
|
||||
> = {
|
||||
worldType: string;
|
||||
playerCharacter: TCharacter;
|
||||
targetCharacter: TCharacter;
|
||||
storyHistory: TStoryMoment[];
|
||||
context: TContext;
|
||||
conversationHistory: TConversationTurn[];
|
||||
conversationSummary: string;
|
||||
playerMessage: string;
|
||||
targetStatus: TTargetStatus;
|
||||
};
|
||||
|
||||
export type CharacterChatSuggestionsRequest<
|
||||
TCharacter = unknown,
|
||||
TStoryMoment = unknown,
|
||||
TContext = unknown,
|
||||
TConversationTurn = unknown,
|
||||
TTargetStatus = unknown,
|
||||
> = {
|
||||
worldType: string;
|
||||
playerCharacter: TCharacter;
|
||||
targetCharacter: TCharacter;
|
||||
storyHistory: TStoryMoment[];
|
||||
context: TContext;
|
||||
conversationHistory: TConversationTurn[];
|
||||
conversationSummary: string;
|
||||
targetStatus: TTargetStatus;
|
||||
};
|
||||
|
||||
export type CharacterChatSummaryRequest<
|
||||
TCharacter = unknown,
|
||||
TStoryMoment = unknown,
|
||||
TContext = unknown,
|
||||
TConversationTurn = unknown,
|
||||
TTargetStatus = unknown,
|
||||
> = {
|
||||
worldType: string;
|
||||
playerCharacter: TCharacter;
|
||||
targetCharacter: TCharacter;
|
||||
storyHistory: TStoryMoment[];
|
||||
context: TContext;
|
||||
conversationHistory: TConversationTurn[];
|
||||
previousSummary: string;
|
||||
targetStatus: TTargetStatus;
|
||||
};
|
||||
|
||||
export type NpcChatDialogueRequest<
|
||||
TCharacter = unknown,
|
||||
TEncounter = unknown,
|
||||
TMonster = unknown,
|
||||
TStoryMoment = unknown,
|
||||
TContext = unknown,
|
||||
> = {
|
||||
worldType: string;
|
||||
character: TCharacter;
|
||||
encounter: TEncounter;
|
||||
monsters: TMonster[];
|
||||
history: TStoryMoment[];
|
||||
context: TContext;
|
||||
topic: string;
|
||||
resultSummary: string;
|
||||
};
|
||||
|
||||
export type NpcRecruitDialogueRequest<
|
||||
TCharacter = unknown,
|
||||
TEncounter = unknown,
|
||||
TMonster = unknown,
|
||||
TStoryMoment = unknown,
|
||||
TContext = unknown,
|
||||
> = {
|
||||
worldType: string;
|
||||
character: TCharacter;
|
||||
encounter: TEncounter;
|
||||
monsters: TMonster[];
|
||||
history: TStoryMoment[];
|
||||
context: TContext;
|
||||
invitationText: string;
|
||||
recruitSummary: string;
|
||||
};
|
||||
|
||||
export type RuntimeItemIntentRequest<
|
||||
TContext = JsonObject,
|
||||
TPlan = JsonObject,
|
||||
> = {
|
||||
context: TContext;
|
||||
plans: TPlan[];
|
||||
};
|
||||
|
||||
export type RuntimeItemIntentResponse<TIntent = JsonObject> = {
|
||||
intents: TIntent[];
|
||||
};
|
||||
|
||||
export type QuestGenerationRequest<
|
||||
TState = JsonObject,
|
||||
TEncounter = JsonObject,
|
||||
> = {
|
||||
state: TState;
|
||||
encounter: TEncounter;
|
||||
};
|
||||
|
||||
export type RuntimeAction<
|
||||
TType extends string = string,
|
||||
TPayload = JsonObject,
|
||||
> = {
|
||||
type: TType;
|
||||
functionId?: string;
|
||||
targetId?: string;
|
||||
payload?: TPayload;
|
||||
};
|
||||
|
||||
export type RuntimeActionRequest<
|
||||
TAction extends RuntimeAction = RuntimeAction,
|
||||
> = {
|
||||
sessionId: string;
|
||||
clientVersion?: number;
|
||||
action: TAction;
|
||||
};
|
||||
|
||||
export type RuntimeActionResponse<
|
||||
TViewModel = JsonObject,
|
||||
TPresentation = JsonObject,
|
||||
TPatch = JsonObject,
|
||||
> = {
|
||||
sessionId: string;
|
||||
serverVersion: number;
|
||||
viewModel: TViewModel;
|
||||
presentation: TPresentation;
|
||||
patches: TPatch[];
|
||||
};
|
||||
|
||||
export const TASK5_RUNTIME_FUNCTION_IDS = [
|
||||
'story_continue_adventure',
|
||||
'story_opening_camp_dialogue',
|
||||
'camp_travel_home_scene',
|
||||
'idle_call_out',
|
||||
'idle_explore_forward',
|
||||
'idle_observe_signs',
|
||||
'idle_rest_focus',
|
||||
'idle_travel_next_scene',
|
||||
'battle_all_in_crush',
|
||||
'battle_escape_breakout',
|
||||
'battle_feint_step',
|
||||
'battle_finisher_window',
|
||||
'battle_guard_break',
|
||||
'battle_probe_pressure',
|
||||
'battle_recover_breath',
|
||||
'npc_chat',
|
||||
'npc_fight',
|
||||
'npc_help',
|
||||
'npc_leave',
|
||||
'npc_preview_talk',
|
||||
'npc_recruit',
|
||||
'npc_spar',
|
||||
] as const;
|
||||
export type Task5RuntimeFunctionId =
|
||||
(typeof TASK5_RUNTIME_FUNCTION_IDS)[number];
|
||||
|
||||
export const TASK6_RUNTIME_FUNCTION_IDS = [
|
||||
'equipment_equip',
|
||||
'equipment_unequip',
|
||||
'forge_craft',
|
||||
'forge_dismantle',
|
||||
'forge_reforge',
|
||||
'inventory_use',
|
||||
'npc_gift',
|
||||
'npc_quest_accept',
|
||||
'npc_quest_turn_in',
|
||||
'npc_trade',
|
||||
'treasure_inspect',
|
||||
'treasure_leave',
|
||||
'treasure_secure',
|
||||
] as const;
|
||||
export type Task6RuntimeFunctionId =
|
||||
(typeof TASK6_RUNTIME_FUNCTION_IDS)[number];
|
||||
|
||||
export const SERVER_RUNTIME_FUNCTION_IDS = [
|
||||
...TASK5_RUNTIME_FUNCTION_IDS,
|
||||
...TASK6_RUNTIME_FUNCTION_IDS,
|
||||
] as const;
|
||||
export type ServerRuntimeFunctionId =
|
||||
(typeof SERVER_RUNTIME_FUNCTION_IDS)[number];
|
||||
|
||||
export const TASK5_RUNTIME_OPTION_SCOPES = ['story', 'combat', 'npc'] as const;
|
||||
export type Task5RuntimeOptionScope =
|
||||
(typeof TASK5_RUNTIME_OPTION_SCOPES)[number];
|
||||
|
||||
export type RuntimeStoryChoicePayload = JsonObject & {
|
||||
optionText?: string;
|
||||
note?: string;
|
||||
};
|
||||
|
||||
export type RuntimeStoryChoiceAction = RuntimeAction<
|
||||
'story_choice',
|
||||
RuntimeStoryChoicePayload
|
||||
> & {
|
||||
functionId: string;
|
||||
targetId?: string;
|
||||
};
|
||||
|
||||
export type RuntimeStoryOptionView = {
|
||||
functionId: string;
|
||||
actionText: string;
|
||||
detailText?: string;
|
||||
scope: Task5RuntimeOptionScope;
|
||||
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>;
|
||||
|
||||
export type RuntimeStoryActionResponse<
|
||||
TSnapshotGameState = JsonObject,
|
||||
TSnapshotCurrentStory = JsonObject,
|
||||
> = RuntimeActionResponse<
|
||||
RuntimeStoryViewModel,
|
||||
RuntimeStoryPresentation,
|
||||
RuntimeStoryPatch
|
||||
> & {
|
||||
snapshot: SavedGameSnapshot<
|
||||
TSnapshotGameState,
|
||||
string,
|
||||
TSnapshotCurrentStory
|
||||
>;
|
||||
};
|
||||
Reference in New Issue
Block a user