Files
i-want-to-heal/src/combat/roguelikeUpgrades.ts
T
2026-06-29 22:35:49 -04:00

82 lines
2.1 KiB
TypeScript

import type { Spell } from '../game'
import { createStackCounts, summarizeStackCounts } from './stackCounts'
export type UpgradeChoice<T extends string> = {
id: T
name: string
description: string
}
export function slotLabel(slot: string, spells: Spell[], labelMode: 'ability' | 'slot') {
const spell = spells.find((candidate) => candidate.key === slot)
if (labelMode === 'ability' && spell) return spell.name
return `Slot ${slot}`
}
export function buildSelfSlotUpgradeChoices<T extends string>({
slots,
spells,
labelMode,
idPrefix = 'slot',
}: {
slots: readonly string[]
spells: Spell[]
labelMode: 'ability' | 'slot'
idPrefix?: string
}) {
return slots.flatMap((slot) => {
const label = slotLabel(slot, spells, labelMode)
return [
{
id: `${idPrefix}${slot}-extra-target` as T,
name: `${label}: +1 target`,
description: `${label} affects 1 additional ally when possible.`,
},
{
id: `${idPrefix}${slot}-cost-down` as T,
name: `${label}: -25% cost`,
description: `${label} costs 25% less resource.`,
},
{
id: `${idPrefix}${slot}-cooldown-down` as T,
name: `${label}: -25% cooldown`,
description: `${label} recharges 25% faster.`,
},
]
})
}
export function buildOpponentSlotDebuffChoices<T extends string>({
slots,
spells,
labelMode,
}: {
slots: readonly string[]
spells: Spell[]
labelMode: 'ability' | 'slot'
}) {
return slots.flatMap((slot) => {
const label = slotLabel(slot, spells, labelMode)
return [
{
id: `opp-slot${slot}-cost-up` as T,
name: `${label}: +25% cost`,
description: `Opponent ${label.toLowerCase()} costs 25% more resource.`,
},
{
id: `opp-slot${slot}-cooldown-up` as T,
name: `${label}: +25% cooldown`,
description: `Opponent ${label.toLowerCase()} recharges 25% slower.`,
},
]
})
}
export function summarizeChoiceStacks<T extends string>(
items: T[],
catalog: Array<UpgradeChoice<T>>,
emptyLabel = '',
) {
return summarizeStackCounts(createStackCounts(items), catalog, emptyLabel)
}