Rework story engine flow and reorganize project docs
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -14,13 +14,17 @@ import {
|
||||
resolveEncounterRecruitCharacter,
|
||||
} from '../data/characterPresets';
|
||||
import { getMonsterPresetById } from '../data/hostileNpcPresets';
|
||||
import { createSceneMonstersFromIds } from '../data/hostileNpcs';
|
||||
import { createSceneHostileNpcsFromIds } from '../data/hostileNpcs';
|
||||
import {
|
||||
describeConversationStyle as describeNpcConversationStyle,
|
||||
describeDisclosureStage,
|
||||
describeWarmthStage,
|
||||
} from '../data/npcInteractions';
|
||||
import { buildSceneEntityCatalogText, getScenePresetById } from '../data/scenePresets';
|
||||
import {
|
||||
buildSceneEntityCatalogText,
|
||||
getSceneHostileNpcPresetIds,
|
||||
getScenePresetById,
|
||||
} from '../data/scenePresets';
|
||||
import {
|
||||
buildFunctionCatalogText,
|
||||
getFunctionById,
|
||||
@@ -31,7 +35,7 @@ import {
|
||||
CharacterGender,
|
||||
CustomWorldProfile,
|
||||
FacingDirection,
|
||||
SceneMonster,
|
||||
SceneHostileNpc,
|
||||
StoryMoment,
|
||||
StoryOption,
|
||||
WorldType,
|
||||
@@ -147,9 +151,12 @@ function describeWorldForPrompt(world: WorldType, customWorldProfile?: CustomWor
|
||||
: describeWorld(world);
|
||||
}
|
||||
|
||||
function describeCustomWorldSection(customWorldProfile?: CustomWorldProfile | null) {
|
||||
return customWorldProfile
|
||||
? `自定义世界补充档案:\n${buildCustomWorldReferenceText(customWorldProfile)}`
|
||||
function describeCustomWorldSection(context: StoryGenerationContext) {
|
||||
return context.customWorldProfile
|
||||
? `自定义世界补充档案:\n${buildCustomWorldReferenceText(context.customWorldProfile, {
|
||||
activeThreadIds: context.activeThreadIds,
|
||||
highlightNpcNames: context.encounterName ? [context.encounterName] : [],
|
||||
})}`
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -292,6 +299,316 @@ function describeFirstMeaningfulContactDirective(context: StoryGenerationContext
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function hasVisibilityFact(
|
||||
slice: StoryGenerationContext['visibilitySlice'],
|
||||
factId: string,
|
||||
) {
|
||||
return Boolean(slice?.sayableFactIds.includes(factId));
|
||||
}
|
||||
|
||||
function describeVisibilityFactLabel(factId: string) {
|
||||
if (factId === 'publicMask') return '公开面';
|
||||
if (factId === 'firstContactMask') return '首遇遮挡说辞';
|
||||
if (factId === 'visibleLine') return '表层线';
|
||||
if (factId === 'immediatePressure') return '当前压力';
|
||||
if (factId === 'contradiction') return '说辞错位';
|
||||
if (factId === 'hiddenLine') return '隐藏线';
|
||||
if (factId === 'debtOrBurden') return '债务或负担';
|
||||
if (factId === 'taboo') return '禁区';
|
||||
if (factId.startsWith('thread:')) return '故事线程索引';
|
||||
if (factId.startsWith('scar:')) return '旧痕索引';
|
||||
if (factId.startsWith('chapter:')) return '已解锁背景摘要';
|
||||
if (factId.startsWith('reaction:')) return '反应钩子';
|
||||
return factId;
|
||||
}
|
||||
|
||||
function describeVisibilitySliceSection(context: StoryGenerationContext) {
|
||||
if (!context.visibilitySlice) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sayable = context.visibilitySlice.sayableFactIds
|
||||
.map(describeVisibilityFactLabel)
|
||||
.join('、');
|
||||
const inferred = context.visibilitySlice.inferredFactIds
|
||||
.map(describeVisibilityFactLabel)
|
||||
.join('、');
|
||||
const forbidden = context.visibilitySlice.forbiddenFactIds
|
||||
.map(describeVisibilityFactLabel)
|
||||
.join('、');
|
||||
|
||||
return [
|
||||
'当前信息可见性切片:',
|
||||
sayable ? `- 可直接进入本轮上下文:${sayable}` : null,
|
||||
inferred ? `- 只能写成推测或缝隙:${inferred}` : null,
|
||||
forbidden ? `- 禁止直接说破:${forbidden}` : null,
|
||||
...(context.visibilitySlice.misdirectionHints ?? []).map(
|
||||
(hint) => `- 误导/遮挡提示:${hint}`,
|
||||
),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function describeSceneNarrativeDirectiveSection(context: StoryGenerationContext) {
|
||||
if (!context.sceneNarrativeDirective) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const directive = context.sceneNarrativeDirective;
|
||||
return [
|
||||
'当前场景导演指令:',
|
||||
`- 主压力:${directive.primaryPressure}`,
|
||||
`- 激活线程:${directive.activeThreadIds.join('、') || '暂无'}`,
|
||||
`- 揭示预算:${directive.revealBudget}`,
|
||||
`- 情绪节奏:${directive.emotionalCadence}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeRecentCompanionReactionsSection(context: StoryGenerationContext) {
|
||||
if (!context.recentCompanionReactions?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'最近一次同行反应:',
|
||||
...context.recentCompanionReactions.slice(-3).map(
|
||||
(reaction) =>
|
||||
`- ${reaction.characterId} / ${reaction.reactionType}:${reaction.reason}`,
|
||||
),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeRecentCarrierEchoesSection(context: StoryGenerationContext) {
|
||||
if (!context.recentCarrierEchoes?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'最近叙事载体回响:',
|
||||
...context.recentCarrierEchoes.slice(0, 4).map((echo) => `- ${echo}`),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeCampaignSection(context: StoryGenerationContext) {
|
||||
if (!context.campaignState && !context.actState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前战役状态:',
|
||||
context.campaignState
|
||||
? `- Campaign:${context.campaignState.title}(Act ${context.campaignState.currentActIndex + 1})`
|
||||
: null,
|
||||
context.actState
|
||||
? `- 当前 Act:${context.actState.title} / ${context.actState.status} / ${context.actState.theme}`
|
||||
: null,
|
||||
].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
function describeConsequenceLedgerSection(context: StoryGenerationContext) {
|
||||
if (!context.consequenceLedger?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'关键后果账本:',
|
||||
...context.consequenceLedger.slice(-5).map(
|
||||
(record) => `- ${record.title}(权重 ${record.weight}):${record.summary}`,
|
||||
),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeConstraintSection(context: StoryGenerationContext) {
|
||||
if (!context.authorialConstraintPack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pack = context.authorialConstraintPack;
|
||||
return [
|
||||
'作者性约束:',
|
||||
`- 基调规则:${pack.toneRules.join('、') || '暂无'}`,
|
||||
`- 禁止模式:${pack.noGoPatterns.join('、') || '暂无'}`,
|
||||
`- 必须回收:${pack.requiredPayoffs.join('、') || '暂无'}`,
|
||||
context.branchBudgetPressure
|
||||
? `- 当前分支预算压力:${context.branchBudgetPressure}`
|
||||
: null,
|
||||
].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
function describePackSection(context: StoryGenerationContext) {
|
||||
if (!context.activeScenarioPack && !context.activeCampaignPack) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前内容包:',
|
||||
context.activeScenarioPack
|
||||
? `- Scenario Pack:${context.activeScenarioPack.title} v${context.activeScenarioPack.version}`
|
||||
: null,
|
||||
context.activeCampaignPack
|
||||
? `- Campaign Pack:${context.activeCampaignPack.title} / ${context.activeCampaignPack.authoringStyle}`
|
||||
: null,
|
||||
].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
function describePlayerStyleSection(context: StoryGenerationContext) {
|
||||
if (!context.playerStyleProfile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前玩家画像:',
|
||||
`- 风格:${context.playerStyleProfile.dominantStyle}`,
|
||||
`- 倾向:剧情 ${context.playerStyleProfile.preferenceWeights.story} / 探索 ${context.playerStyleProfile.preferenceWeights.exploration} / 战斗 ${context.playerStyleProfile.preferenceWeights.combat} / 同伴 ${context.playerStyleProfile.preferenceWeights.companion} / 收集 ${context.playerStyleProfile.preferenceWeights.collection}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeNarrativeQaSection(context: StoryGenerationContext) {
|
||||
if (!context.narrativeQaReport) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前叙事 QA:',
|
||||
`- 摘要:${context.narrativeQaReport.summary}`,
|
||||
...context.narrativeQaReport.issues.slice(0, 4).map(
|
||||
(issue) => `- ${issue.severity}/${issue.category}:${issue.summary}`,
|
||||
),
|
||||
context.releaseGateReport
|
||||
? `- Release Gate:${context.releaseGateReport.status} / ${context.releaseGateReport.summary}`
|
||||
: null,
|
||||
context.simulationRunResults?.length
|
||||
? `- Simulation 覆盖:${context.simulationRunResults.length} 条`
|
||||
: null,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeChapterSection(context: StoryGenerationContext) {
|
||||
if (!context.chapterState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前章节状态:',
|
||||
`- 标题:${context.chapterState.title}`,
|
||||
`- 阶段:${context.chapterState.stage}`,
|
||||
`- 主题:${context.chapterState.theme}`,
|
||||
`- 摘要:${context.chapterState.chapterSummary}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeJourneyBeatSection(context: StoryGenerationContext) {
|
||||
if (!context.journeyBeat) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前旅程段落:',
|
||||
`- 类型:${context.journeyBeat.beatType}`,
|
||||
`- 标题:${context.journeyBeat.title}`,
|
||||
`- 情绪目标:${context.journeyBeat.emotionalGoal}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeCampEventSection(context: StoryGenerationContext) {
|
||||
if (!context.currentCampEvent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前可触发营地/旅途事件:',
|
||||
`- 标题:${context.currentCampEvent.title}`,
|
||||
`- 类型:${context.currentCampEvent.eventType}`,
|
||||
`- 原因:${context.currentCampEvent.triggerReason}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeSetpieceSection(context: StoryGenerationContext) {
|
||||
if (!context.setpieceDirective) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前高光导演指令:',
|
||||
`- 类型:${context.setpieceDirective.setpieceType}`,
|
||||
`- 标题:${context.setpieceDirective.title}`,
|
||||
`- 核心问题:${context.setpieceDirective.dramaticQuestion}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeWorldMutationSection(context: StoryGenerationContext) {
|
||||
if (!context.recentWorldMutations?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'最近世界变化:',
|
||||
...context.recentWorldMutations.slice(-4).map(
|
||||
(mutation) =>
|
||||
`- ${mutation.mutationType} / ${mutation.targetId}:${mutation.reason}`,
|
||||
),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeFactionTensionSection(context: StoryGenerationContext) {
|
||||
if (!context.recentFactionTensionStates?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'当前阵营温度:',
|
||||
...context.recentFactionTensionStates.slice(0, 4).map(
|
||||
(tension) =>
|
||||
`- ${tension.factionId} / 温度 ${tension.temperature}:${tension.pressureSummary}`,
|
||||
),
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function describeChronicleSection(context: StoryGenerationContext) {
|
||||
if (!context.recentChronicleSummary?.trim()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `近期旅程回顾:\n${context.recentChronicleSummary}`;
|
||||
}
|
||||
|
||||
function buildCustomEncounterBackstoryLines(context: StoryGenerationContext) {
|
||||
const encounterCustomProfile = context.encounterCustomProfile;
|
||||
const narrativeProfile = context.encounterNarrativeProfile;
|
||||
if (!encounterCustomProfile || !narrativeProfile) {
|
||||
return ['对方有自己的来路与立场,只是暂时没有完全表现出来。'];
|
||||
}
|
||||
|
||||
const lines: string[] = [];
|
||||
if (hasVisibilityFact(context.visibilitySlice, 'publicMask')) {
|
||||
lines.push(narrativeProfile.publicMask);
|
||||
}
|
||||
if (hasVisibilityFact(context.visibilitySlice, 'firstContactMask')) {
|
||||
lines.push(narrativeProfile.firstContactMask);
|
||||
}
|
||||
if (hasVisibilityFact(context.visibilitySlice, 'visibleLine')) {
|
||||
lines.push(narrativeProfile.visibleLine);
|
||||
}
|
||||
if (hasVisibilityFact(context.visibilitySlice, 'immediatePressure')) {
|
||||
lines.push(narrativeProfile.immediatePressure);
|
||||
}
|
||||
|
||||
(encounterCustomProfile.backstoryReveal?.chapters ?? []).forEach((chapter) => {
|
||||
if (hasVisibilityFact(context.visibilitySlice, `chapter:${chapter.id}`)) {
|
||||
const snippet =
|
||||
chapter.contextSnippet || chapter.teaser || encounterCustomProfile.backstoryReveal?.publicSummary;
|
||||
if (snippet) {
|
||||
lines.push(snippet);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return lines.length > 0
|
||||
? [...new Set(lines.filter(Boolean))]
|
||||
: [encounterCustomProfile.backstoryReveal?.publicSummary ?? narrativeProfile.publicMask];
|
||||
}
|
||||
|
||||
function describeBackstoryContext(label: string, snippets: string[]) {
|
||||
const normalized = snippets
|
||||
.map(snippet => snippet.trim())
|
||||
@@ -408,7 +725,7 @@ function describeSkills(character: Character, context: StoryGenerationContext) {
|
||||
function describeFrontEntity(
|
||||
world: WorldType,
|
||||
context: StoryGenerationContext,
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
) {
|
||||
const schema = resolveAttributeSchema(world, context.customWorldProfile);
|
||||
if (context.encounterName) {
|
||||
@@ -427,37 +744,20 @@ function describeFrontEntity(
|
||||
|
||||
const attributeProfile = encounterCharacter
|
||||
? resolveCharacterAttributeProfile(encounterCharacter, world, context.customWorldProfile)
|
||||
: inferEncounterAttributeProfile(world, context, `encounter:${context.encounterName}`, [
|
||||
encounterCustomProfile?.personality ||
|
||||
inferEncounterPersonality(
|
||||
context.encounterContext,
|
||||
context.encounterDescription,
|
||||
),
|
||||
encounterCustomProfile?.backstory ?? '',
|
||||
encounterCustomProfile?.motivation ?? '',
|
||||
encounterCustomProfile?.combatStyle ?? '',
|
||||
...(encounterCustomProfile?.relationshipHooks ?? []),
|
||||
...(encounterCustomProfile?.tags ?? []),
|
||||
...(encounterCustomProfile?.backstoryReveal?.chapters ?? []).flatMap(
|
||||
(chapter) => [
|
||||
chapter.title,
|
||||
chapter.teaser,
|
||||
chapter.content,
|
||||
chapter.contextSnippet,
|
||||
],
|
||||
),
|
||||
...(encounterCustomProfile?.skills ?? []).flatMap((skill) => [
|
||||
skill.name,
|
||||
skill.summary,
|
||||
skill.style,
|
||||
]),
|
||||
...(encounterCustomProfile?.initialItems ?? []).flatMap((item) => [
|
||||
item.name,
|
||||
item.category,
|
||||
item.description,
|
||||
...item.tags,
|
||||
]),
|
||||
]);
|
||||
: inferEncounterAttributeProfile(world, context, `encounter:${context.encounterName}`, [
|
||||
encounterCustomProfile?.personality ||
|
||||
inferEncounterPersonality(
|
||||
context.encounterContext,
|
||||
context.encounterDescription,
|
||||
),
|
||||
context.encounterNarrativeProfile?.publicMask ?? '',
|
||||
context.encounterNarrativeProfile?.visibleLine ?? '',
|
||||
context.encounterNarrativeProfile?.immediatePressure ?? '',
|
||||
...(context.visibilitySlice?.sayableFactIds.includes('contradiction')
|
||||
&& context.encounterNarrativeProfile?.contradiction
|
||||
? [context.encounterNarrativeProfile.contradiction]
|
||||
: []),
|
||||
]);
|
||||
const title =
|
||||
encounterCharacter?.title ??
|
||||
encounterCustomProfile?.title ??
|
||||
@@ -484,17 +784,7 @@ function describeFrontEntity(
|
||||
world,
|
||||
)
|
||||
: encounterCustomProfile
|
||||
? [
|
||||
encounterCustomProfile.backstoryReveal?.publicSummary ??
|
||||
'对方有自己的来路与立场。',
|
||||
encounterCustomProfile.backstory,
|
||||
...(
|
||||
encounterCustomProfile.backstoryReveal?.chapters.map(
|
||||
(chapter) =>
|
||||
chapter.contextSnippet || chapter.content || chapter.teaser,
|
||||
) ?? []
|
||||
),
|
||||
].filter((line): line is string => Boolean(line))
|
||||
? buildCustomEncounterBackstoryLines(context)
|
||||
: ['对方有自己的来路与立场,只是暂时没有完全表现出来。'];
|
||||
const status = context.encounterKind === 'npc'
|
||||
? context.isFirstMeaningfulContact
|
||||
@@ -511,24 +801,37 @@ function describeFrontEntity(
|
||||
`- 描述:${description}`,
|
||||
...describeBackstoryContext('背景', backstoryLines).map(line => `- ${line}`),
|
||||
`- 性格:${personality}`,
|
||||
encounterCustomProfile?.motivation
|
||||
context.encounterNarrativeProfile?.firstContactMask
|
||||
? `- 首遇遮挡说辞:${context.encounterNarrativeProfile.firstContactMask}`
|
||||
: null,
|
||||
context.encounterNarrativeProfile?.visibleLine
|
||||
? `- 表层线:${context.encounterNarrativeProfile.visibleLine}`
|
||||
: null,
|
||||
context.encounterNarrativeProfile?.immediatePressure
|
||||
? `- 当前压力:${context.encounterNarrativeProfile.immediatePressure}`
|
||||
: null,
|
||||
context.visibilitySlice?.inferredFactIds.includes('contradiction') &&
|
||||
context.encounterNarrativeProfile?.contradiction
|
||||
? `- 可写成推测的错位:${context.encounterNarrativeProfile.contradiction}`
|
||||
: null,
|
||||
!context.encounterNarrativeProfile && encounterCustomProfile?.motivation
|
||||
? `- 当前动机:${encounterCustomProfile.motivation}`
|
||||
: null,
|
||||
encounterCustomProfile?.combatStyle
|
||||
!context.encounterNarrativeProfile && encounterCustomProfile?.combatStyle
|
||||
? `- 战斗风格:${encounterCustomProfile.combatStyle}`
|
||||
: null,
|
||||
encounterCustomProfile?.relationshipHooks?.length
|
||||
!context.encounterNarrativeProfile && encounterCustomProfile?.relationshipHooks?.length
|
||||
? `- 关系切入口:${encounterCustomProfile.relationshipHooks.join('、')}`
|
||||
: null,
|
||||
encounterCustomProfile?.tags?.length
|
||||
!context.encounterNarrativeProfile && encounterCustomProfile?.tags?.length
|
||||
? `- 标签:${encounterCustomProfile.tags.join('、')}`
|
||||
: null,
|
||||
encounterCustomProfile?.skills?.length
|
||||
!context.encounterNarrativeProfile && encounterCustomProfile?.skills?.length
|
||||
? `- 自定义技能:${encounterCustomProfile.skills
|
||||
.map((skill) => `${skill.name}(${skill.style}):${skill.summary}`)
|
||||
.join(';')}`
|
||||
: null,
|
||||
encounterCustomProfile?.initialItems?.length
|
||||
!context.encounterNarrativeProfile && encounterCustomProfile?.initialItems?.length
|
||||
? `- 随身物:${encounterCustomProfile.initialItems
|
||||
.map(
|
||||
(item) =>
|
||||
@@ -602,7 +905,7 @@ function describePlayerState(world: WorldType, character: Character, context: St
|
||||
].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
function describeMonsters(monsters: SceneMonster[]) {
|
||||
function describeMonsters(monsters: SceneHostileNpc[]) {
|
||||
if (monsters.length === 0) {
|
||||
return '当前没有可见敌对目标。';
|
||||
}
|
||||
@@ -646,7 +949,7 @@ function describeStoryHistory(history: StoryMoment[]) {
|
||||
function _buildResolvedUserPrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
choice?: string,
|
||||
@@ -674,12 +977,12 @@ function _buildResolvedUserPrompt(
|
||||
const hasOpeningCampFollowupContext = hasProvidedNpcChatOptions
|
||||
&& Boolean(context.openingCampBackground?.trim())
|
||||
&& Boolean(context.openingCampDialogue?.trim());
|
||||
const sceneMonsterIds = scene?.monsterIds ?? [];
|
||||
const sceneMonsterIds = getSceneHostileNpcPresetIds(scene);
|
||||
const battleCatalog = scene
|
||||
? buildFunctionCatalogText({
|
||||
...functionContext,
|
||||
inBattle: true,
|
||||
monsters: createSceneMonstersFromIds(world, sceneMonsterIds, context.playerX),
|
||||
monsters: createSceneHostileNpcsFromIds(world, sceneMonsterIds, context.playerX),
|
||||
})
|
||||
: '';
|
||||
const idleCatalog = buildFunctionCatalogText({
|
||||
@@ -694,9 +997,26 @@ function _buildResolvedUserPrompt(
|
||||
const sections = [
|
||||
`世界:${describeWorldForPrompt(world, context.customWorldProfile)}`,
|
||||
describePlayerState(world, character, context),
|
||||
describeCustomWorldSection(context.customWorldProfile),
|
||||
describeCustomWorldSection(context),
|
||||
`主角性别:${describeGender(character.gender ?? 'unknown')}`,
|
||||
describeFrontEntity(world, context, monsters),
|
||||
describePackSection(context),
|
||||
describePlayerStyleSection(context),
|
||||
describeCampaignSection(context),
|
||||
describeChapterSection(context),
|
||||
describeJourneyBeatSection(context),
|
||||
describeSceneNarrativeDirectiveSection(context),
|
||||
describeVisibilitySliceSection(context),
|
||||
describeConsequenceLedgerSection(context),
|
||||
describeConstraintSection(context),
|
||||
describeCampEventSection(context),
|
||||
describeSetpieceSection(context),
|
||||
describeRecentCompanionReactionsSection(context),
|
||||
describeRecentCarrierEchoesSection(context),
|
||||
describeWorldMutationSection(context),
|
||||
describeFactionTensionSection(context),
|
||||
describeChronicleSection(context),
|
||||
describeNarrativeQaSection(context),
|
||||
describeConversationSituationDirective(context),
|
||||
describeEncounterConversationDirective(context),
|
||||
context.encounterName ? `当前面前实体性别:${describeGender(getEncounterGender(context))}` : null,
|
||||
@@ -824,7 +1144,7 @@ function describeProvidedOptions(options: StoryOption[]) {
|
||||
function buildCatalogAwareUserPrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
choice?: string,
|
||||
@@ -856,7 +1176,7 @@ function buildCatalogAwareUserPrompt(
|
||||
? buildFunctionCatalogText({
|
||||
...functionContext,
|
||||
inBattle: true,
|
||||
monsters: createSceneMonstersFromIds(world, scene?.monsterIds ?? [], context.playerX),
|
||||
monsters: createSceneHostileNpcsFromIds(world, getSceneHostileNpcPresetIds(scene), context.playerX),
|
||||
})
|
||||
: '';
|
||||
const idleCatalog = buildFunctionCatalogText({
|
||||
@@ -871,9 +1191,26 @@ function buildCatalogAwareUserPrompt(
|
||||
const sections = [
|
||||
`世界:${describeWorldForPrompt(world, context.customWorldProfile)}`,
|
||||
describePlayerState(world, character, context),
|
||||
describeCustomWorldSection(context.customWorldProfile),
|
||||
describeCustomWorldSection(context),
|
||||
`主角性别:${describeGender(character.gender ?? 'unknown')}`,
|
||||
describeFrontEntity(world, context, monsters),
|
||||
describePackSection(context),
|
||||
describePlayerStyleSection(context),
|
||||
describeCampaignSection(context),
|
||||
describeChapterSection(context),
|
||||
describeJourneyBeatSection(context),
|
||||
describeSceneNarrativeDirectiveSection(context),
|
||||
describeVisibilitySliceSection(context),
|
||||
describeConsequenceLedgerSection(context),
|
||||
describeConstraintSection(context),
|
||||
describeCampEventSection(context),
|
||||
describeSetpieceSection(context),
|
||||
describeRecentCompanionReactionsSection(context),
|
||||
describeRecentCarrierEchoesSection(context),
|
||||
describeWorldMutationSection(context),
|
||||
describeFactionTensionSection(context),
|
||||
describeChronicleSection(context),
|
||||
describeNarrativeQaSection(context),
|
||||
context.encounterName ? `当前面前实体性别:${describeGender(getEncounterGender(context))}` : null,
|
||||
describeSkills(character, context),
|
||||
`当前敌对目标状态:\n${describeMonsters(monsters)}`,
|
||||
@@ -940,7 +1277,7 @@ function buildCatalogAwareUserPrompt(
|
||||
export function buildUserPrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
choice?: string,
|
||||
@@ -954,7 +1291,7 @@ function buildResolvedNpcChatDialoguePrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
encounterName: string,
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
topic: string,
|
||||
@@ -963,8 +1300,26 @@ function buildResolvedNpcChatDialoguePrompt(
|
||||
return [
|
||||
`世界:${describeWorldForPrompt(world, context.customWorldProfile)}`,
|
||||
describePlayerState(world, character, context),
|
||||
describeCustomWorldSection(context),
|
||||
`主角性别:${describeGender(character.gender ?? 'unknown')}`,
|
||||
describeFrontEntity(world, context, monsters),
|
||||
describePackSection(context),
|
||||
describePlayerStyleSection(context),
|
||||
describeCampaignSection(context),
|
||||
describeChapterSection(context),
|
||||
describeJourneyBeatSection(context),
|
||||
describeSceneNarrativeDirectiveSection(context),
|
||||
describeVisibilitySliceSection(context),
|
||||
describeConsequenceLedgerSection(context),
|
||||
describeConstraintSection(context),
|
||||
describeCampEventSection(context),
|
||||
describeSetpieceSection(context),
|
||||
describeRecentCompanionReactionsSection(context),
|
||||
describeRecentCarrierEchoesSection(context),
|
||||
describeWorldMutationSection(context),
|
||||
describeFactionTensionSection(context),
|
||||
describeChronicleSection(context),
|
||||
describeNarrativeQaSection(context),
|
||||
`当前面前实体性别:${describeGender(getEncounterGender(context))}`,
|
||||
describeSkills(character, context),
|
||||
`当前敌对目标状态:\n${describeMonsters(monsters)}`,
|
||||
@@ -988,7 +1343,7 @@ function buildNpcChatDialoguePrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
encounterName: string,
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
topic: string,
|
||||
@@ -1010,7 +1365,7 @@ export function buildStrictNpcChatDialoguePrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
encounter: { npcName: string },
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
topic: string,
|
||||
@@ -1030,17 +1385,35 @@ export function buildNpcRecruitDialoguePrompt(
|
||||
world: WorldType,
|
||||
character: Character,
|
||||
encounter: { npcName: string },
|
||||
monsters: SceneMonster[],
|
||||
monsters: SceneHostileNpc[],
|
||||
history: StoryMoment[],
|
||||
context: StoryGenerationContext,
|
||||
invitationText: string,
|
||||
recruitSummary: string,
|
||||
) {
|
||||
return [
|
||||
`世界:${describeWorld(world)}`,
|
||||
`世界:${describeWorldForPrompt(world, context.customWorldProfile)}`,
|
||||
describePlayerState(world, character, context),
|
||||
describeCustomWorldSection(context),
|
||||
`主角性别:${describeGender(character.gender ?? 'unknown')}`,
|
||||
describeFrontEntity(world, context, monsters),
|
||||
describePackSection(context),
|
||||
describePlayerStyleSection(context),
|
||||
describeCampaignSection(context),
|
||||
describeChapterSection(context),
|
||||
describeJourneyBeatSection(context),
|
||||
describeSceneNarrativeDirectiveSection(context),
|
||||
describeVisibilitySliceSection(context),
|
||||
describeConsequenceLedgerSection(context),
|
||||
describeConstraintSection(context),
|
||||
describeCampEventSection(context),
|
||||
describeSetpieceSection(context),
|
||||
describeRecentCompanionReactionsSection(context),
|
||||
describeRecentCarrierEchoesSection(context),
|
||||
describeWorldMutationSection(context),
|
||||
describeFactionTensionSection(context),
|
||||
describeChronicleSection(context),
|
||||
describeNarrativeQaSection(context),
|
||||
`当前招募对象性别:${describeGender(getEncounterGender(context))}`,
|
||||
describeSkills(character, context),
|
||||
`当前敌对目标状态:\n${describeMonsters(monsters)}`,
|
||||
|
||||
Reference in New Issue
Block a user