@@ -6,7 +6,6 @@ import { NPC_PREVIEW_TALK_FUNCTION } from '../../data/functionCatalog';
|
||||
import {
|
||||
addInventoryItems,
|
||||
applyStoryChoiceToStanceProfile,
|
||||
buildNpcChatResultText,
|
||||
buildNpcHelpCommitActionText,
|
||||
buildNpcHelpResultText,
|
||||
buildNpcHelpReward,
|
||||
@@ -15,7 +14,6 @@ import {
|
||||
createNpcBattleMonster,
|
||||
describeNpcAffinityInWords,
|
||||
generateNpcHelpReward,
|
||||
getChatAffinityOutcome,
|
||||
getNpcLootItems,
|
||||
getNpcSparMaxHp,
|
||||
markNpcFirstMeaningfulContactResolved,
|
||||
@@ -609,6 +607,60 @@ export function createStoryNpcEncounterActions({
|
||||
];
|
||||
};
|
||||
|
||||
const isNpcChatOptionForEncounter = (
|
||||
option: StoryOption,
|
||||
encounter: Encounter,
|
||||
) => {
|
||||
if (option.functionId !== 'npc_chat') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (option.interaction?.kind !== 'npc') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
option.interaction.action === 'chat' &&
|
||||
option.interaction.npcId === (encounter.id ?? encounter.npcName)
|
||||
);
|
||||
};
|
||||
|
||||
const buildNpcChatEntryOptions = (
|
||||
encounter: Encounter,
|
||||
selectedOption: StoryOption,
|
||||
) => {
|
||||
const candidateOptions = [
|
||||
selectedOption,
|
||||
...(currentStory?.options ?? []).filter((option) =>
|
||||
isNpcChatOptionForEncounter(option, encounter),
|
||||
),
|
||||
];
|
||||
const dedupedOptions: StoryOption[] = [];
|
||||
const seenActionTexts = new Set<string>();
|
||||
|
||||
for (const option of candidateOptions) {
|
||||
const actionText = option.actionText?.trim();
|
||||
if (!actionText || seenActionTexts.has(actionText)) {
|
||||
continue;
|
||||
}
|
||||
seenActionTexts.add(actionText);
|
||||
dedupedOptions.push(option);
|
||||
if (dedupedOptions.length === 3) {
|
||||
return dedupedOptions;
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackSuggestions = buildFallbackNpcChatSuggestions(
|
||||
currentStory?.text?.trim() || selectedOption.actionText,
|
||||
);
|
||||
const mergedSuggestions = [
|
||||
...dedupedOptions.map((option) => option.actionText),
|
||||
...fallbackSuggestions.filter((suggestion) => !seenActionTexts.has(suggestion)),
|
||||
].slice(0, 3);
|
||||
|
||||
return buildNpcChatTurnOptions(encounter, mergedSuggestions);
|
||||
};
|
||||
|
||||
const buildNpcChatStoryMoment = (params: {
|
||||
encounter: Encounter;
|
||||
dialogue: NonNullable<StoryMoment['dialogue']>;
|
||||
@@ -629,6 +681,37 @@ export function createStoryNpcEncounterActions({
|
||||
},
|
||||
});
|
||||
|
||||
const enterNpcChat = (
|
||||
encounter: Encounter,
|
||||
selectedOption: StoryOption,
|
||||
) => {
|
||||
const openingDialogue =
|
||||
currentStory?.npcChatState?.npcId === (encounter.id ?? encounter.npcName) &&
|
||||
currentStory.dialogue
|
||||
? [...currentStory.dialogue]
|
||||
: currentStory?.dialogue && currentStory.dialogue.length > 0
|
||||
? [...currentStory.dialogue]
|
||||
: [
|
||||
{
|
||||
speaker: 'npc' as const,
|
||||
speakerName: encounter.npcName,
|
||||
text: `${encounter.npcName}看着你,像是在等你把话接下去。`,
|
||||
},
|
||||
];
|
||||
|
||||
setAiError(null);
|
||||
setCurrentStory(
|
||||
buildNpcChatStoryMoment({
|
||||
encounter,
|
||||
dialogue: openingDialogue,
|
||||
options: buildNpcChatEntryOptions(encounter, selectedOption),
|
||||
streaming: false,
|
||||
turnCount: 0,
|
||||
}),
|
||||
);
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleNpcChatTurn = async (
|
||||
encounter: Encounter,
|
||||
playerMessage: string,
|
||||
@@ -1071,8 +1154,14 @@ export function createStoryNpcEncounterActions({
|
||||
return true;
|
||||
}
|
||||
case 'chat': {
|
||||
void handleNpcChatTurn(encounter, option.actionText);
|
||||
return true;
|
||||
if (
|
||||
currentStory?.npcChatState?.npcId === (encounter.id ?? encounter.npcName)
|
||||
) {
|
||||
void handleNpcChatTurn(encounter, option.actionText);
|
||||
return true;
|
||||
}
|
||||
|
||||
return enterNpcChat(encounter, option);
|
||||
}
|
||||
case 'quest_accept': {
|
||||
void resolveServerNpcStoryAction({
|
||||
|
||||
Reference in New Issue
Block a user