Made modifiers lazy
This commit is contained in:
parent
17a033bfd9
commit
1997f70699
2 changed files with 184 additions and 128 deletions
|
@ -20,6 +20,7 @@ import type {
|
||||||
ProcessedComputable
|
ProcessedComputable
|
||||||
} from "util/computed";
|
} from "util/computed";
|
||||||
import { convertComputable, processComputable } from "util/computed";
|
import { convertComputable, processComputable } from "util/computed";
|
||||||
|
import { createLazyProxy } from "util/proxies";
|
||||||
import { renderJSX } from "util/vue";
|
import { renderJSX } from "util/vue";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import { computed, unref } from "vue";
|
import { computed, unref } from "vue";
|
||||||
|
@ -253,62 +254,67 @@ export interface Section {
|
||||||
/**
|
/**
|
||||||
* Takes an array of modifier "sections", and creates a JSXFunction that can render all those sections, and allow each section to be collapsed.
|
* Takes an array of modifier "sections", and creates a JSXFunction that can render all those sections, and allow each section to be collapsed.
|
||||||
* Also returns a list of persistent refs that are used to control which sections are currently collapsed.
|
* Also returns a list of persistent refs that are used to control which sections are currently collapsed.
|
||||||
|
* @param sectionsFunc A function that returns the sections to display.
|
||||||
*/
|
*/
|
||||||
export function createCollapsibleModifierSections(
|
export function createCollapsibleModifierSections(
|
||||||
sections: Section[]
|
sectionsFunc: () => Section[]
|
||||||
): [JSXFunction, Persistent<boolean>[]] {
|
): [JSXFunction, Persistent<boolean>[]] {
|
||||||
const processedBase = sections.map(s => convertComputable(s.base));
|
return createLazyProxy(() => {
|
||||||
const processedBaseText = sections.map(s => convertComputable(s.baseText));
|
const sections = sectionsFunc();
|
||||||
const processedVisible = sections.map(s => convertComputable(s.visible));
|
|
||||||
const collapsed = sections.map(() => persistent<boolean>(false));
|
|
||||||
const jsxFunc = jsx(() => {
|
|
||||||
const sectionJSX = sections.map((s, i) => {
|
|
||||||
if (unref(processedVisible[i]) === false) return null;
|
|
||||||
const header = (
|
|
||||||
<h3
|
|
||||||
onClick={() => (collapsed[i].value = !collapsed[i].value)}
|
|
||||||
style="cursor: pointer"
|
|
||||||
>
|
|
||||||
<span class={"modifier-toggle" + (unref(collapsed[i]) ? " collapsed" : "")}>
|
|
||||||
▼
|
|
||||||
</span>
|
|
||||||
{s.title}
|
|
||||||
{s.subtitle ? <span class="subtitle"> ({s.subtitle})</span> : null}
|
|
||||||
</h3>
|
|
||||||
);
|
|
||||||
|
|
||||||
const modifiers = unref(collapsed[i]) ? null : (
|
const processedBase = sections.map(s => convertComputable(s.base));
|
||||||
<>
|
const processedBaseText = sections.map(s => convertComputable(s.baseText));
|
||||||
<div class="modifier-container">
|
const processedVisible = sections.map(s => convertComputable(s.visible));
|
||||||
<span class="modifier-amount">
|
const collapsed = sections.map(() => persistent<boolean>(false));
|
||||||
{format(unref(processedBase[i]) ?? 1)}
|
const jsxFunc = jsx(() => {
|
||||||
|
const sectionJSX = sections.map((s, i) => {
|
||||||
|
if (unref(processedVisible[i]) === false) return null;
|
||||||
|
const header = (
|
||||||
|
<h3
|
||||||
|
onClick={() => (collapsed[i].value = !collapsed[i].value)}
|
||||||
|
style="cursor: pointer"
|
||||||
|
>
|
||||||
|
<span class={"modifier-toggle" + (unref(collapsed[i]) ? " collapsed" : "")}>
|
||||||
|
▼
|
||||||
|
</span>
|
||||||
|
{s.title}
|
||||||
|
{s.subtitle ? <span class="subtitle"> ({s.subtitle})</span> : null}
|
||||||
|
</h3>
|
||||||
|
);
|
||||||
|
|
||||||
|
const modifiers = unref(collapsed[i]) ? null : (
|
||||||
|
<>
|
||||||
|
<div class="modifier-container">
|
||||||
|
<span class="modifier-amount">
|
||||||
|
{format(unref(processedBase[i]) ?? 1)}
|
||||||
|
{s.unit}
|
||||||
|
</span>
|
||||||
|
<span class="modifier-description">
|
||||||
|
{renderJSX(unref(processedBaseText[i]) ?? "Base")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{renderJSX(unref(s.modifier.description))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{i === 0 ? null : <br />}
|
||||||
|
<div>
|
||||||
|
{header}
|
||||||
|
<br />
|
||||||
|
{modifiers}
|
||||||
|
<hr />
|
||||||
|
Total: {format(s.modifier.apply(unref(processedBase[i]) ?? 1))}
|
||||||
{s.unit}
|
{s.unit}
|
||||||
</span>
|
</div>
|
||||||
<span class="modifier-description">
|
</>
|
||||||
{renderJSX(unref(processedBaseText[i]) ?? "Base")}
|
);
|
||||||
</span>
|
});
|
||||||
</div>
|
return <>{sectionJSX}</>;
|
||||||
{renderJSX(unref(s.modifier.description))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{i === 0 ? null : <br />}
|
|
||||||
<div>
|
|
||||||
{header}
|
|
||||||
<br />
|
|
||||||
{modifiers}
|
|
||||||
<hr />
|
|
||||||
Total: {format(s.modifier.apply(unref(processedBase[i]) ?? 1))}
|
|
||||||
{s.unit}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
return <>{sectionJSX}</>;
|
return [jsxFunc, collapsed];
|
||||||
});
|
});
|
||||||
return [jsxFunc, collapsed];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Decimal, { format } from "util/bignum";
|
||||||
import type { WithRequired } from "util/common";
|
import type { WithRequired } from "util/common";
|
||||||
import type { Computable, ProcessedComputable } from "util/computed";
|
import type { Computable, ProcessedComputable } from "util/computed";
|
||||||
import { convertComputable } from "util/computed";
|
import { convertComputable } from "util/computed";
|
||||||
|
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";
|
||||||
|
|
||||||
|
@ -44,112 +45,161 @@ export type ModifierFromOptionalParams<T, S> = T extends undefined
|
||||||
? Omit<WithRequired<Modifier, "revert" | "description">, "enabled">
|
? Omit<WithRequired<Modifier, "revert" | "description">, "enabled">
|
||||||
: WithRequired<Modifier, "revert" | "enabled" | "description">;
|
: WithRequired<Modifier, "revert" | "enabled" | "description">;
|
||||||
|
|
||||||
|
/** An object that configures an additive modifier via {@link createAdditiveModifier}. */
|
||||||
|
export interface AdditiveModifierOptions<
|
||||||
|
T extends Computable<CoercableComponent> | undefined,
|
||||||
|
S extends Computable<boolean> | undefined
|
||||||
|
> {
|
||||||
|
/** The amount to add to the input value. */
|
||||||
|
addend: Computable<DecimalSource>;
|
||||||
|
/** Description of what this modifier is doing. */
|
||||||
|
description?: T;
|
||||||
|
/** A computable that will be processed and passed directly into the returned modifier. */
|
||||||
|
enabled?: S;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a modifier that adds some value to the input value.
|
* Create a modifier that adds some value to the input value.
|
||||||
* @param addend The amount to add to the input value.
|
* @param optionsFunc Additive modifier options.
|
||||||
* @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<
|
export function createAdditiveModifier<
|
||||||
T extends Computable<CoercableComponent> | undefined,
|
T extends Computable<CoercableComponent> | undefined,
|
||||||
S extends Computable<boolean> | undefined,
|
S extends Computable<boolean> | undefined,
|
||||||
R = ModifierFromOptionalParams<T, S>
|
R = ModifierFromOptionalParams<T, S>
|
||||||
>(addend: Computable<DecimalSource>, description?: T, enabled?: S): R {
|
>(optionsFunc: () => AdditiveModifierOptions<T, S>): R {
|
||||||
const processedAddend = convertComputable(addend);
|
return createLazyProxy(() => {
|
||||||
const processedDescription = convertComputable(description);
|
const { addend, description, enabled } = optionsFunc();
|
||||||
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
|
||||||
return {
|
const processedAddend = convertComputable(addend);
|
||||||
apply: (gain: DecimalSource) => Decimal.add(gain, unref(processedAddend)),
|
const processedDescription = convertComputable(description);
|
||||||
revert: (gain: DecimalSource) => Decimal.sub(gain, unref(processedAddend)),
|
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
||||||
enabled: processedEnabled,
|
return {
|
||||||
description:
|
apply: (gain: DecimalSource) => Decimal.add(gain, unref(processedAddend)),
|
||||||
description == null
|
revert: (gain: DecimalSource) => Decimal.sub(gain, unref(processedAddend)),
|
||||||
? undefined
|
enabled: processedEnabled,
|
||||||
: jsx(() => (
|
description:
|
||||||
<div class="modifier-container">
|
description == null
|
||||||
<span class="modifier-amount">
|
? undefined
|
||||||
{Decimal.gte(unref(processedAddend), 0) ? "+" : ""}
|
: jsx(() => (
|
||||||
{format(unref(processedAddend))}
|
<div class="modifier-container">
|
||||||
</span>
|
<span class="modifier-amount">
|
||||||
{unref(processedDescription) ? (
|
{Decimal.gte(unref(processedAddend), 0) ? "+" : ""}
|
||||||
<span class="modifier-description">
|
{format(unref(processedAddend))}
|
||||||
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
|
||||||
{renderJSX(unref(processedDescription)!)}
|
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
{unref(processedDescription) ? (
|
||||||
</div>
|
<span class="modifier-description">
|
||||||
))
|
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
||||||
} as unknown as R;
|
{renderJSX(unref(processedDescription)!)}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}) as unknown as R;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An object that configures an multiplicative modifier via {@link createMultiplicativeModifier}. */
|
||||||
|
export interface MultiplicativeModifierOptions<
|
||||||
|
T extends Computable<CoercableComponent> | undefined,
|
||||||
|
S extends Computable<boolean> | undefined
|
||||||
|
> {
|
||||||
|
/** The amount to multiply the input value by. */
|
||||||
|
multiplier: Computable<DecimalSource>;
|
||||||
|
/** Description of what this modifier is doing. */
|
||||||
|
description?: T;
|
||||||
|
/** A computable that will be processed and passed directly into the returned modifier. */
|
||||||
|
enabled?: S;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a modifier that multiplies the input value by some value.
|
* Create a modifier that multiplies the input value by some value.
|
||||||
* @param multiplier The value to multiply the input value by.
|
* @param optionsFunc Multiplicative modifier options.
|
||||||
* @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<
|
export function createMultiplicativeModifier<
|
||||||
T extends Computable<CoercableComponent> | undefined,
|
T extends Computable<CoercableComponent> | undefined,
|
||||||
S extends Computable<boolean> | undefined,
|
S extends Computable<boolean> | undefined,
|
||||||
R = ModifierFromOptionalParams<T, S>
|
R = ModifierFromOptionalParams<T, S>
|
||||||
>(multiplier: Computable<DecimalSource>, description?: T, enabled?: S): R {
|
>(optionsFunc: () => MultiplicativeModifierOptions<T, S>): R {
|
||||||
const processedMultiplier = convertComputable(multiplier);
|
return createLazyProxy(() => {
|
||||||
const processedDescription = convertComputable(description);
|
const { multiplier, description, enabled } = optionsFunc();
|
||||||
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
|
||||||
return {
|
const processedMultiplier = convertComputable(multiplier);
|
||||||
apply: (gain: DecimalSource) => Decimal.times(gain, unref(processedMultiplier)),
|
const processedDescription = convertComputable(description);
|
||||||
revert: (gain: DecimalSource) => Decimal.div(gain, unref(processedMultiplier)),
|
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
||||||
enabled: processedEnabled,
|
return {
|
||||||
description:
|
apply: (gain: DecimalSource) => Decimal.times(gain, unref(processedMultiplier)),
|
||||||
description == null
|
revert: (gain: DecimalSource) => Decimal.div(gain, unref(processedMultiplier)),
|
||||||
? undefined
|
enabled: processedEnabled,
|
||||||
: jsx(() => (
|
description:
|
||||||
<div class="modifier-container">
|
description == null
|
||||||
<span class="modifier-amount">x{format(unref(processedMultiplier))}</span>
|
? undefined
|
||||||
{unref(processedDescription) ? (
|
: jsx(() => (
|
||||||
<span class="modifier-description">
|
<div class="modifier-container">
|
||||||
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
<span class="modifier-amount">
|
||||||
{renderJSX(unref(processedDescription)!)}
|
x{format(unref(processedMultiplier))}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
{unref(processedDescription) ? (
|
||||||
</div>
|
<span class="modifier-description">
|
||||||
))
|
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
||||||
} as unknown as R;
|
{renderJSX(unref(processedDescription)!)}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}) as unknown as R;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An object that configures an exponential modifier via {@link createExponentialModifier}. */
|
||||||
|
export interface ExponentialModifierOptions<
|
||||||
|
T extends Computable<CoercableComponent> | undefined,
|
||||||
|
S extends Computable<boolean> | undefined
|
||||||
|
> {
|
||||||
|
/** The amount to raise the input value to the power of. */
|
||||||
|
exponent: Computable<DecimalSource>;
|
||||||
|
/** Description of what this modifier is doing. */
|
||||||
|
description?: T;
|
||||||
|
/** A computable that will be processed and passed directly into the returned modifier. */
|
||||||
|
enabled?: S;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a modifier that raises the input value to the power of some value.
|
* 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 optionsFunc Exponential modifier options.
|
||||||
* @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<
|
export function createExponentialModifier<
|
||||||
T extends Computable<CoercableComponent> | undefined,
|
T extends Computable<CoercableComponent> | undefined,
|
||||||
S extends Computable<boolean> | undefined,
|
S extends Computable<boolean> | undefined,
|
||||||
R = ModifierFromOptionalParams<T, S>
|
R = ModifierFromOptionalParams<T, S>
|
||||||
>(exponent: Computable<DecimalSource>, description?: T, enabled?: S): R {
|
>(optionsFunc: () => ExponentialModifierOptions<T, S>): R {
|
||||||
const processedExponent = convertComputable(exponent);
|
return createLazyProxy(() => {
|
||||||
const processedDescription = convertComputable(description);
|
const { exponent, description, enabled } = optionsFunc();
|
||||||
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
|
||||||
return {
|
const processedExponent = convertComputable(exponent);
|
||||||
apply: (gain: DecimalSource) => Decimal.pow(gain, unref(processedExponent)),
|
const processedDescription = convertComputable(description);
|
||||||
revert: (gain: DecimalSource) => Decimal.root(gain, unref(processedExponent)),
|
const processedEnabled = enabled == null ? undefined : convertComputable(enabled);
|
||||||
enabled: processedEnabled,
|
return {
|
||||||
description:
|
apply: (gain: DecimalSource) => Decimal.pow(gain, unref(processedExponent)),
|
||||||
description == null
|
revert: (gain: DecimalSource) => Decimal.root(gain, unref(processedExponent)),
|
||||||
? undefined
|
enabled: processedEnabled,
|
||||||
: jsx(() => (
|
description:
|
||||||
<div class="modifier-container">
|
description == null
|
||||||
<span class="modifier-amount">^{format(unref(processedExponent))}</span>
|
? undefined
|
||||||
{unref(processedDescription) ? (
|
: jsx(() => (
|
||||||
<span class="modifier-description">
|
<div class="modifier-container">
|
||||||
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
<span class="modifier-amount">
|
||||||
{renderJSX(unref(processedDescription)!)}
|
^{format(unref(processedExponent))}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
{unref(processedDescription) ? (
|
||||||
</div>
|
<span class="modifier-description">
|
||||||
))
|
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
||||||
} as unknown as R;
|
{renderJSX(unref(processedDescription)!)}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}) as unknown as R;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue