From fe865bff9d723d10ab405e16337a9f31ee6ac997 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 21 Jul 2022 19:23:33 -0500 Subject: [PATCH 1/4] Add onLoad event --- src/game/events.ts | 5 +++++ src/util/save.ts | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/game/events.ts b/src/game/events.ts index 78219fd..3be00b7 100644 --- a/src/game/events.ts +++ b/src/game/events.ts @@ -45,6 +45,11 @@ export interface GlobalEvents { * @param vue The Vue App being constructed. */ 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}. */ diff --git a/src/util/save.ts b/src/util/save.ts index c5a0073..4138e17 100644 --- a/src/util/save.ts +++ b/src/util/save.ts @@ -1,4 +1,5 @@ import projInfo from "data/projInfo.json"; +import { globalBus } from "game/events"; import type { Player, PlayerData } from "game/player"; import player, { stringifySave } from "game/player"; import settings, { loadSettings } from "game/settings"; @@ -112,6 +113,8 @@ export async function loadSave(playerObj: Partial): Promise { Object.assign(player, playerObj); settings.active = player.id; + + globalBus.emit("onLoad"); } setInterval(() => { From c84bffae592e2b6f3176e31682a01ba433a4d055 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Fri, 22 Jul 2022 18:59:52 -0500 Subject: [PATCH 2/4] Made default layer option functions not anonymous --- src/data/layers/prestige.tsx | 4 ++-- src/data/projEntry.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/layers/prestige.tsx b/src/data/layers/prestige.tsx index 4902610..8216af1 100644 --- a/src/data/layers/prestige.tsx +++ b/src/data/layers/prestige.tsx @@ -10,13 +10,13 @@ import MainDisplay from "features/resources/MainDisplay.vue"; import { createResource } from "features/resources/resource"; import { addTooltip } from "features/tooltips/tooltip"; import { createResourceTooltip } from "features/trees/tree"; -import { createLayer } from "game/layers"; +import { BaseLayer, createLayer } from "game/layers"; import type { DecimalSource } from "util/bignum"; import { render } from "util/vue"; import { createLayerTreeNode, createResetButton } from "../common"; const id = "p"; -const layer = createLayer(id, () => { +const layer = createLayer(id, function (this: BaseLayer) { const name = "Prestige"; const color = "#4BDC13"; const points = createResource(0, "prestige points"); diff --git a/src/data/projEntry.tsx b/src/data/projEntry.tsx index 34a67a0..8ee2c7b 100644 --- a/src/data/projEntry.tsx +++ b/src/data/projEntry.tsx @@ -4,7 +4,7 @@ import { createResource, trackBest, trackOOMPS, trackTotal } from "features/reso import type { GenericTree } from "features/trees/tree"; import { branchedResetPropagation, createTree } from "features/trees/tree"; import { globalBus } from "game/events"; -import type { GenericLayer } from "game/layers"; +import type { BaseLayer, GenericLayer } from "game/layers"; import { createLayer } from "game/layers"; import type { PlayerData } from "game/player"; import player from "game/player"; @@ -17,7 +17,7 @@ import prestige from "./layers/prestige"; /** * @hidden */ -export const main = createLayer("main", () => { +export const main = createLayer("main", function (this: BaseLayer) { const points = createResource(10); const best = trackBest(points); const total = trackTotal(points); From 17a033bfd9f8f7a685826bf69ef976aba75010cd Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Fri, 22 Jul 2022 21:54:37 -0500 Subject: [PATCH 3/4] Use ID to compare layers in trackResetTime --- src/features/reset.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/reset.ts b/src/features/reset.ts index 3a724e3..eaa3631 100644 --- a/src/features/reset.ts +++ b/src/features/reset.ts @@ -70,7 +70,7 @@ const listeners: Record = {}; export function trackResetTime(layer: BaseLayer, reset: GenericReset): Persistent { const resetTime = persistent(new Decimal(0)); globalBus.on("addLayer", layerBeingAdded => { - if (layer === layerBeingAdded) { + if (layer.id === layerBeingAdded.id) { listeners[layer.id]?.(); listeners[layer.id] = layer.on("preUpdate", diff => { resetTime.value = Decimal.add(resetTime.value, diff); From 1997f706994461104b9a447d155d1aa7245df605 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 26 Jul 2022 15:25:31 -0500 Subject: [PATCH 4/4] Made modifiers lazy --- src/data/common.tsx | 106 +++++++++++---------- src/game/modifiers.tsx | 206 +++++++++++++++++++++++++---------------- 2 files changed, 184 insertions(+), 128 deletions(-) diff --git a/src/data/common.tsx b/src/data/common.tsx index f392741..b421460 100644 --- a/src/data/common.tsx +++ b/src/data/common.tsx @@ -20,6 +20,7 @@ import type { ProcessedComputable } from "util/computed"; import { convertComputable, processComputable } from "util/computed"; +import { createLazyProxy } from "util/proxies"; import { renderJSX } from "util/vue"; import type { Ref } from "vue"; import { computed, unref } from "vue"; @@ -33,7 +34,7 @@ export interface ResetButtonOptions extends ClickableOptions { tree: GenericTree; /** The specific tree node associated with this reset button */ treeNode: GenericTreeNode; - /** + /** * Text to display on low conversion amounts, describing what "resetting" is in this context. * Defaults to "Reset for ". */ @@ -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. * 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( - sections: Section[] + sectionsFunc: () => Section[] ): [JSXFunction, Persistent[]] { - const processedBase = sections.map(s => convertComputable(s.base)); - const processedBaseText = sections.map(s => convertComputable(s.baseText)); - const processedVisible = sections.map(s => convertComputable(s.visible)); - const collapsed = sections.map(() => persistent(false)); - const jsxFunc = jsx(() => { - const sectionJSX = sections.map((s, i) => { - if (unref(processedVisible[i]) === false) return null; - const header = ( -

(collapsed[i].value = !collapsed[i].value)} - style="cursor: pointer" - > - - ▼ - - {s.title} - {s.subtitle ? ({s.subtitle}) : null} -

- ); + return createLazyProxy(() => { + const sections = sectionsFunc(); - const modifiers = unref(collapsed[i]) ? null : ( - <> -
- - {format(unref(processedBase[i]) ?? 1)} + const processedBase = sections.map(s => convertComputable(s.base)); + const processedBaseText = sections.map(s => convertComputable(s.baseText)); + const processedVisible = sections.map(s => convertComputable(s.visible)); + const collapsed = sections.map(() => persistent(false)); + const jsxFunc = jsx(() => { + const sectionJSX = sections.map((s, i) => { + if (unref(processedVisible[i]) === false) return null; + const header = ( +

(collapsed[i].value = !collapsed[i].value)} + style="cursor: pointer" + > + + ▼ + + {s.title} + {s.subtitle ? ({s.subtitle}) : null} +

+ ); + + const modifiers = unref(collapsed[i]) ? null : ( + <> +
+ + {format(unref(processedBase[i]) ?? 1)} + {s.unit} + + + {renderJSX(unref(processedBaseText[i]) ?? "Base")} + +
+ {renderJSX(unref(s.modifier.description))} + + ); + + return ( + <> + {i === 0 ? null :
} +
+ {header} +
+ {modifiers} +
+ Total: {format(s.modifier.apply(unref(processedBase[i]) ?? 1))} {s.unit} - - - {renderJSX(unref(processedBaseText[i]) ?? "Base")} - -
- {renderJSX(unref(s.modifier.description))} - - ); - - return ( - <> - {i === 0 ? null :
} -
- {header} -
- {modifiers} -
- Total: {format(s.modifier.apply(unref(processedBase[i]) ?? 1))} - {s.unit} -
- - ); +
+ + ); + }); + return <>{sectionJSX}; }); - return <>{sectionJSX}; + return [jsxFunc, collapsed]; }); - return [jsxFunc, collapsed]; } /** diff --git a/src/game/modifiers.tsx b/src/game/modifiers.tsx index 6f090c7..b476027 100644 --- a/src/game/modifiers.tsx +++ b/src/game/modifiers.tsx @@ -6,6 +6,7 @@ import Decimal, { format } from "util/bignum"; import type { WithRequired } from "util/common"; import type { Computable, ProcessedComputable } from "util/computed"; import { convertComputable } from "util/computed"; +import { createLazyProxy } from "util/proxies"; import { renderJSX } from "util/vue"; import { computed, unref } from "vue"; @@ -44,112 +45,161 @@ export type ModifierFromOptionalParams = T extends undefined ? Omit, "enabled"> : WithRequired; +/** An object that configures an additive modifier via {@link createAdditiveModifier}. */ +export interface AdditiveModifierOptions< + T extends Computable | undefined, + S extends Computable | undefined +> { + /** The amount to add to the input value. */ + addend: Computable; + /** 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. - * @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. + * @param optionsFunc Additive modifier options. */ export function createAdditiveModifier< T extends Computable | undefined, S extends Computable | undefined, R = ModifierFromOptionalParams ->(addend: Computable, description?: T, enabled?: S): R { - const processedAddend = convertComputable(addend); - const processedDescription = convertComputable(description); - const processedEnabled = enabled == null ? undefined : convertComputable(enabled); - return { - apply: (gain: DecimalSource) => Decimal.add(gain, unref(processedAddend)), - revert: (gain: DecimalSource) => Decimal.sub(gain, unref(processedAddend)), - enabled: processedEnabled, - description: - description == null - ? undefined - : jsx(() => ( -
- - {Decimal.gte(unref(processedAddend), 0) ? "+" : ""} - {format(unref(processedAddend))} - - {unref(processedDescription) ? ( - - {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} - {renderJSX(unref(processedDescription)!)} +>(optionsFunc: () => AdditiveModifierOptions): R { + return createLazyProxy(() => { + const { addend, description, enabled } = optionsFunc(); + + const processedAddend = convertComputable(addend); + const processedDescription = convertComputable(description); + const processedEnabled = enabled == null ? undefined : convertComputable(enabled); + return { + apply: (gain: DecimalSource) => Decimal.add(gain, unref(processedAddend)), + revert: (gain: DecimalSource) => Decimal.sub(gain, unref(processedAddend)), + enabled: processedEnabled, + description: + description == null + ? undefined + : jsx(() => ( +
+ + {Decimal.gte(unref(processedAddend), 0) ? "+" : ""} + {format(unref(processedAddend))} - ) : null} -
- )) - } as unknown as R; + {unref(processedDescription) ? ( + + {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} + {renderJSX(unref(processedDescription)!)} + + ) : null} +
+ )) + }; + }) as unknown as R; +} + +/** An object that configures an multiplicative modifier via {@link createMultiplicativeModifier}. */ +export interface MultiplicativeModifierOptions< + T extends Computable | undefined, + S extends Computable | undefined +> { + /** The amount to multiply the input value by. */ + multiplier: Computable; + /** 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. - * @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. + * @param optionsFunc Multiplicative modifier options. */ export function createMultiplicativeModifier< T extends Computable | undefined, S extends Computable | undefined, R = ModifierFromOptionalParams ->(multiplier: Computable, description?: T, enabled?: S): R { - const processedMultiplier = convertComputable(multiplier); - const processedDescription = convertComputable(description); - const processedEnabled = enabled == null ? undefined : convertComputable(enabled); - return { - apply: (gain: DecimalSource) => Decimal.times(gain, unref(processedMultiplier)), - revert: (gain: DecimalSource) => Decimal.div(gain, unref(processedMultiplier)), - enabled: processedEnabled, - description: - description == null - ? undefined - : jsx(() => ( -
- x{format(unref(processedMultiplier))} - {unref(processedDescription) ? ( - - {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} - {renderJSX(unref(processedDescription)!)} +>(optionsFunc: () => MultiplicativeModifierOptions): R { + return createLazyProxy(() => { + const { multiplier, description, enabled } = optionsFunc(); + + const processedMultiplier = convertComputable(multiplier); + const processedDescription = convertComputable(description); + const processedEnabled = enabled == null ? undefined : convertComputable(enabled); + return { + apply: (gain: DecimalSource) => Decimal.times(gain, unref(processedMultiplier)), + revert: (gain: DecimalSource) => Decimal.div(gain, unref(processedMultiplier)), + enabled: processedEnabled, + description: + description == null + ? undefined + : jsx(() => ( +
+ + x{format(unref(processedMultiplier))} - ) : null} -
- )) - } as unknown as R; + {unref(processedDescription) ? ( + + {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} + {renderJSX(unref(processedDescription)!)} + + ) : null} +
+ )) + }; + }) as unknown as R; +} + +/** An object that configures an exponential modifier via {@link createExponentialModifier}. */ +export interface ExponentialModifierOptions< + T extends Computable | undefined, + S extends Computable | undefined +> { + /** The amount to raise the input value to the power of. */ + exponent: Computable; + /** 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. - * @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. + * @param optionsFunc Exponential modifier options. */ export function createExponentialModifier< T extends Computable | undefined, S extends Computable | undefined, R = ModifierFromOptionalParams ->(exponent: Computable, description?: T, enabled?: S): R { - const processedExponent = convertComputable(exponent); - const processedDescription = convertComputable(description); - const processedEnabled = enabled == null ? undefined : convertComputable(enabled); - return { - apply: (gain: DecimalSource) => Decimal.pow(gain, unref(processedExponent)), - revert: (gain: DecimalSource) => Decimal.root(gain, unref(processedExponent)), - enabled: processedEnabled, - description: - description == null - ? undefined - : jsx(() => ( -
- ^{format(unref(processedExponent))} - {unref(processedDescription) ? ( - - {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} - {renderJSX(unref(processedDescription)!)} +>(optionsFunc: () => ExponentialModifierOptions): R { + return createLazyProxy(() => { + const { exponent, description, enabled } = optionsFunc(); + + const processedExponent = convertComputable(exponent); + const processedDescription = convertComputable(description); + const processedEnabled = enabled == null ? undefined : convertComputable(enabled); + return { + apply: (gain: DecimalSource) => Decimal.pow(gain, unref(processedExponent)), + revert: (gain: DecimalSource) => Decimal.root(gain, unref(processedExponent)), + enabled: processedEnabled, + description: + description == null + ? undefined + : jsx(() => ( +
+ + ^{format(unref(processedExponent))} - ) : null} -
- )) - } as unknown as R; + {unref(processedDescription) ? ( + + {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} + {renderJSX(unref(processedDescription)!)} + + ) : null} +
+ )) + }; + }) as unknown as R; } /**