import type { RuntimeStoryActionRequest, RuntimeStoryPatch, } from '../../../../packages/shared/src/contracts/rpgRuntimeStoryState.js'; import { conflict, invalidRequest } from '../../errors.js'; import { addInventoryItems, appendStoryEngineCarrierMemory, } from '../../bridges/legacyNpcTask6Bridge.js'; import { buildTreasureResultText, resolveTreasureReward, } from '../../bridges/legacyTreasureRuntimeBridge.js'; import { buildBuildToast } from '../inventory/inventoryStoryActionService.js'; import { replaceRuntimeSessionRawGameState, } from '../rpg-runtime-story/RpgRuntimeSnapshotSync.js'; import type { RuntimeSession } from '../rpg-runtime-story/RpgRuntimeSessionLoader.js'; const SUPPORTED_TREASURE_STORY_FUNCTION_IDS = new Set([ 'treasure_inspect', 'treasure_leave', 'treasure_secure', ]); type TreasureStoryResolution = { actionText: string; resultText: string; patches: RuntimeStoryPatch[]; toast?: string | null; }; type JsonRecord = Record; type RuntimeGameState = Parameters[0]; type RuntimeEncounter = Parameters[1]; function resolveTreasureAction(functionId: string) { switch (functionId) { case 'treasure_secure': return 'secure'; case 'treasure_inspect': return 'inspect'; case 'treasure_leave': return 'leave'; default: throw invalidRequest(`暂不支持的 Treasure 动作:${functionId}`); } } function getTreasureEncounter( session: RuntimeSession, state: RuntimeGameState, ): RuntimeEncounter | null { const rawEncounter = state.currentEncounter; if (!rawEncounter || rawEncounter.kind !== 'treasure') { return null; } return { npcAvatar: '', hostile: false, ...rawEncounter, id: rawEncounter.id ?? session.currentEncounter?.id ?? rawEncounter.npcName, } satisfies RuntimeEncounter; } export function isSupportedTreasureStoryFunctionId(functionId: string) { return SUPPORTED_TREASURE_STORY_FUNCTION_IDS.has(functionId); } export function resolveTreasureStoryAction( session: RuntimeSession, request: RuntimeStoryActionRequest, ): TreasureStoryResolution { const state = session.rawGameState as unknown as RuntimeGameState; const encounter = getTreasureEncounter(session, state); if (!encounter) { throw conflict('当前没有可结算的宝藏遭遇。'); } const action = resolveTreasureAction(request.action.functionId); const reward = action === 'leave' ? null : resolveTreasureReward(state, encounter, action); let nextState = { ...state, currentEncounter: null, npcInteractionActive: false, sceneHostileNpcs: [], playerX: 0, playerFacing: 'right' as const, animationState: state.animationState, scrollWorld: false, inBattle: false, playerHp: reward ? Math.min(state.playerMaxHp, state.playerHp + reward.hp) : state.playerHp, playerMana: reward ? Math.min(state.playerMaxMana, state.playerMana + reward.mana) : state.playerMana, playerCurrency: reward ? state.playerCurrency + reward.currency : state.playerCurrency, playerInventory: reward ? addInventoryItems(state.playerInventory, reward.items) : state.playerInventory, currentBattleNpcId: null, currentNpcBattleMode: null, currentNpcBattleOutcome: null, sparReturnEncounter: null, sparPlayerHpBefore: null, sparPlayerMaxHpBefore: null, sparStoryHistoryBefore: null, } satisfies RuntimeGameState; if (reward) { nextState = appendStoryEngineCarrierMemory(nextState, reward.items); } replaceRuntimeSessionRawGameState( session, nextState as unknown as JsonRecord, ); return { actionText: action === 'leave' ? '先记下位置' : action === 'inspect' ? '仔细检查' : '直接收取', resultText: buildTreasureResultText( encounter, action, reward ?? undefined, state.worldType, ), patches: [], toast: reward ? buildBuildToast(nextState) : null, }; }