Refine NPC interactions and runtime item generation

This commit is contained in:
2026-04-05 17:13:07 +08:00
parent c49c64896a
commit 89cecda7da
58 changed files with 4199 additions and 1562 deletions

View File

@@ -17,12 +17,16 @@ import {
} from '../../data/economy';
import {
addInventoryItems,
buildNpcGiftCommitActionText,
buildNpcGiftResultText,
buildNpcRecruitResultText,
buildNpcTradeTransactionActionText,
buildNpcTradeTransactionResultText,
getGiftCandidates,
getPreferredGiftItemId,
markNpcFirstMeaningfulContactResolved,
removeInventoryItem,
syncNpcTradeInventory,
} from '../../data/npcInteractions';
import { streamNpcRecruitDialogue } from '../../services/ai';
import type { StoryGenerationContext } from '../../services/aiTypes';
@@ -326,7 +330,7 @@ export function useStoryNpcInteractionFlow({
})
.catch(error => {
console.error('Failed to continue recruit story:', error);
runtime.setAiError(error instanceof Error ? error.message : '未知 AI 错误');
runtime.setAiError(error instanceof Error ? error.message : '未知智能生成错误');
runtime.setCurrentStory(
runtime.buildFallbackStoryForState(stateWithHistory, gameState.playerCharacter!, recruitResultText),
);
@@ -412,7 +416,7 @@ export function useStoryNpcInteractionFlow({
await typewriterPromise;
console.error('Failed to stream recruit dialogue:', error);
dialogueText = displayedText || buildOfflineRecruitDialogue(encounter, releasedCompanionName);
runtime.setAiError(error instanceof Error ? error.message : '未知 AI 错误');
runtime.setAiError(error instanceof Error ? error.message : '未知智能生成错误');
}
const finalDialogueText = normalizeRecruitDialogue(
@@ -426,7 +430,20 @@ export function useStoryNpcInteractionFlow({
};
const openTradeModal = (encounter: Encounter, actionText: string) => {
const npcState = getResolvedNpcState(gameState, encounter);
const currentNpcState = getResolvedNpcState(gameState, encounter);
const npcState = syncNpcTradeInventory(
gameState,
encounter,
currentNpcState,
);
if (
gameState.npcStates[getNpcEncounterKey(encounter)] !== npcState
|| npcState !== currentNpcState
) {
setGameState(updateNpcState(gameState, encounter, () => npcState));
}
setTradeModal({
encounter,
actionText,
@@ -438,10 +455,20 @@ export function useStoryNpcInteractionFlow({
};
const openGiftModal = (encounter: Encounter, actionText: string) => {
const selectedItemId = getPreferredGiftItemId(
gameState.playerInventory,
encounter,
{
worldType: gameState.worldType,
customWorldProfile: gameState.customWorldProfile,
},
);
if (!selectedItemId) return;
setGiftModal({
encounter,
actionText,
selectedItemId: gameState.playerInventory[0]?.id ?? null,
selectedItemId,
});
};
@@ -494,7 +521,12 @@ export function useStoryNpcInteractionFlow({
void commitGeneratedState(
nextState,
gameState.playerCharacter,
tradeModal.actionText,
buildNpcTradeTransactionActionText({
encounter,
mode: 'buy',
item: npcItem,
quantity,
}),
buildNpcTradeTransactionResultText({
encounter,
mode: 'buy',
@@ -534,7 +566,12 @@ export function useStoryNpcInteractionFlow({
void commitGeneratedState(
nextState,
gameState.playerCharacter,
tradeModal.actionText,
buildNpcTradeTransactionActionText({
encounter,
mode: 'sell',
item: playerItem,
quantity,
}),
buildNpcTradeTransactionResultText({
encounter,
mode: 'sell',
@@ -590,7 +627,7 @@ export function useStoryNpcInteractionFlow({
void commitGeneratedState(
nextState,
gameState.playerCharacter,
giftModal.actionText,
buildNpcGiftCommitActionText(encounter, giftItem),
buildNpcGiftResultText(encounter, giftItem, affinityGain, nextAffinity, attributeSummary ?? undefined),
'npc_gift',
);