import { CoercableComponent, jsx } from "features/feature"; import Decimal, { DecimalSource, format } from "util/bignum"; import { Computable, convertComputable, ProcessedComputable } from "util/computed"; import { renderJSX } from "util/vue"; import { computed, unref } from "vue"; import "components/common/modifiers.css"; export interface Modifier { apply: (gain: DecimalSource) => DecimalSource; revert: (gain: DecimalSource) => DecimalSource; enabled: ProcessedComputable; description?: ProcessedComputable; } export function createAdditiveModifier( addend: Computable, description?: Computable, enabled?: Computable ): Modifier { const processedAddend = convertComputable(addend); const processedDescription = convertComputable(description); const processedEnabled = convertComputable(enabled == null ? true : enabled); return { apply: gain => Decimal.add(gain, unref(processedAddend)), revert: gain => Decimal.sub(gain, unref(processedAddend)), enabled: processedEnabled, description: jsx(() => (
+{format(unref(processedAddend))} {unref(processedDescription) ? ( {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} {renderJSX(unref(processedDescription)!)} ) : null}
)) }; } export function createMultiplicativeModifier( multiplier: Computable, description?: Computable, enabled?: Computable ): Modifier { const processedMultiplier = convertComputable(multiplier); const processedDescription = convertComputable(description); const processedEnabled = convertComputable(enabled == null ? true : enabled); return { apply: gain => Decimal.times(gain, unref(processedMultiplier)), revert: gain => Decimal.div(gain, unref(processedMultiplier)), enabled: processedEnabled, description: jsx(() => (
x{format(unref(processedMultiplier))} {unref(processedDescription) ? ( {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} {renderJSX(unref(processedDescription)!)} ) : null}
)) }; } export function createExponentialModifier( exponent: Computable, description?: Computable, enabled?: Computable ): Modifier { const processedExponent = convertComputable(exponent); const processedDescription = convertComputable(description); const processedEnabled = convertComputable(enabled == null ? true : enabled); return { apply: gain => Decimal.pow(gain, unref(processedExponent)), revert: gain => Decimal.root(gain, unref(processedExponent)), enabled: processedEnabled, description: jsx(() => (
^{format(unref(processedExponent))} {unref(processedDescription) ? ( {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} {renderJSX(unref(processedDescription)!)} ) : null}
)) }; } export function createSequentialModifier(...modifiers: Modifier[]): Required { return { apply: gain => modifiers .filter(m => unref(m.enabled)) .reduce((gain, modifier) => modifier.apply(gain), gain), revert: gain => modifiers .filter(m => unref(m.enabled)) .reduceRight((gain, modifier) => modifier.revert(gain), gain), enabled: computed(() => modifiers.filter(m => unref(m.enabled)).length > 0), description: jsx(() => ( <> {( modifiers .filter(m => unref(m.enabled)) .map(m => unref(m.description)) .filter(d => d) as CoercableComponent[] ).map(renderJSX)} )) }; } export function createModifierSection( title: string, subtitle: string, modifier: Required, base: DecimalSource = 1, unit = "" ) { return (

{title} {subtitle ? ({subtitle}) : null}


{format(base)} {unit} Base
{renderJSX(unref(modifier.description))}
Total: {format(modifier.apply(base))} {unit}
); }