@@ -26,6 +26,7 @@ import {
|
||||
scoreAttributeFit,
|
||||
} from './attributeResolver';
|
||||
import {
|
||||
getCharacterAdventureOpening,
|
||||
getCharacterById,
|
||||
getCharacterCombatStats,
|
||||
getCharacterEquipment,
|
||||
@@ -985,6 +986,76 @@ function getFirstContactRelationStance(npcState: NpcPersistentState) {
|
||||
return npcState.relationState?.stance ?? buildRelationState(npcState.affinity).stance;
|
||||
}
|
||||
|
||||
function ensureDialogueSentence(text: string | null | undefined) {
|
||||
const normalized = text?.trim() ?? '';
|
||||
if (!normalized) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return /[。!?!?]$/u.test(normalized) ? normalized : `${normalized}。`;
|
||||
}
|
||||
|
||||
export function buildNpcChatOpeningText(
|
||||
encounter: Encounter,
|
||||
npcState: NpcPersistentState,
|
||||
worldType: WorldType | null,
|
||||
recruitCharacterOverride?: Character | null,
|
||||
) {
|
||||
const recruitCharacter =
|
||||
recruitCharacterOverride ?? resolveEncounterRecruitCharacter(encounter);
|
||||
const opening = recruitCharacter
|
||||
? getCharacterAdventureOpening(recruitCharacter, worldType)
|
||||
: null;
|
||||
const stance = getFirstContactRelationStance(npcState);
|
||||
|
||||
if (isNpcFirstMeaningfulContact(encounter, npcState)) {
|
||||
const greeting =
|
||||
stance === 'guarded' ? '先打个招呼。' : '先和你打个招呼。';
|
||||
const surfaceHook = ensureDialogueSentence(opening?.surfaceHook);
|
||||
const immediateConcern = ensureDialogueSentence(opening?.immediateConcern);
|
||||
const guardedMotive = ensureDialogueSentence(opening?.guardedMotive);
|
||||
const fallbackLine =
|
||||
stance === 'bonded'
|
||||
? '这一步我既然亲自来了,就说明眼前这件事得先和你对齐。'
|
||||
: stance === 'cooperative'
|
||||
? '我先来和你碰个头,眼下这局势最好别各说各话。'
|
||||
: stance === 'neutral'
|
||||
? '我会出现在这里不是没有缘由,不过咱们最好先把眼前情况看清。'
|
||||
: '前面的动静不太对,我想先看看你会怎么开口。';
|
||||
|
||||
if (
|
||||
encounter.specialBehavior === 'camp_companion'
|
||||
|| encounter.specialBehavior === 'initial_companion'
|
||||
) {
|
||||
return [
|
||||
greeting,
|
||||
surfaceHook || immediateConcern || fallbackLine,
|
||||
surfaceHook && immediateConcern && surfaceHook !== immediateConcern
|
||||
? immediateConcern
|
||||
: null,
|
||||
guardedMotive,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('');
|
||||
}
|
||||
|
||||
return [greeting, immediateConcern || surfaceHook || fallbackLine]
|
||||
.filter(Boolean)
|
||||
.join('');
|
||||
}
|
||||
|
||||
switch (stance) {
|
||||
case 'bonded':
|
||||
return '又见面了。你想先从哪件事接着说?';
|
||||
case 'cooperative':
|
||||
return '你开口吧,我先听听你想聊哪一件。';
|
||||
case 'neutral':
|
||||
return '先说吧,你想从哪里问起?';
|
||||
default:
|
||||
return '说吧,你想先问什么?';
|
||||
}
|
||||
}
|
||||
|
||||
export function getNpcFirstContactTopics(
|
||||
encounter: Encounter,
|
||||
npcState: NpcPersistentState,
|
||||
|
||||
@@ -169,10 +169,14 @@ export function getWorldAttributeSchema(
|
||||
customWorldProfile?: CustomWorldProfile | null,
|
||||
) {
|
||||
if (worldType === WorldType.CUSTOM && customWorldProfile) {
|
||||
return (
|
||||
resolveCustomWorldRuleProfile(customWorldProfile)?.attributeSchema
|
||||
?? customWorldProfile.attributeSchema
|
||||
);
|
||||
try {
|
||||
return (
|
||||
resolveCustomWorldRuleProfile(customWorldProfile)?.attributeSchema
|
||||
?? customWorldProfile.attributeSchema
|
||||
);
|
||||
} catch {
|
||||
return customWorldProfile.attributeSchema;
|
||||
}
|
||||
}
|
||||
|
||||
if (worldType === WorldType.XIANXIA) {
|
||||
|
||||
Reference in New Issue
Block a user