From 8f7160c725765fb9b0ebd1aaa4277e9bc06c556b Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Sun, 1 May 2022 14:12:00 -0500 Subject: [PATCH] Add comments for modifiers --- src/game/modifiers.tsx | 165 +++++++++++++++++++++++++++++------------ src/util/common.ts | 2 + 2 files changed, 120 insertions(+), 47 deletions(-) diff --git a/src/game/modifiers.tsx b/src/game/modifiers.tsx index ffbef3c..1dd73be 100644 --- a/src/game/modifiers.tsx +++ b/src/game/modifiers.tsx @@ -1,17 +1,45 @@ +import "components/common/modifiers.css"; import { CoercableComponent, jsx } from "features/feature"; import Decimal, { DecimalSource, format } from "util/bignum"; +import { WithRequired } from "util/common"; import { Computable, convertComputable, ProcessedComputable } from "util/computed"; import { renderJSX } from "util/vue"; import { computed, unref } from "vue"; -import "components/common/modifiers.css"; +/** + * An object that can be used to apply or unapply some modification to a number. + * Being reversible requires the operation being invertible, but some features may rely on that. + * Descriptions can be optionally included for displaying them to the player. + * The built-in modifier creators are designed to display the modifiers using + * {@link createModifierSection} + */ export interface Modifier { + /** + * Applies some operation on the input and returns the result + */ apply: (gain: DecimalSource) => DecimalSource; - revert: (gain: DecimalSource) => DecimalSource; - enabled: ProcessedComputable; + /** + * Reverses the operation applied by the apply property. Required by some features + */ + revert?: (gain: DecimalSource) => DecimalSource; + /** + * Whether or not this modifier should be considered enabled. + * Typically for use with modifiers passed into {@link createSequentialModifier} + */ + enabled?: ProcessedComputable; + /** + * A description of this modifier. + * @see {@link createModifierSection} + */ description?: ProcessedComputable; } +/** + * Create a modifier that adds some value to the input value + * @param addend The amount to add to the input value + * @param description Description of what this modifier is doing + * @param enabled A computable that will be processed and passed directly into the returned modifier + */ export function createAdditiveModifier( addend: Computable, description?: Computable, @@ -19,25 +47,34 @@ export function createAdditiveModifier( ): Modifier { const processedAddend = convertComputable(addend); const processedDescription = convertComputable(description); - const processedEnabled = convertComputable(enabled == null ? true : enabled); + const processedEnabled = enabled == null ? undefined : convertComputable(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} -
- )) + description: + description == null + ? undefined + : jsx(() => ( +
+ +{format(unref(processedAddend))} + {unref(processedDescription) ? ( + + {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} + {renderJSX(unref(processedDescription)!)} + + ) : null} +
+ )) }; } +/** + * Create a modifier that multiplies the input value by some value + * @param multiplier The value to multiply the input value by + * @param description Description of what this modifier is doing + * @param enabled A computable that will be processed and passed directly into the returned modifier + */ export function createMultiplicativeModifier( multiplier: Computable, description?: Computable, @@ -45,25 +82,34 @@ export function createMultiplicativeModifier( ): Modifier { const processedMultiplier = convertComputable(multiplier); const processedDescription = convertComputable(description); - const processedEnabled = convertComputable(enabled == null ? true : enabled); + const processedEnabled = enabled == null ? undefined : convertComputable(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} -
- )) + description: + description == null + ? undefined + : jsx(() => ( +
+ x{format(unref(processedMultiplier))} + {unref(processedDescription) ? ( + + {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} + {renderJSX(unref(processedDescription)!)} + + ) : null} +
+ )) }; } +/** + * Create a modifier that raises the input value to the power of some value + * @param exponent The value to raise the input value to the power of + * @param description Description of what this modifier is doing + * @param enabled A computable that will be processed and passed directly into the returned modifier + */ export function createExponentialModifier( exponent: Computable, description?: Computable, @@ -71,41 +117,56 @@ export function createExponentialModifier( ): Modifier { const processedExponent = convertComputable(exponent); const processedDescription = convertComputable(description); - const processedEnabled = convertComputable(enabled == null ? true : enabled); + const processedEnabled = enabled == null ? undefined : convertComputable(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} -
- )) + description: + description == null + ? undefined + : 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 { +/** + * Takes an array of modifiers and applies and reverses them in order. + * Modifiers that are not enabled will not be applied nor reversed. + * Also joins their descriptions together. + * @param modifiers The modifiers to perform sequentially + * @see {@link createModifierSection} + */ +export function createSequentialModifier( + ...modifiers: Modifier[] +): WithRequired { return { apply: gain => modifiers - .filter(m => unref(m.enabled)) + .filter(m => unref(m.enabled) !== false) .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), + revert: modifiers.every(m => m.revert != null) + ? gain => + modifiers + .filter(m => unref(m.enabled) !== false) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + .reduceRight((gain, modifier) => modifier.revert!(gain), gain) + : undefined, + enabled: computed(() => modifiers.filter(m => unref(m.enabled) !== false).length > 0), description: jsx(() => ( <> {( modifiers - .filter(m => unref(m.enabled)) + .filter(m => unref(m.enabled) !== false) .map(m => unref(m.description)) .filter(d => d) as CoercableComponent[] ).map(renderJSX)} @@ -114,6 +175,16 @@ export function createSequentialModifier(...modifiers: Modifier[]): Required = T & { [P in K]-?: T[P] }; + // Reference: // https://stackoverflow.com/questions/7225407/convert-camelcasetext-to-sentence-case-text export function camelToTitle(camel: string): string {