This commit is contained in:
2026-04-26 17:34:52 +08:00
104 changed files with 5086 additions and 2142 deletions

View File

@@ -1192,6 +1192,38 @@ export function createStoryNpcEncounterActions({
};
};
const shouldUseHostileNpcChatClosureOptions = (
directive: NpcChatDirective,
affinity: number,
) =>
affinity < 0 ||
directive?.limitReason === 'negative_affinity' ||
directive?.terminationMode === 'hostile_model' ||
directive?.isHostileChat === true;
// 负好感聊天结束后不能回到普通冒险分支,只允许玩家立刻战斗或逃离。
const buildNpcChatClosureOptions = (
encounter: Encounter,
character: Character,
directive: NpcChatDirective,
affinity: number,
) => {
if (!shouldUseHostileNpcChatClosureOptions(directive, affinity)) {
return [buildContinueAdventureOption()];
}
const fightOption = buildHostileNpcFightOption(encounter);
return [
{
...fightOption,
actionText: '战斗',
text: '战斗',
},
buildHostileNpcEscapeOption(character),
];
};
const enterNpcChat = (
encounter: Encounter,
selectedOption: StoryOption,
@@ -1290,7 +1322,7 @@ export function createStoryNpcEncounterActions({
encounterNpcStateOverride: npcState,
}),
existingDialogue,
'【NPC 主动开场】',
'',
{
affinity: npcState.affinity,
chattedCount: npcState.chattedCount,
@@ -1583,14 +1615,28 @@ export function createStoryNpcEncounterActions({
);
setCurrentStory({
text: closingDialogue.map((turn) => turn.text).join('\n'),
options: [buildContinueAdventureOption()],
options: buildNpcChatClosureOptions(
encounter,
playerCharacter,
resolvedChatDirective,
nextAffinity,
),
displayMode: 'dialogue',
dialogue: closingDialogue,
streaming: false,
npcAffinityEffect: latestAffinityEffect,
deferredOptions: progressionResult.options,
deferredRuntimeState:
progressionResult.deferredRuntimeState ?? undefined,
deferredOptions: shouldUseHostileNpcChatClosureOptions(
resolvedChatDirective,
nextAffinity,
)
? undefined
: progressionResult.options,
deferredRuntimeState: shouldUseHostileNpcChatClosureOptions(
resolvedChatDirective,
nextAffinity,
)
? undefined
: (progressionResult.deferredRuntimeState ?? undefined),
});
return true;
}
@@ -2037,6 +2083,24 @@ export function createStoryNpcEncounterActions({
return true;
}
const npcState = getResolvedNpcState(gameState, encounter);
const limitedChatDirective = resolveLimitedPrimaryNpcChatState({
state: gameState,
npcId: encounter.id ?? encounter.npcName,
affinity: npcState.affinity,
nextTurnCount: 0,
});
if (!npcState.firstMeaningfulContactResolved) {
void startNpcInitiatedOpening(
encounter,
resolvedOption,
[],
limitedChatDirective,
);
return true;
}
return enterNpcChat(encounter, resolvedOption);
}
case 'quest_accept': {