82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
import type { Spell } from '../game'
|
|
import { stackCount, type StackCounts } from './stackCounts'
|
|
|
|
export type SlotModifier<T extends string> = {
|
|
stacks: StackCounts<T>
|
|
id: (slot: string) => T
|
|
multiplier?: number
|
|
}
|
|
|
|
export type StackModifier<T extends string> = {
|
|
stacks: StackCounts<T>
|
|
id: T
|
|
multiplier?: number
|
|
}
|
|
|
|
function slotKey(spell: Spell) {
|
|
return String(spell.key)
|
|
}
|
|
|
|
function slotModifierStacks<T extends string>(spell: Spell, modifier?: SlotModifier<T>) {
|
|
return modifier ? stackCount(modifier.stacks, modifier.id(slotKey(spell))) : 0
|
|
}
|
|
|
|
function stackModifierStacks<T extends string>(modifier?: StackModifier<T>) {
|
|
return modifier ? stackCount(modifier.stacks, modifier.id) : 0
|
|
}
|
|
|
|
function stackMultiplier<T extends string>(modifier?: StackModifier<T>) {
|
|
if (!modifier) return 1
|
|
return (modifier.multiplier ?? 1.25) ** stackModifierStacks(modifier)
|
|
}
|
|
|
|
export function spellSlotMultiplier<TPositive extends string, TNegative extends string = never>(
|
|
spell: Spell,
|
|
positive?: SlotModifier<TPositive>,
|
|
negative?: SlotModifier<TNegative>,
|
|
) {
|
|
const positiveMultiplier = (positive?.multiplier ?? 0.75) ** slotModifierStacks(spell, positive)
|
|
const negativeMultiplier = (negative?.multiplier ?? 1.25) ** slotModifierStacks(spell, negative)
|
|
return positiveMultiplier * negativeMultiplier
|
|
}
|
|
|
|
export function spellCooldownMultiplier<TPositive extends string, TNegative extends string = never>(
|
|
spell: Spell,
|
|
cooldownDown?: SlotModifier<TPositive>,
|
|
cooldownUp?: SlotModifier<TNegative>,
|
|
) {
|
|
return spellSlotMultiplier(spell, cooldownDown, cooldownUp)
|
|
}
|
|
|
|
export function spellResourceCost<TPositive extends string, TNegative extends string = never>({
|
|
spell,
|
|
costDown,
|
|
costUp,
|
|
freeCastReady = false,
|
|
freeCast,
|
|
}: {
|
|
spell: Spell
|
|
costDown?: SlotModifier<TPositive>
|
|
costUp?: SlotModifier<TNegative>
|
|
freeCastReady?: boolean
|
|
freeCast?: StackModifier<TPositive>
|
|
}) {
|
|
if (freeCastReady && stackModifierStacks(freeCast) > 0) return 0
|
|
return Math.ceil(spell.cost * spellSlotMultiplier(spell, costDown, costUp))
|
|
}
|
|
|
|
export function spellExtraTargets<T extends string>(
|
|
spell: Spell,
|
|
extraTarget: SlotModifier<T>,
|
|
) {
|
|
return slotModifierStacks(spell, extraTarget)
|
|
}
|
|
|
|
export function spellPowerMultiplier<T extends string>(modifier: StackModifier<T>) {
|
|
return stackMultiplier(modifier)
|
|
}
|
|
|
|
export function hasSpellStack<T extends string>(modifier: StackModifier<T>) {
|
|
return stackModifierStacks(modifier) > 0
|
|
}
|