92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import type {
|
|
CustomWorldProfile,
|
|
StoryThread,
|
|
ThreadContract,
|
|
ThreadContractStep,
|
|
} from '../../types';
|
|
|
|
function createStep(
|
|
contractId: string,
|
|
suffix: string,
|
|
title: string,
|
|
revealText: string,
|
|
completionSignalIds: string[],
|
|
optionalFactIds: string[],
|
|
) {
|
|
return {
|
|
id: `${contractId}:${suffix}`,
|
|
title,
|
|
revealText,
|
|
completionSignalIds,
|
|
optionalFactIds,
|
|
} satisfies ThreadContractStep;
|
|
}
|
|
|
|
export function buildThreadContract(params: {
|
|
thread: StoryThread;
|
|
issuerActorId?: string | null;
|
|
}) {
|
|
const { thread, issuerActorId = thread.involvedActorIds[0] ?? null } = params;
|
|
const contractId = `thread-contract:${thread.id}`;
|
|
const narrativeType: ThreadContract['narrativeType'] =
|
|
/调查|追查|真相|线索/u.test(`${thread.title} ${thread.summary}`)
|
|
? 'investigation'
|
|
: /试炼|考验/u.test(`${thread.title} ${thread.summary}`)
|
|
? 'trial'
|
|
: /关系|誓|旧识/u.test(`${thread.title} ${thread.summary}`)
|
|
? 'relationship'
|
|
: /护送|撤离/u.test(`${thread.title} ${thread.summary}`)
|
|
? 'escort'
|
|
: /夺回|收复|回收/u.test(`${thread.title} ${thread.summary}`)
|
|
? 'recovery'
|
|
: 'investigation';
|
|
const primarySceneSignal = thread.relatedLocationIds[0]
|
|
? [`enter_scene:${thread.relatedLocationIds[0]}`, `inspect_scene:${thread.relatedLocationIds[0]}`]
|
|
: [`talk_to_actor:${issuerActorId ?? 'actor'}`];
|
|
const actorSignal = issuerActorId
|
|
? [`talk_to_actor:${issuerActorId}`]
|
|
: [];
|
|
|
|
return {
|
|
id: contractId,
|
|
threadId: thread.id,
|
|
issuerActorId,
|
|
narrativeType,
|
|
currentStepId: `${contractId}:step_1`,
|
|
visibleStage: 0,
|
|
steps: [
|
|
createStep(
|
|
contractId,
|
|
'step_1',
|
|
`追上 ${thread.title} 的表层线索`,
|
|
thread.summary,
|
|
primarySceneSignal,
|
|
thread.relatedLocationIds.map((locationId) => `scene:${locationId}`),
|
|
),
|
|
createStep(
|
|
contractId,
|
|
'step_2',
|
|
`把 ${thread.title} 的线头对回角色`,
|
|
`${thread.stakes} 还需要有人当面松口。`,
|
|
actorSignal.length > 0 ? actorSignal : [`resolve_contract_step:${thread.id}`],
|
|
thread.involvedActorIds.map((actorId) => `actor:${actorId}`),
|
|
),
|
|
],
|
|
followupThreadIds: [],
|
|
} satisfies ThreadContract;
|
|
}
|
|
|
|
export function buildThreadContractsFromProfile(profile: CustomWorldProfile) {
|
|
const threads = [
|
|
...(profile.storyGraph?.visibleThreads ?? []),
|
|
...(profile.storyGraph?.hiddenThreads ?? []),
|
|
];
|
|
|
|
return threads.map((thread) =>
|
|
buildThreadContract({
|
|
thread,
|
|
issuerActorId: thread.involvedActorIds[0] ?? null,
|
|
}),
|
|
);
|
|
}
|