This commit is contained in:
165
src/data/treasureInteractions.ts
Normal file
165
src/data/treasureInteractions.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
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}`;
|
||||
}
|
||||
Reference in New Issue
Block a user