Merge remote-tracking branch 'template/main'

This commit is contained in:
thepaperpilot 2022-07-26 15:32:07 -05:00
commit bc420e092e
7 changed files with 197 additions and 133 deletions

View file

@ -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];
} }
/** /**

View file

@ -10,13 +10,13 @@ import MainDisplay from "features/resources/MainDisplay.vue";
import { createResource } from "features/resources/resource"; import { createResource } from "features/resources/resource";
import { addTooltip } from "features/tooltips/tooltip"; import { addTooltip } from "features/tooltips/tooltip";
import { createResourceTooltip } from "features/trees/tree"; import { createResourceTooltip } from "features/trees/tree";
import { createLayer } from "game/layers"; import { BaseLayer, createLayer } from "game/layers";
import type { DecimalSource } from "util/bignum"; import type { DecimalSource } from "util/bignum";
import { render } from "util/vue"; import { render } from "util/vue";
import { createLayerTreeNode, createResetButton } from "../common"; import { createLayerTreeNode, createResetButton } from "../common";
const id = "p"; const id = "p";
const layer = createLayer(id, () => { const layer = createLayer(id, function (this: BaseLayer) {
const name = "Prestige"; const name = "Prestige";
const color = "#4BDC13"; const color = "#4BDC13";
const points = createResource<DecimalSource>(0, "prestige points"); const points = createResource<DecimalSource>(0, "prestige points");

View file

@ -5,7 +5,7 @@ import { createResource, trackBest, trackOOMPS, trackTotal } from "features/reso
import type { GenericTree } from "features/trees/tree"; import type { GenericTree } from "features/trees/tree";
import { branchedResetPropagation, createTree } from "features/trees/tree"; import { branchedResetPropagation, createTree } from "features/trees/tree";
import { globalBus } from "game/events"; import { globalBus } from "game/events";
import type { GenericLayer } from "game/layers"; import type { BaseLayer, GenericLayer } from "game/layers";
import { setupLayerModal } from "game/layers"; import { setupLayerModal } from "game/layers";
import { createLayer } from "game/layers"; import { createLayer } from "game/layers";
import type { PlayerData } from "game/player"; import type { PlayerData } from "game/player";
@ -21,7 +21,7 @@ import f from "./layers/aca/f";
/** /**
* @hidden * @hidden
*/ */
export const main = createLayer("main", () => { export const main = createLayer("main", function (this: BaseLayer) {
const points = createResource<DecimalSource>(10); const points = createResource<DecimalSource>(10);
const best = trackBest(points); const best = trackBest(points);
const total = trackTotal(points); const total = trackTotal(points);

View file

@ -70,7 +70,7 @@ const listeners: Record<string, Unsubscribe | undefined> = {};
export function trackResetTime(layer: BaseLayer, reset: GenericReset): Persistent<Decimal> { export function trackResetTime(layer: BaseLayer, reset: GenericReset): Persistent<Decimal> {
const resetTime = persistent<Decimal>(new Decimal(0)); const resetTime = persistent<Decimal>(new Decimal(0));
globalBus.on("addLayer", layerBeingAdded => { globalBus.on("addLayer", layerBeingAdded => {
if (layer === layerBeingAdded) { if (layer.id === layerBeingAdded.id) {
listeners[layer.id]?.(); listeners[layer.id]?.();
listeners[layer.id] = layer.on("preUpdate", diff => { listeners[layer.id] = layer.on("preUpdate", diff => {
resetTime.value = Decimal.add(resetTime.value, diff); resetTime.value = Decimal.add(resetTime.value, diff);

View file

@ -45,6 +45,11 @@ export interface GlobalEvents {
* @param vue The Vue App being constructed. * @param vue The Vue App being constructed.
*/ */
setupVue: (vue: App) => void; setupVue: (vue: App) => void;
/**
* Sent whenever a save has finished loading.
* Happens when the page is opened and upon switching saves in the saves manager.
*/
onLoad: VoidFunction;
} }
/** A global event bus for hooking into {@link GlobalEvents}. */ /** A global event bus for hooking into {@link GlobalEvents}. */

View file

@ -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;
} }
/** /**

View file

@ -1,4 +1,5 @@
import projInfo from "data/projInfo.json"; import projInfo from "data/projInfo.json";
import { globalBus } from "game/events";
import type { Player, PlayerData } from "game/player"; import type { Player, PlayerData } from "game/player";
import player, { stringifySave } from "game/player"; import player, { stringifySave } from "game/player";
import settings, { loadSettings } from "game/settings"; import settings, { loadSettings } from "game/settings";
@ -112,6 +113,8 @@ export async function loadSave(playerObj: Partial<PlayerData>): Promise<void> {
Object.assign(player, playerObj); Object.assign(player, playerObj);
settings.active = player.id; settings.active = player.id;
globalBus.emit("onLoad");
} }
setInterval(() => { setInterval(() => {