forked from profectus/Profectus
Reworked flow for converting modifiers to formulas, and renamed revert to invert
This commit is contained in:
parent
8c0a0c4410
commit
c65dc777cc
4 changed files with 33 additions and 42 deletions
|
@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- **BREAKING** Formulas, which can be used to calculate buy max for you
|
- **BREAKING** Formulas, which can be used to calculate buy max for you
|
||||||
- Requirements can use them so repeatables and challenges can be "buy max" without any extra effort
|
- Requirements can use them so repeatables and challenges can be "buy max" without any extra effort
|
||||||
- Conversions now use formulas instead of the old scaling functions system, allowing for arbitrary functions that are much easier to follow
|
- Conversions now use formulas instead of the old scaling functions system, allowing for arbitrary functions that are much easier to follow
|
||||||
- There's a utility for converting modifiers to formulas, thus replacing things like the gain modifier on conversions
|
- Modifiers have a new getFormula property
|
||||||
- Action feature, which is a clickable with a cooldown
|
- Action feature, which is a clickable with a cooldown
|
||||||
- ETA util (calculates time until a specific amount of a resource, based on its current gain rate)
|
- ETA util (calculates time until a specific amount of a resource, based on its current gain rate)
|
||||||
- createCollapsibleAchievements util
|
- createCollapsibleAchievements util
|
||||||
|
|
|
@ -491,29 +491,3 @@ export function createFormulaPreview(
|
||||||
return formatSmall(formula.evaluate());
|
return formatSmall(formula.evaluate());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility for converting a modifier into a formula. Takes the input for this formula as the base parameter.
|
|
||||||
* @param modifier The modifier to convert to the formula
|
|
||||||
* @param base An existing formula or processed DecimalSource that will be the input to the formula
|
|
||||||
*/
|
|
||||||
export function modifierToFormula<T extends GenericFormula>(
|
|
||||||
modifier: WithRequired<Modifier, "revert">,
|
|
||||||
base: T
|
|
||||||
): T;
|
|
||||||
export function modifierToFormula(modifier: Modifier, base: FormulaSource): GenericFormula;
|
|
||||||
export function modifierToFormula(modifier: Modifier, base: FormulaSource) {
|
|
||||||
return new Formula({
|
|
||||||
inputs: [base],
|
|
||||||
evaluate: val => modifier.apply(val),
|
|
||||||
invert:
|
|
||||||
"revert" in modifier && modifier.revert != null
|
|
||||||
? (val, lhs) => {
|
|
||||||
if (lhs instanceof Formula && lhs.hasVariable()) {
|
|
||||||
return lhs.invert(modifier.revert!(val));
|
|
||||||
}
|
|
||||||
throw new Error("Could not invert due to no input being a variable");
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ import { ClickableOptions } from "./clickables/clickable";
|
||||||
export const ActionType = Symbol("Action");
|
export const ActionType = Symbol("Action");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object that configures a {@link Action}.
|
* An object that configures an {@link Action}.
|
||||||
*/
|
*/
|
||||||
export interface ActionOptions extends Omit<ClickableOptions, "onClick" | "onHold"> {
|
export interface ActionOptions extends Omit<ClickableOptions, "onClick" | "onHold"> {
|
||||||
/** The cooldown during which the action cannot be performed again, in seconds. */
|
/** The cooldown during which the action cannot be performed again, in seconds. */
|
||||||
|
@ -71,7 +71,7 @@ export interface BaseAction {
|
||||||
[GatherProps]: () => Record<string, unknown>;
|
[GatherProps]: () => Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An object that represens a feature that can be clicked upon, and then have a cooldown before they can be clicked again. */
|
/** An object that represents a feature that can be clicked upon, and then has a cooldown before it can be clicked again. */
|
||||||
export type Action<T extends ActionOptions> = Replace<
|
export type Action<T extends ActionOptions> = Replace<
|
||||||
T & BaseAction,
|
T & BaseAction,
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { convertComputable } from "util/computed";
|
||||||
import { createLazyProxy } from "util/proxies";
|
import { createLazyProxy } from "util/proxies";
|
||||||
import { renderJSX } from "util/vue";
|
import { renderJSX } from "util/vue";
|
||||||
import { computed, unref } from "vue";
|
import { computed, unref } from "vue";
|
||||||
|
import Formula from "./formulas/formulas";
|
||||||
|
import { FormulaSource, GenericFormula } from "./formulas/types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object that can be used to apply or unapply some modification to a number.
|
* An object that can be used to apply or unapply some modification to a number.
|
||||||
|
@ -21,7 +23,9 @@ export interface Modifier {
|
||||||
/** Applies some operation on the input and returns the result. */
|
/** Applies some operation on the input and returns the result. */
|
||||||
apply: (gain: DecimalSource) => DecimalSource;
|
apply: (gain: DecimalSource) => DecimalSource;
|
||||||
/** Reverses the operation applied by the apply property. Required by some features. */
|
/** Reverses the operation applied by the apply property. Required by some features. */
|
||||||
revert?: (gain: DecimalSource) => DecimalSource;
|
invert?: (gain: DecimalSource) => DecimalSource;
|
||||||
|
/** Get a formula for this modifier. Required by some features. */
|
||||||
|
getFormula?: (gain: FormulaSource) => GenericFormula;
|
||||||
/**
|
/**
|
||||||
* Whether or not this modifier should be considered enabled.
|
* Whether or not this modifier should be considered enabled.
|
||||||
* Typically for use with modifiers passed into {@link createSequentialModifier}.
|
* Typically for use with modifiers passed into {@link createSequentialModifier}.
|
||||||
|
@ -39,11 +43,11 @@ export interface Modifier {
|
||||||
*/
|
*/
|
||||||
export type ModifierFromOptionalParams<T, S> = T extends undefined
|
export type ModifierFromOptionalParams<T, S> = T extends undefined
|
||||||
? S extends undefined
|
? S extends undefined
|
||||||
? Omit<WithRequired<Modifier, "revert">, "description" | "enabled">
|
? Omit<WithRequired<Modifier, "invert">, "description" | "enabled">
|
||||||
: Omit<WithRequired<Modifier, "revert" | "enabled">, "description">
|
: Omit<WithRequired<Modifier, "invert" | "enabled">, "description">
|
||||||
: S extends undefined
|
: S extends undefined
|
||||||
? Omit<WithRequired<Modifier, "revert" | "description">, "enabled">
|
? Omit<WithRequired<Modifier, "invert" | "description">, "enabled">
|
||||||
: WithRequired<Modifier, "revert" | "enabled" | "description">;
|
: WithRequired<Modifier, "invert" | "enabled" | "description">;
|
||||||
|
|
||||||
/** An object that configures an additive modifier via {@link createAdditiveModifier}. */
|
/** An object that configures an additive modifier via {@link createAdditiveModifier}. */
|
||||||
export interface AdditiveModifierOptions {
|
export interface AdditiveModifierOptions {
|
||||||
|
@ -72,7 +76,8 @@ export function createAdditiveModifier<T extends AdditiveModifierOptions>(
|
||||||
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
||||||
return {
|
return {
|
||||||
apply: (gain: DecimalSource) => Decimal.add(gain, unref(processedAddend)),
|
apply: (gain: DecimalSource) => Decimal.add(gain, unref(processedAddend)),
|
||||||
revert: (gain: DecimalSource) => Decimal.sub(gain, unref(processedAddend)),
|
invert: (gain: DecimalSource) => Decimal.sub(gain, unref(processedAddend)),
|
||||||
|
getFormula: (gain: FormulaSource) => Formula.add(gain, processedAddend),
|
||||||
enabled: processedEnabled,
|
enabled: processedEnabled,
|
||||||
description:
|
description:
|
||||||
description == null
|
description == null
|
||||||
|
@ -133,7 +138,8 @@ export function createMultiplicativeModifier<T extends MultiplicativeModifierOpt
|
||||||
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
||||||
return {
|
return {
|
||||||
apply: (gain: DecimalSource) => Decimal.times(gain, unref(processedMultiplier)),
|
apply: (gain: DecimalSource) => Decimal.times(gain, unref(processedMultiplier)),
|
||||||
revert: (gain: DecimalSource) => Decimal.div(gain, unref(processedMultiplier)),
|
invert: (gain: DecimalSource) => Decimal.div(gain, unref(processedMultiplier)),
|
||||||
|
getFormula: (gain: FormulaSource) => Formula.times(gain, processedMultiplier),
|
||||||
enabled: processedEnabled,
|
enabled: processedEnabled,
|
||||||
description:
|
description:
|
||||||
description == null
|
description == null
|
||||||
|
@ -206,7 +212,7 @@ export function createExponentialModifier<T extends ExponentialModifierOptions>(
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
revert: (gain: DecimalSource) => {
|
invert: (gain: DecimalSource) => {
|
||||||
let result = gain;
|
let result = gain;
|
||||||
if (supportLowNumbers) {
|
if (supportLowNumbers) {
|
||||||
result = Decimal.add(result, 1);
|
result = Decimal.add(result, 1);
|
||||||
|
@ -217,6 +223,10 @@ export function createExponentialModifier<T extends ExponentialModifierOptions>(
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
getFormula: (gain: FormulaSource) =>
|
||||||
|
supportLowNumbers
|
||||||
|
? Formula.add(gain, 1).pow(processedExponent).sub(1)
|
||||||
|
: Formula.pow(gain, processedExponent),
|
||||||
enabled: processedEnabled,
|
enabled: processedEnabled,
|
||||||
description:
|
description:
|
||||||
description == null
|
description == null
|
||||||
|
@ -259,9 +269,9 @@ export function createExponentialModifier<T extends ExponentialModifierOptions>(
|
||||||
*/
|
*/
|
||||||
export function createSequentialModifier<
|
export function createSequentialModifier<
|
||||||
T extends Modifier[],
|
T extends Modifier[],
|
||||||
S = T extends WithRequired<Modifier, "revert">[]
|
S = T extends WithRequired<Modifier, "invert">[]
|
||||||
? WithRequired<Modifier, "description" | "revert">
|
? WithRequired<Modifier, "description" | "invert">
|
||||||
: Omit<WithRequired<Modifier, "description">, "revert">
|
: Omit<WithRequired<Modifier, "description">, "invert">
|
||||||
>(modifiersFunc: () => T): S {
|
>(modifiersFunc: () => T): S {
|
||||||
return createLazyProxy(() => {
|
return createLazyProxy(() => {
|
||||||
const modifiers = modifiersFunc();
|
const modifiers = modifiersFunc();
|
||||||
|
@ -271,12 +281,19 @@ export function createSequentialModifier<
|
||||||
modifiers
|
modifiers
|
||||||
.filter(m => unref(m.enabled) !== false)
|
.filter(m => unref(m.enabled) !== false)
|
||||||
.reduce((gain, modifier) => modifier.apply(gain), gain),
|
.reduce((gain, modifier) => modifier.apply(gain), gain),
|
||||||
revert: modifiers.every(m => m.revert != null)
|
invert: modifiers.every(m => m.invert != null)
|
||||||
? (gain: DecimalSource) =>
|
? (gain: DecimalSource) =>
|
||||||
modifiers
|
modifiers
|
||||||
.filter(m => unref(m.enabled) !== false)
|
.filter(m => unref(m.enabled) !== false)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
.reduceRight((gain, modifier) => modifier.revert!(gain), gain)
|
.reduceRight((gain, modifier) => modifier.invert!(gain), gain)
|
||||||
|
: undefined,
|
||||||
|
getFormula: modifiers.every(m => m.getFormula != null)
|
||||||
|
? (gain: FormulaSource) =>
|
||||||
|
modifiers
|
||||||
|
.filter(m => unref(m.enabled) !== false)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
.reduce((acc, curr) => curr.getFormula!(acc), gain)
|
||||||
: undefined,
|
: undefined,
|
||||||
enabled: computed(() => modifiers.filter(m => unref(m.enabled) !== false).length > 0),
|
enabled: computed(() => modifiers.filter(m => unref(m.enabled) !== false).length > 0),
|
||||||
description: jsx(() => (
|
description: jsx(() => (
|
||||||
|
|
Loading…
Reference in a new issue