diff --git a/src/features/achievements/achievement.tsx b/src/features/achievements/achievement.tsx index 87af9e2..64f60ee 100644 --- a/src/features/achievements/achievement.tsx +++ b/src/features/achievements/achievement.tsx @@ -1,5 +1,5 @@ import AchievementComponent from "features/achievements/Achievement.vue"; -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import { CoercableComponent, Component, diff --git a/src/features/action.tsx b/src/features/action.tsx index ed098bb..ab4b3e4 100644 --- a/src/features/action.tsx +++ b/src/features/action.tsx @@ -31,7 +31,7 @@ import { coerceComponent, isCoercableComponent, render } from "util/vue"; import { computed, Ref, ref, unref } from "vue"; import { BarOptions, createBar, GenericBar } from "./bars/bar"; import { ClickableOptions } from "./clickables/clickable"; -import { Decorator } from "./decorators"; +import { Decorator } from "./decorators/common"; export const ActionType = Symbol("Action"); diff --git a/src/features/bars/bar.ts b/src/features/bars/bar.ts index 107fe1f..72d9a60 100644 --- a/src/features/bars/bar.ts +++ b/src/features/bars/bar.ts @@ -1,5 +1,5 @@ import BarComponent from "features/bars/Bar.vue"; -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import type { CoercableComponent, GenericComponent, diff --git a/src/features/challenges/challenge.tsx b/src/features/challenges/challenge.tsx index f735191..1bbbee6 100644 --- a/src/features/challenges/challenge.tsx +++ b/src/features/challenges/challenge.tsx @@ -1,7 +1,7 @@ import { isArray } from "@vue/shared"; import Toggle from "components/fields/Toggle.vue"; import ChallengeComponent from "features/challenges/Challenge.vue"; -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import type { CoercableComponent, OptionsFunc, Replace, StyleValue } from "features/feature"; import { Component, diff --git a/src/features/clickables/clickable.ts b/src/features/clickables/clickable.ts index 8df5285..b9e383b 100644 --- a/src/features/clickables/clickable.ts +++ b/src/features/clickables/clickable.ts @@ -1,5 +1,5 @@ import ClickableComponent from "features/clickables/Clickable.vue"; -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import type { CoercableComponent, GenericComponent, diff --git a/src/features/conversion.ts b/src/features/conversion.ts index baa1ce2..b0ee578 100644 --- a/src/features/conversion.ts +++ b/src/features/conversion.ts @@ -11,7 +11,7 @@ import { convertComputable, processComputable } from "util/computed"; import { createLazyProxy } from "util/proxies"; import type { Ref } from "vue"; import { computed, unref } from "vue"; -import { Decorator } from "./decorators"; +import { Decorator } from "./decorators/common"; /** An object that configures a {@link Conversion}. */ export interface ConversionOptions { diff --git a/src/features/decorators.ts b/src/features/decorators/bonusDecorator.ts similarity index 50% rename from src/features/decorators.ts rename to src/features/decorators/bonusDecorator.ts index 4eeadb4..d41d2d5 100644 --- a/src/features/decorators.ts +++ b/src/features/decorators/bonusDecorator.ts @@ -1,44 +1,9 @@ -import { Replace, OptionsObject } from "./feature"; -import Decimal, { DecimalSource } from "util/bignum"; -import { Computable, GetComputableType, processComputable, ProcessedComputable } from "util/computed"; -import { Persistent, State } from "game/persistence"; -import { computed, Ref, unref } from "vue"; +import { Replace } from "features/feature"; +import Decimal, { DecimalSource } from "lib/break_eternity"; +import { Computable, GetComputableType, ProcessedComputable, processComputable } from "util/computed"; +import { Ref, computed, unref } from "vue"; +import { Decorator } from "./common"; -/*----====----*/ - -export type Decorator = { - getPersistentData?(): Record>; - preConstruct?(feature: OptionsObject): void; - postConstruct?(feature: OptionsObject): void; - getGatheredProps?(feature: OptionsObject): Partial> -} - -/*----====----*/ - -// #region Effect Decorator -export interface EffectFeatureOptions { - effect: Computable; -} - -export type EffectFeature = Replace< - T, { effect: GetComputableType; } ->; - -export type GenericEffectFeature = Replace< - EffectFeature, - { effect: ProcessedComputable; } ->; - -export const effectDecorator: Decorator = { - postConstruct(feature) { - processComputable(feature, "effect"); - } -} -// #endregion - -/*----====----*/ - -// #region Bonus Amount/Completions Decorator export interface BonusAmountFeatureOptions { bonusAmount: Computable; } @@ -77,6 +42,16 @@ export type GenericBonusCompletionsFeature = Replace< } >; +/** + * Allows the addition of "bonus levels" to the decorated feature, with an accompanying "total amount". + * To function properly, the `createFeature()` function must have its generic type extended by {@linkcode BonusAmountFeatureOptions}. + * To allow access to the decorated values outside the `createFeature()` function, the output type must be extended by {@linkcode GenericBonusAmountFeature}. + * @example ```ts + * createRepeatable(() => ({ + * bonusAmount: noPersist(otherRepeatable.amount), + * ... + * }), bonusAmountDecorator) as GenericRepeatable & GenericBonusAmountFeature + */ export const bonusAmountDecorator: Decorator = { postConstruct(feature) { processComputable(feature, "bonusAmount"); @@ -88,18 +63,25 @@ export const bonusAmountDecorator: Decorator = { + +/** + * Allows the addition of "bonus levels" to the decorated feature, with an accompanying "total amount". + * To function properly, the `createFeature()` function must have its generic type extended by {@linkcode BonusCompletionFeatureOptions}. + * To allow access to the decorated values outside the `createFeature()` function, the output type must be extended by {@linkcode GenericBonusCompletionFeature}. + * @example ```ts + * createChallenge(() => ({ + * bonusCompletions: noPersist(otherChallenge.completions), + * ... + * }), bonusCompletionDecorator) as GenericChallenge & GenericBonusCompletionFeature + */ +export const bonusCompletionsDecorator: Decorator = { postConstruct(feature) { - processComputable(feature, "bonusAmount"); + processComputable(feature, "bonusCompletions"); if (feature.totalCompletions === undefined) { feature.totalCompletions = computed(() => Decimal.add( unref(feature.completions ?? 0), - unref(feature.bonusAmount as ProcessedComputable) + unref(feature.bonusCompletions as ProcessedComputable) )); } } } -// #endregion - -/*----====----*/ - diff --git a/src/features/decorators/common.ts b/src/features/decorators/common.ts new file mode 100644 index 0000000..d308390 --- /dev/null +++ b/src/features/decorators/common.ts @@ -0,0 +1,49 @@ +import { Replace, OptionsObject } from "../feature"; +import { Computable, GetComputableType, processComputable, ProcessedComputable } from "util/computed"; +import { Persistent, State } from "game/persistence"; + +/*----====----*/ + +export type Decorator = { + getPersistentData?(): Record>; + preConstruct?(feature: OptionsObject): void; + postConstruct?(feature: OptionsObject): void; + getGatheredProps?(feature: OptionsObject): Partial> +} + +/*----====----*/ + +// #region Effect Decorator +export interface EffectFeatureOptions { + effect: Computable; +} + +export type EffectFeature = Replace< + T, { effect: GetComputableType; } +>; + +export type GenericEffectFeature = Replace< + EffectFeature, + { effect: ProcessedComputable; } +>; + +/** + * Allows the usage of an `effect` field in the decorated feature. + * To function properly, the `createFeature()` function must have its generic type extended by {@linkcode EffectFeatureOptions}. + * To allow access to the decorated values outside the `createFeature()` function, the output type must be extended by {@linkcode GenericEffectFeature}. + * @example ```ts + * createRepeatable(() => ({ + * effect() { return Decimal.pow(2, this.amount); }, + * ... + * }), effectDecorator) as GenericUpgrade & GenericEffectFeature; + * ``` + */ +export const effectDecorator: Decorator = { + postConstruct(feature) { + processComputable(feature, "effect"); + } +} +// #endregion + +/*----====----*/ + diff --git a/src/features/milestones/milestone.tsx b/src/features/milestones/milestone.tsx index 9908089..2796f57 100644 --- a/src/features/milestones/milestone.tsx +++ b/src/features/milestones/milestone.tsx @@ -1,5 +1,5 @@ import Select from "components/fields/Select.vue"; -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import type { CoercableComponent, GenericComponent, diff --git a/src/features/repeatable.tsx b/src/features/repeatable.tsx index ae3ecf4..dd6d717 100644 --- a/src/features/repeatable.tsx +++ b/src/features/repeatable.tsx @@ -24,7 +24,7 @@ import { createLazyProxy } from "util/proxies"; import { coerceComponent, isCoercableComponent } from "util/vue"; import type { Ref } from "vue"; import { computed, unref } from "vue"; -import { Decorator, GenericBonusAmountFeature } from "./decorators"; +import { Decorator } from "./decorators/common"; /** A symbol used to identify {@link Repeatable} features. */ export const RepeatableType = Symbol("Repeatable"); diff --git a/src/features/trees/tree.ts b/src/features/trees/tree.ts index caaeee3..0784f3e 100644 --- a/src/features/trees/tree.ts +++ b/src/features/trees/tree.ts @@ -1,4 +1,4 @@ -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import type { CoercableComponent, OptionsFunc, Replace, StyleValue } from "features/feature"; import { Component, GatherProps, getUniqueID, setDefault, Visibility } from "features/feature"; import type { Link } from "features/links/links"; diff --git a/src/features/upgrades/upgrade.ts b/src/features/upgrades/upgrade.ts index 7c90aa5..72914a8 100644 --- a/src/features/upgrades/upgrade.ts +++ b/src/features/upgrades/upgrade.ts @@ -1,5 +1,5 @@ import { isArray } from "@vue/shared"; -import { Decorator } from "features/decorators"; +import { Decorator } from "features/decorators/common"; import type { CoercableComponent, GenericComponent, @@ -15,11 +15,13 @@ import { setDefault, Visibility } from "features/feature"; +import { createResource } from "features/resources/resource"; import UpgradeComponent from "features/upgrades/Upgrade.vue"; import type { GenericLayer } from "game/layers"; import type { Persistent } from "game/persistence"; import { persistent } from "game/persistence"; import { +createCostRequirement, createVisibilityRequirement, payRequirements, Requirements,