Added FeatureOptionsFunc to simplify features

This commit is contained in:
thepaperpilot 2022-04-10 19:04:56 -05:00
parent 838ac46cf9
commit 64f1b460b0
21 changed files with 76 additions and 67 deletions

View file

@ -5,7 +5,7 @@ import {
GenericClickable
} from "features/clickables/clickable";
import { GenericConversion } from "features/conversion";
import { CoercableComponent, jsx, Replace, setDefault } from "features/feature";
import { CoercableComponent, OptionsFunc, jsx, Replace, setDefault } from "features/feature";
import { displayResource } from "features/resources/resource";
import {
createTreeNode,
@ -57,7 +57,7 @@ export type GenericResetButton = Replace<
>;
export function createResetButton<T extends ClickableOptions & ResetButtonOptions>(
optionsFunc: () => T
optionsFunc: OptionsFunc<T>
): ResetButton<T> {
return createClickable(() => {
const resetButton = optionsFunc();
@ -139,7 +139,7 @@ export type GenericLayerTreeNode = Replace<
>;
export function createLayerTreeNode<T extends LayerTreeNodeOptions>(
optionsFunc: () => T
optionsFunc: OptionsFunc<T>
): LayerTreeNode<T> {
return createTreeNode(() => {
const options = optionsFunc();

View file

@ -2,6 +2,7 @@ import AchievementComponent from "features/achievements/Achievement.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -67,12 +68,10 @@ export type GenericAchievement = Replace<
>;
export function createAchievement<T extends AchievementOptions>(
optionsFunc: () => T & ThisType<Achievement<T>>
optionsFunc: OptionsFunc<T, Achievement<T>, BaseAchievement>
): Achievement<T> {
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const achievement: Partial<BaseAchievement> & typeof temp = temp;
const achievement = Object.assign(persistent, optionsFunc());
achievement.id = getUniqueID("achievement-");
achievement.type = AchievementType;
achievement[Component] = AchievementComponent;

View file

@ -2,6 +2,7 @@ import BarComponent from "features/bars/Bar.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -79,9 +80,11 @@ export type GenericBar = Replace<
}
>;
export function createBar<T extends BarOptions>(optionsFunc: () => T & ThisType<Bar<T>>): Bar<T> {
export function createBar<T extends BarOptions>(
optionsFunc: OptionsFunc<T, Bar<T>, BaseBar>
): Bar<T> {
return createLazyProxy(() => {
const bar: T & Partial<BaseBar> = optionsFunc();
const bar = optionsFunc();
bar.id = getUniqueID("bar-");
bar.type = BarType;
bar[Component] = BarComponent;

View file

@ -1,6 +1,7 @@
import BoardComponent from "features/boards/Board.vue";
import {
Component,
OptionsFunc,
findFeatures,
GatherProps,
getUniqueID,
@ -197,13 +198,11 @@ export type GenericBoard = Replace<
>;
export function createBoard<T extends BoardOptions>(
optionsFunc: () => T & ThisType<Board<T>>
optionsFunc: OptionsFunc<T, Board<T>, BaseBoard>
): Board<T> {
return createLazyProxy(
persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const board: Partial<BaseBoard> & typeof temp = temp;
const board = Object.assign(persistent, optionsFunc());
board.id = getUniqueID("board-");
board.type = BoardType;
board[Component] = BoardComponent;

View file

@ -15,6 +15,7 @@ import { computed, Ref, unref } from "vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
jsx,
@ -87,12 +88,10 @@ export type GenericBuyable = Replace<
>;
export function createBuyable<T extends BuyableOptions>(
optionsFunc: () => T & ThisType<Buyable<T>>
optionsFunc: OptionsFunc<T, Buyable<T>, BaseBuyable>
): Buyable<T> {
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const buyable: Partial<BaseBuyable> & typeof temp = temp;
const buyable = Object.assign(persistent, optionsFunc());
if (buyable.canPurchase == null && (buyable.resource == null || buyable.cost == null)) {
console.warn(

View file

@ -4,6 +4,7 @@ import ChallengeComponent from "features/challenges/Challenge.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
jsx,
@ -96,12 +97,12 @@ export type GenericChallenge = Replace<
>;
export function createChallenge<T extends ChallengeOptions>(
optionsFunc: () => T & ThisType<Challenge<T>>
optionsFunc: OptionsFunc<T, Challenge<T>, BaseChallenge>
): Challenge<T> {
const completions = persistent(0);
const active = persistent(false);
return createLazyProxy(() => {
const challenge: T & Partial<BaseChallenge> = optionsFunc();
const challenge = optionsFunc();
if (
challenge.canComplete == null &&

View file

@ -2,6 +2,7 @@ import ClickableComponent from "features/clickables/Clickable.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -69,10 +70,10 @@ export type GenericClickable = Replace<
>;
export function createClickable<T extends ClickableOptions>(
optionsFunc: () => T & ThisType<Clickable<T>>
optionsFunc: OptionsFunc<T, Clickable<T>, BaseClickable>
): Clickable<T> {
return createLazyProxy(() => {
const clickable: T & Partial<BaseClickable> = optionsFunc();
const clickable = optionsFunc();
clickable.id = getUniqueID("clickable-");
clickable.type = ClickableType;
clickable[Component] = ClickableComponent;

View file

@ -1,17 +1,15 @@
import { GenericLayer } from "game/layers";
import Decimal, { DecimalSource } from "util/bignum";
import { isFunction } from "util/common";
import {
Computable,
convertComputable,
DoNotCache,
GetComputableTypeWithDefault,
processComputable,
ProcessedComputable
} from "util/computed";
import { createLazyProxy } from "util/proxies";
import { computed, isRef, Ref, unref } from "vue";
import { Replace, setDefault } from "./feature";
import { OptionsFunc, Replace, setDefault } from "./feature";
import { Resource } from "./resources/resource";
export interface ConversionOptions {
@ -62,10 +60,10 @@ export interface GainModifier {
}
export function createConversion<T extends ConversionOptions>(
optionsFunc: () => T & ThisType<Conversion<T>>
optionsFunc: OptionsFunc<T, Conversion<T>, BaseConversion>
): Conversion<T> {
return createLazyProxy(() => {
const conversion: T = optionsFunc();
const conversion = optionsFunc();
if (conversion.currentGain == null) {
conversion.currentGain = computed(() => {
@ -199,13 +197,13 @@ export function createPolynomialScaling(
}
export function createCumulativeConversion<S extends ConversionOptions>(
optionsFunc: () => S & ThisType<Conversion<S>>
optionsFunc: OptionsFunc<S, Conversion<S>>
): Conversion<S> {
return createConversion(optionsFunc);
}
export function createIndependentConversion<S extends ConversionOptions>(
optionsFunc: () => S & ThisType<Conversion<S>>
optionsFunc: OptionsFunc<S, Conversion<S>>
): Conversion<S> {
return createConversion(() => {
const conversion: S = optionsFunc();

View file

@ -24,6 +24,8 @@ export type FeatureComponent<T> = Omit<
export type Replace<T, S> = S & Omit<T, keyof S>;
export type OptionsFunc<T, S = T, R = Record<string, unknown>> = () => T & ThisType<S> & Partial<R>;
let id = 0;
// Get a unique ID to allow a feature to be found for creating branches
// and any other uses requiring unique identifiers for each feature

View file

@ -2,6 +2,7 @@ import GridComponent from "features/grids/Grid.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -241,12 +242,10 @@ export type GenericGrid = Replace<
>;
export function createGrid<T extends GridOptions>(
optionsFunc: () => T & ThisType<Grid<T>>
optionsFunc: OptionsFunc<T, Grid<T>, BaseGrid>
): Grid<T> {
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const grid: Partial<BaseGrid> & typeof temp = temp;
const grid = Object.assign(persistent, optionsFunc());
grid.id = getUniqueID("grid-");
grid[Component] = GridComponent;

View file

@ -11,7 +11,7 @@ import {
} from "util/computed";
import { createLazyProxy } from "util/proxies";
import { shallowReactive, unref } from "vue";
import { findFeatures, jsx, Replace, setDefault } from "./feature";
import { OptionsFunc, findFeatures, jsx, Replace, setDefault } from "./feature";
export const hotkeys: Record<string, GenericHotkey | undefined> = shallowReactive({});
export const HotkeyType = Symbol("Hotkey");
@ -43,10 +43,10 @@ export type GenericHotkey = Replace<
>;
export function createHotkey<T extends HotkeyOptions>(
optionsFunc: () => T & ThisType<Hotkey<T>>
optionsFunc: OptionsFunc<T, Hotkey<T>, BaseHotkey>
): Hotkey<T> {
return createLazyProxy(() => {
const hotkey: T & Partial<BaseHotkey> = optionsFunc();
const hotkey = optionsFunc();
hotkey.type = HotkeyType;
processComputable(hotkey as T, "enabled");

View file

@ -2,6 +2,7 @@ import InfoboxComponent from "features/infoboxes/Infobox.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -63,12 +64,10 @@ export type GenericInfobox = Replace<
>;
export function createInfobox<T extends InfoboxOptions>(
optionsFunc: () => T & ThisType<Infobox<T>>
optionsFunc: OptionsFunc<T, Infobox<T>, BaseInfobox>
): Infobox<T> {
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const infobox: Partial<BaseInfobox> & typeof temp = temp;
const infobox = Object.assign(persistent, optionsFunc());
infobox.id = getUniqueID("infobox-");
infobox.type = InfoboxType;
infobox[Component] = InfoboxComponent;

View file

@ -1,5 +1,5 @@
import LinksComponent from "./Links.vue";
import { Component, GatherProps, Replace } from "features/feature";
import { Component, OptionsFunc, GatherProps, Replace } from "features/feature";
import { Position } from "game/layers";
import {
Computable,
@ -44,10 +44,10 @@ export type GenericLinks = Replace<
>;
export function createLinks<T extends LinksOptions>(
optionsFunc: (() => T) & ThisType<Links<T>>
optionsFunc: OptionsFunc<T, Links<T>, BaseLinks>
): Links<T> {
return createLazyProxy(() => {
const links: T & Partial<BaseLinks> = optionsFunc();
const links = optionsFunc();
links.type = LinksType;
links[Component] = LinksComponent;

View file

@ -2,6 +2,7 @@ import Select from "components/fields/Select.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
jsx,
@ -83,12 +84,10 @@ export type GenericMilestone = Replace<
>;
export function createMilestone<T extends MilestoneOptions>(
optionsFunc: () => T & ThisType<Milestone<T>>
optionsFunc: OptionsFunc<T, Milestone<T>, BaseMilestone>
): Milestone<T> {
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const milestone: Partial<BaseMilestone> & typeof temp = temp;
const milestone = Object.assign(persistent, optionsFunc());
milestone.id = getUniqueID("milestone-");
milestone.type = MilestoneType;
milestone[Component] = MilestoneComponent;

View file

@ -1,6 +1,13 @@
import ParticlesComponent from "features/particles/Particles.vue";
import { Ref, shallowRef, unref } from "vue";
import { Component, GatherProps, getUniqueID, Replace, StyleValue } from "features/feature";
import {
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
StyleValue
} from "features/feature";
import { createLazyProxy } from "util/proxies";
import { Application } from "pixi.js";
import { Emitter, EmitterConfigV3, upgradeConfig } from "@pixi/particle-emitter";
@ -35,10 +42,10 @@ export type Particles<T extends ParticlesOptions> = Replace<
export type GenericParticles = Particles<ParticlesOptions>;
export function createParticles<T extends ParticlesOptions>(
optionsFunc: () => T & ThisType<Particles<T>>
optionsFunc: OptionsFunc<T, Particles<T>, BaseParticles>
): Particles<T> {
return createLazyProxy(() => {
const particles: T & Partial<BaseParticles> = optionsFunc();
const particles = optionsFunc();
particles.id = getUniqueID("particles-");
particles.type = ParticlesType;
particles[Component] = ParticlesComponent;

View file

@ -1,4 +1,4 @@
import { getUniqueID, Replace } from "features/feature";
import { OptionsFunc, getUniqueID, Replace } from "features/feature";
import { globalBus } from "game/events";
import { GenericLayer } from "game/layers";
import { DefaultValue, Persistent, persistent, PersistentState } from "game/persistence";
@ -31,10 +31,10 @@ export type Reset<T extends ResetOptions> = Replace<
export type GenericReset = Reset<ResetOptions>;
export function createReset<T extends ResetOptions>(
optionsFunc: () => T & ThisType<Reset<T>>
optionsFunc: OptionsFunc<T, Reset<T>, BaseReset>
): Reset<T> {
return createLazyProxy(() => {
const reset: T & Partial<BaseReset> = optionsFunc();
const reset = optionsFunc();
reset.id = getUniqueID("reset-");
reset.type = ResetType;

View file

@ -1,6 +1,7 @@
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -36,9 +37,11 @@ export type Tab<T extends TabOptions> = Replace<
export type GenericTab = Tab<TabOptions>;
export function createTab<T extends TabOptions>(optionsFunc: () => T & ThisType<Tab<T>>): Tab<T> {
export function createTab<T extends TabOptions>(
optionsFunc: OptionsFunc<T, Tab<T>, BaseTab>
): Tab<T> {
return createLazyProxy(() => {
const tab: T & Partial<BaseTab> = optionsFunc();
const tab = optionsFunc();
tab.id = getUniqueID("tab-");
tab.type = TabType;
tab[Component] = TabComponent;

View file

@ -1,6 +1,7 @@
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -91,7 +92,7 @@ export type GenericTabFamily = Replace<
export function createTabFamily<T extends TabFamilyOptions>(
tabs: Record<string, () => TabButtonOptions>,
optionsFunc: () => T & ThisType<TabFamily<T>>
optionsFunc: OptionsFunc<T, TabFamily<T>, BaseTabFamily>
): TabFamily<T> {
if (Object.keys(tabs).length === 0) {
console.warn("Cannot create tab family with 0 tabs");
@ -99,9 +100,7 @@ export function createTabFamily<T extends TabFamilyOptions>(
}
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const tabFamily: Partial<BaseTabFamily> & typeof temp = temp;
const tabFamily = Object.assign(persistent, optionsFunc());
tabFamily.id = getUniqueID("tabFamily-");
tabFamily.type = TabFamilyType;

View file

@ -1,6 +1,7 @@
import {
CoercableComponent,
Component,
OptionsFunc,
GatherProps,
getUniqueID,
Replace,
@ -74,11 +75,11 @@ export type GenericTreeNode = Replace<
>;
export function createTreeNode<T extends TreeNodeOptions>(
optionsFunc: () => T & ThisType<TreeNode<T>>
optionsFunc: OptionsFunc<T, TreeNode<T>, BaseTreeNode>
): TreeNode<T> {
const forceTooltip = persistent(false);
return createLazyProxy(() => {
const treeNode: T & Partial<BaseTreeNode> = optionsFunc();
const treeNode = optionsFunc();
treeNode.id = getUniqueID("treeNode-");
treeNode.type = TreeNodeType;
@ -168,10 +169,10 @@ export type GenericTree = Replace<
>;
export function createTree<T extends TreeOptions>(
optionsFunc: () => T & ThisType<Tree<T>>
optionsFunc: OptionsFunc<T, Tree<T>, BaseTree>
): Tree<T> {
return createLazyProxy(() => {
const tree: T & Partial<BaseTree> = optionsFunc();
const tree = optionsFunc();
tree.id = getUniqueID("tree-");
tree.type = TreeType;
tree[Component] = TreeComponent;

View file

@ -2,6 +2,7 @@ import UpgradeComponent from "features/upgrades/Upgrade.vue";
import {
CoercableComponent,
Component,
OptionsFunc,
findFeatures,
GatherProps,
getUniqueID,
@ -78,12 +79,10 @@ export type GenericUpgrade = Replace<
>;
export function createUpgrade<T extends UpgradeOptions>(
optionsFunc: () => T & ThisType<Upgrade<T>>
optionsFunc: OptionsFunc<T, Upgrade<T>, BaseUpgrade>
): Upgrade<T> {
return createLazyProxy(persistent => {
// Create temp literally just to avoid explicitly assigning types
const temp = Object.assign(persistent, optionsFunc());
const upgrade: Partial<BaseUpgrade> & typeof temp = temp;
const upgrade = Object.assign(persistent, optionsFunc());
upgrade.id = getUniqueID("upgrade-");
upgrade.type = UpgradeType;
upgrade[Component] = UpgradeComponent;

View file

@ -1,6 +1,7 @@
import Modal from "components/Modal.vue";
import {
CoercableComponent,
OptionsFunc,
jsx,
JSXFunction,
Replace,
@ -104,7 +105,7 @@ export const persistentRefs: Record<string, Set<Persistent>> = {};
export const addingLayers: string[] = [];
export function createLayer<T extends LayerOptions>(
id: string,
optionsFunc: (() => T) & ThisType<BaseLayer>
optionsFunc: OptionsFunc<T, BaseLayer, BaseLayer>
): Layer<T> {
return createLazyProxy(() => {
const layer = {} as T & Partial<BaseLayer>;