Files
Genarrative/src/data/treasureInteractions.ts
高物 c49c64896a
Some checks failed
CI / verify (push) Has been cancelled
初始仓库迁移
2026-04-04 23:57:06 +08:00

166 lines
5.0 KiB
TypeScript

import {
AnimationState,
type Encounter,
type GameState,
type StoryMoment,
type StoryOption,
type TreasureInteractionAction,
} from '../types';
import { formatCurrency } from './economy';
import {
TREASURE_INSPECT_FUNCTION,
TREASURE_LEAVE_FUNCTION,
TREASURE_SECURE_FUNCTION,
} from './functionCatalog';
import { buildRuntimeItemGenerationContext } from './runtimeItemContext';
import { buildDirectedRuntimeReward } from './runtimeItemDirector';
import { flattenDirectedRuntimeRewardItems } from './runtimeItemNarrative';
export type TreasureReward = {
items: ReturnType<typeof flattenDirectedRuntimeRewardItems>;
hp: number;
mana: number;
currency: number;
storyHint?: string;
};
function buildTreasureOption(
functionId: string,
actionText: string,
detailText: string,
action: TreasureInteractionAction,
): StoryOption {
return {
functionId,
actionText,
detailText,
visuals: {
playerAnimation: AnimationState.IDLE,
playerMoveMeters: 0,
playerOffsetY: 0,
playerFacing: 'right',
scrollWorld: false,
monsterChanges: [],
},
interaction: {
kind: 'treasure',
action,
},
} as StoryOption;
}
function buildTreasureReward(
state: GameState,
encounter: Encounter,
action: TreasureInteractionAction,
): TreasureReward {
const context = buildRuntimeItemGenerationContext({
state,
generationChannel: 'treasure',
encounter,
});
const directed = buildDirectedRuntimeReward(context, {
seedKey: `treasure:${encounter.id ?? encounter.npcName}:${action}`,
variant: action,
itemCount: action === 'inspect' ? 2 : 2,
fixedKinds:
action === 'inspect' ? ['relic', 'consumable'] : ['relic', 'material'],
fixedPermanence:
action === 'inspect' ? ['permanent', 'timed'] : ['permanent', 'resource'],
baseHp: action === 'inspect' ? 10 : 0,
baseMana: action === 'inspect' ? 12 : 0,
baseCurrency:
action === 'inspect'
? state.worldType === 'XIANXIA'
? 34
: 48
: state.worldType === 'XIANXIA'
? 22
: 30,
storyHint: `${encounter.npcName}里藏着与你当前构筑和现场线索贴合的战利品。`,
});
return {
items: flattenDirectedRuntimeRewardItems(directed),
hp: directed.hp ?? 0,
mana: directed.mana ?? 0,
currency: directed.currency ?? 0,
storyHint: directed.storyHint,
};
}
export function buildTreasureEncounterStoryMoment({
state,
encounter,
overrideText,
}: {
state: GameState;
encounter: Encounter;
overrideText?: string;
}): StoryMoment {
const secureReward = buildTreasureReward(state, encounter, 'secure');
const inspectReward = buildTreasureReward(state, encounter, 'inspect');
return {
text:
overrideText ??
`你在 ${encounter.npcName} 前停下脚步。${encounter.npcDescription} 它看起来并非随意遗落,而像是被刻意留在这里。`,
options: [
buildTreasureOption(
TREASURE_SECURE_FUNCTION.id,
TREASURE_SECURE_FUNCTION.title,
`直接带走 ${secureReward.items.map((item) => item.name).join('、')},并获得 ${formatCurrency(secureReward.currency, state.worldType)}`,
'secure',
),
buildTreasureOption(
TREASURE_INSPECT_FUNCTION.id,
TREASURE_INSPECT_FUNCTION.title,
`多花些时间搜查,可额外拿到 ${inspectReward.items.map((item) => item.name).join('、')}${formatCurrency(inspectReward.currency, state.worldType)} 与恢复收益。`,
'inspect',
),
buildTreasureOption(
TREASURE_LEAVE_FUNCTION.id,
TREASURE_LEAVE_FUNCTION.title,
`先把 ${encounter.npcName} 的位置和迹象记住,暂时不动它。`,
'leave',
),
],
};
}
export function resolveTreasureReward(
state: GameState,
encounter: Encounter,
action: TreasureInteractionAction,
) {
return buildTreasureReward(state, encounter, action);
}
export function buildTreasureResultText(
encounter: Encounter,
action: TreasureInteractionAction,
reward?: TreasureReward,
) {
if (action === 'leave') {
return `你暂时没有触碰 ${encounter.npcName},只是把它的异常位置和痕迹牢牢记下。`;
}
const itemText = reward?.items.length
? reward.items.map((item) => item.name).join('、')
: '零散战利品';
const restoreParts = [
(reward?.hp ?? 0) > 0 ? `气血 +${reward?.hp ?? 0}` : null,
(reward?.mana ?? 0) > 0 ? `灵力 +${reward?.mana ?? 0}` : null,
].filter(Boolean);
const restoreText =
restoreParts.length > 0 ? `,并恢复 ${restoreParts.join('、')}` : '';
const currencyText = reward ? `,另得 ${reward.currency} 钱币` : '';
const storyHint = reward?.storyHint ? ` ${reward.storyHint}` : '';
if (action === 'inspect') {
return `你仔细检查了 ${encounter.npcName},顺着现场痕迹拆开机关与伪装,最终收回 ${itemText}${currencyText}${restoreText}${storyHint}`;
}
return `你迅速收下了 ${encounter.npcName} 中最关键的收获:${itemText}${currencyText}${storyHint}`;
}