Documented the rest of the features

Not the vue components though
This commit is contained in:
thepaperpilot 2023-04-04 00:02:23 -05:00
parent 44a5b336d6
commit 3ad0d64590
19 changed files with 565 additions and 6 deletions

View file

@ -95,7 +95,7 @@ export interface AchievementOptions {
* The properties that are added onto a processed {@link AchievementOptions} to create an {@link Achievement}.
*/
export interface BaseAchievement {
/** An auto-generated ID for identifying achievements that appear in the DOM. Will not persist between refreshes or updates. */
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** Whether or not this achievement has been earned. */
earned: Persistent<boolean>;
@ -109,7 +109,7 @@ export interface BaseAchievement {
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature with that is passively earned upon meeting certain requirements. */
/** An object that represents a feature with requirements that is passively earned upon meeting certain requirements. */
export type Achievement<T extends AchievementOptions> = Replace<
T & BaseAchievement,
{
@ -133,7 +133,7 @@ export type GenericAchievement = Replace<
>;
/**
* Lazily creates a achievement with the given options.
* Lazily creates an achievement with the given options.
* @param optionsFunc Achievement options.
*/
export function createAchievement<T extends AchievementOptions>(

View file

@ -32,26 +32,46 @@ import { computed, Ref, ref, unref } from "vue";
import { BarOptions, createBar, GenericBar } from "./bars/bar";
import { ClickableOptions } from "./clickables/clickable";
/** A symbol used to identify {@link Action} features. */
export const ActionType = Symbol("Action");
/**
* An object that configures a {@link Action}.
*/
export interface ActionOptions extends Omit<ClickableOptions, "onClick" | "onHold"> {
/** The cooldown during which the action cannot be performed again, in seconds. */
duration: Computable<DecimalSource>;
/** Whether or not the action should perform automatically when the cooldown is finished. */
autoStart?: Computable<boolean>;
/** A function that is called when the action is clicked. */
onClick: (amount: DecimalSource) => void;
/** A pass-through to the {@link Bar} used to display the cooldown progress for the action. */
barOptions?: Partial<BarOptions>;
}
/**
* The properties that are added onto a processed {@link ActionOptions} to create an {@link Action}.
*/
export interface BaseAction {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** A symbol that helps identify features of the same type. */
type: typeof ActionType;
/** Whether or not the player is holding down the action. Actions will be considered clicked as soon as the cooldown completes when being held down. */
isHolding: Ref<boolean>;
/** The current amount of progress through the cooldown. */
progress: Ref<DecimalSource>;
/** The bar used to display the current cooldown progress. */
progressBar: GenericBar;
/** Update the cooldown the specified number of seconds */
update: (diff: number) => void;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represens a feature that can be clicked upon, and then have a cooldown before they can be clicked again. */
export type Action<T extends ActionOptions> = Replace<
T & BaseAction,
{
@ -67,6 +87,7 @@ export type Action<T extends ActionOptions> = Replace<
}
>;
/** A type that matches any valid {@link Action} object. */
export type GenericAction = Replace<
Action<ActionOptions>,
{
@ -76,6 +97,10 @@ export type GenericAction = Replace<
}
>;
/**
* Lazily creates an action with the given options.
* @param optionsFunc Action options.
*/
export function createAction<T extends ActionOptions>(
optionsFunc?: OptionsFunc<T, BaseAction, GenericAction>
): Action<T> {

View file

@ -19,31 +19,56 @@ import { processComputable } from "util/computed";
import { createLazyProxy } from "util/proxies";
import { unref } from "vue";
/** A symbol used to identify {@link Bar} features. */
export const BarType = Symbol("Bar");
/**
* An object that configures a {@link Bar}.
*/
export interface BarOptions {
/** Whether this bar should be visible. */
visibility?: Computable<Visibility | boolean>;
/** The width of the bar. */
width: Computable<number>;
/** The height of the bar. */
height: Computable<number>;
/** The direction in which the bar progresses. */
direction: Computable<Direction>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to the bar's border. */
borderStyle?: Computable<StyleValue>;
/** CSS to apply to the bar's base. */
baseStyle?: Computable<StyleValue>;
/** CSS to apply to the bar's text. */
textStyle?: Computable<StyleValue>;
/** CSS to apply to the bar's fill. */
fillStyle?: Computable<StyleValue>;
/** The progress value of the bar, from 0 to 1. */
progress: Computable<DecimalSource>;
/** The display to use for this bar. */
display?: Computable<CoercableComponent>;
/** Shows a marker on the corner of the feature. */
mark?: Computable<boolean | string>;
}
/**
* The properties that are added onto a processed {@link BarOptions} to create a {@link Bar}.
*/
export interface BaseBar {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** A symbol that helps identify features of the same type. */
type: typeof BarType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that displays some sort of progress or completion or resource with a cap. */
export type Bar<T extends BarOptions> = Replace<
T & BaseBar,
{
@ -63,6 +88,7 @@ export type Bar<T extends BarOptions> = Replace<
}
>;
/** A type that matches any valid {@link Bar} object. */
export type GenericBar = Replace<
Bar<BarOptions>,
{
@ -70,6 +96,10 @@ export type GenericBar = Replace<
}
>;
/**
* Lazily creates a bar with the given options.
* @param optionsFunc Bar options.
*/
export function createBar<T extends BarOptions>(
optionsFunc: OptionsFunc<T, BaseBar, GenericBar>
): Bar<T> {

View file

@ -27,20 +27,27 @@ import type { Link } from "../links/links";
globalBus.on("setupVue", app => panZoom.install(app));
/** A symbol used to identify {@link Board} features. */
export const BoardType = Symbol("Board");
/**
* A type representing a computable value for a node on the board. Used for node types to return different values based on the given node and the state of the board.
*/
export type NodeComputable<T> = Computable<T> | ((node: BoardNode) => T);
/** Ways to display progress of an action with a duration. */
export enum ProgressDisplay {
Outline = "Outline",
Fill = "Fill"
}
/** Node shapes. */
export enum Shape {
Circle = "Circle",
Diamond = "Triangle"
}
/** An object representing a node on the board. */
export interface BoardNode {
id: number;
position: {
@ -52,48 +59,76 @@ export interface BoardNode {
pinned?: boolean;
}
/** An object representing a link between two nodes on the board. */
export interface BoardNodeLink extends Omit<Link, "startNode" | "endNode"> {
startNode: BoardNode;
endNode: BoardNode;
pulsing?: boolean;
}
/** An object representing a label for a node. */
export interface NodeLabel {
text: string;
color?: string;
pulsing?: boolean;
}
/** The persistent data for a board. */
export type BoardData = {
nodes: BoardNode[];
selectedNode: number | null;
selectedAction: string | null;
};
/**
* An object that configures a {@link NodeType}.
*/
export interface NodeTypeOptions {
/** The title to display for the node. */
title: NodeComputable<string>;
/** An optional label for the node. */
label?: NodeComputable<NodeLabel | null>;
/** The size of the node - diameter for circles, width and height for squares. */
size: NodeComputable<number>;
/** Whether the node is draggable or not. */
draggable?: NodeComputable<boolean>;
/** The shape of the node. */
shape: NodeComputable<Shape>;
/** Whether the node can accept another node being dropped upon it. */
canAccept?: boolean | Ref<boolean> | ((node: BoardNode, otherNode: BoardNode) => boolean);
/** The progress value of the node. */
progress?: NodeComputable<number>;
/** How the progress should be displayed on the node. */
progressDisplay?: NodeComputable<ProgressDisplay>;
/** The color of the progress indicator. */
progressColor?: NodeComputable<string>;
/** The fill color of the node. */
fillColor?: NodeComputable<string>;
/** The outline color of the node. */
outlineColor?: NodeComputable<string>;
/** The color of the title text. */
titleColor?: NodeComputable<string>;
/** The list of action options for the node. */
actions?: BoardNodeActionOptions[];
/** The distance between the center of the node and its actions. */
actionDistance?: NodeComputable<number>;
/** A function that is called when the node is clicked. */
onClick?: (node: BoardNode) => void;
/** A function that is called when a node is dropped onto this node. */
onDrop?: (node: BoardNode, otherNode: BoardNode) => void;
/** A function that is called for each node of this type every tick. */
update?: (node: BoardNode, diff: number) => void;
}
/**
* The properties that are added onto a processed {@link NodeTypeOptions} to create a {@link NodeType}.
*/
export interface BaseNodeType {
/** The nodes currently on the board of this type. */
nodes: Ref<BoardNode[]>;
}
/** An object that represents a type of node that can appear on a board. It will handle getting properties and callbacks for every node of that type. */
export type NodeType<T extends NodeTypeOptions> = Replace<
T & BaseNodeType,
{
@ -114,6 +149,7 @@ export type NodeType<T extends NodeTypeOptions> = Replace<
}
>;
/** A type that matches any valid {@link NodeType} object. */
export type GenericNodeType = Replace<
NodeType<NodeTypeOptions>,
{
@ -127,20 +163,34 @@ export type GenericNodeType = Replace<
}
>;
/**
* An object that configures a {@link BoardNodeAction}.
*/
export interface BoardNodeActionOptions {
/** A unique identifier for the action. */
id: string;
/** Whether this action should be visible. */
visibility?: NodeComputable<Visibility | boolean>;
/** The icon to display for the action. */
icon: NodeComputable<string>;
/** The fill color of the action. */
fillColor?: NodeComputable<string>;
/** The tooltip text to display for the action. */
tooltip: NodeComputable<string>;
/** An array of board node links associated with the action. They appear when the action is focused. */
links?: NodeComputable<BoardNodeLink[]>;
/** A function that is called when the action is clicked. */
onClick: (node: BoardNode) => boolean | undefined;
}
/**
* The properties that are added onto a processed {@link BoardNodeActionOptions} to create an {@link BoardNodeAction}.
*/
export interface BaseBoardNodeAction {
links?: Ref<BoardNodeLink[]>;
}
/** An object that represents an action that can be taken upon a node. */
export type BoardNodeAction<T extends BoardNodeActionOptions> = Replace<
T & BaseBoardNodeAction,
{
@ -152,6 +202,7 @@ export type BoardNodeAction<T extends BoardNodeActionOptions> = Replace<
}
>;
/** A type that matches any valid {@link BoardNodeAction} object. */
export type GenericBoardNodeAction = Replace<
BoardNodeAction<BoardNodeActionOptions>,
{
@ -159,29 +210,53 @@ export type GenericBoardNodeAction = Replace<
}
>;
/**
* An object that configures a {@link Board}.
*/
export interface BoardOptions {
/** Whether this board should be visible. */
visibility?: Computable<Visibility | boolean>;
/** The height of the board. Defaults to 100% */
height?: Computable<string>;
/** The width of the board. Defaults to 100% */
width?: Computable<string>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** A function that returns an array of initial board nodes, without IDs. */
startNodes: () => Omit<BoardNode, "id">[];
/** A dictionary of node types that can appear on the board. */
types: Record<string, NodeTypeOptions>;
/** The persistent state of the board. */
state?: Computable<BoardData>;
/** An array of board node links to display. */
links?: Computable<BoardNodeLink[] | null>;
}
/**
* The properties that are added onto a processed {@link BoardOptions} to create a {@link Board}.
*/
export interface BaseBoard {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** All the nodes currently on the board. */
nodes: Ref<BoardNode[]>;
/** The currently selected node, if any. */
selectedNode: Ref<BoardNode | null>;
/** The currently selected action, if any. */
selectedAction: Ref<GenericBoardNodeAction | null>;
/** The current mouse position, if over the board. */
mousePosition: Ref<{ x: number; y: number } | null>;
/** A symbol that helps identify features of the same type. */
type: typeof BoardType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that is a zoomable, pannable board with various nodes upon it. */
export type Board<T extends BoardOptions> = Replace<
T & BaseBoard,
{
@ -196,6 +271,7 @@ export type Board<T extends BoardOptions> = Replace<
}
>;
/** A type that matches any valid {@link Board} object. */
export type GenericBoard = Replace<
Board<BoardOptions>,
{
@ -205,6 +281,10 @@ export type GenericBoard = Replace<
}
>;
/**
* Lazily creates a board with the given options.
* @param optionsFunc Board options.
*/
export function createBoard<T extends BoardOptions>(
optionsFunc: OptionsFunc<T, BaseBoard, GenericBoard>
): Board<T> {
@ -368,10 +448,19 @@ export function createBoard<T extends BoardOptions>(
});
}
/**
* Gets the value of a property for a specified node.
* @param property The property to find the value of
* @param node The node to get the property of
*/
export function getNodeProperty<T>(property: NodeComputable<T>, node: BoardNode): T {
return isFunction<T, [BoardNode], Computable<T>>(property) ? property(node) : unref(property);
}
/**
* Utility to get an ID for a node that is guaranteed unique.
* @param board The board feature to generate an ID for
*/
export function getUniqueNodeID(board: GenericBoard): number {
let id = 0;
board.nodes.value.forEach(node => {

View file

@ -89,7 +89,7 @@ export interface ChallengeOptions {
* The properties that are added onto a processed {@link ChallengeOptions} to create a {@link Challenge}.
*/
export interface BaseChallenge {
/** An auto-generated ID for identifying challenges that appear in the DOM. Will not persist between refreshes or updates. */
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** The current amount of times this challenge can be completed. */
canComplete: Ref<DecimalSource>;

View file

@ -19,33 +19,56 @@ import { processComputable } from "util/computed";
import { createLazyProxy } from "util/proxies";
import { computed, unref } from "vue";
/** A symbol used to identify {@link Clickable} features. */
export const ClickableType = Symbol("Clickable");
/**
* An object that configures a {@link Clickable}.
*/
export interface ClickableOptions {
/** Whether this clickable should be visible. */
visibility?: Computable<Visibility | boolean>;
/** Whether or not the clickable may be clicked. */
canClick?: Computable<boolean>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** Shows a marker on the corner of the feature. */
mark?: Computable<boolean | string>;
/** The display to use for this clickable. */
display?: Computable<
| CoercableComponent
| {
/** A header to appear at the top of the display. */
title?: CoercableComponent;
/** The main text that appears in the display. */
description: CoercableComponent;
}
>;
/** Toggles a smaller design for the feature. */
small?: boolean;
/** A function that is called when the clickable is clicked. */
onClick?: (e?: MouseEvent | TouchEvent) => void;
/** A function that is called when the clickable is held down. */
onHold?: VoidFunction;
}
/**
* The properties that are added onto a processed {@link ClickableOptions} to create an {@link Clickable}.
*/
export interface BaseClickable {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** A symbol that helps identify features of the same type. */
type: typeof ClickableType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that can be clicked or held down. */
export type Clickable<T extends ClickableOptions> = Replace<
T & BaseClickable,
{
@ -58,6 +81,7 @@ export type Clickable<T extends ClickableOptions> = Replace<
}
>;
/** A type that matches any valid {@link Clickable} object. */
export type GenericClickable = Replace<
Clickable<ClickableOptions>,
{
@ -66,6 +90,10 @@ export type GenericClickable = Replace<
}
>;
/**
* Lazily creates a clickable with the given options.
* @param optionsFunc Clickable options.
*/
export function createClickable<T extends ClickableOptions>(
optionsFunc?: OptionsFunc<T, BaseClickable, GenericClickable>
): Clickable<T> {
@ -132,6 +160,12 @@ export function createClickable<T extends ClickableOptions>(
});
}
/**
* Utility to auto click a clickable whenever it can be.
* @param layer The layer the clickable is apart of
* @param clickable The clicker to click automatically
* @param autoActive Whether or not the clickable should currently be auto-clicking
*/
export function setupAutoClick(
layer: BaseLayer,
clickable: GenericClickable,

View file

@ -21,14 +21,22 @@ import { createLazyProxy } from "util/proxies";
import type { Ref } from "vue";
import { computed, unref } from "vue";
/** A symbol used to identify {@link Grid} features. */
export const GridType = Symbol("Grid");
/** A type representing a computable value for a cell in the grid. */
export type CellComputable<T> = Computable<T> | ((id: string | number, state: State) => T);
/** Create proxy to more easily get the properties of cells on a grid. */
function createGridProxy(grid: GenericGrid): Record<string | number, GridCell> {
return new Proxy({}, getGridHandler(grid)) as Record<string | number, GridCell>;
}
/**
* Returns traps for a proxy that will give cell proxies when accessing any numerical key.
* @param grid The grid to get the cells from.
* @see {@link createGridProxy}
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getGridHandler(grid: GenericGrid): ProxyHandler<Record<string | number, GridCell>> {
const keys = computed(() => {
@ -86,6 +94,12 @@ function getGridHandler(grid: GenericGrid): ProxyHandler<Record<string | number,
};
}
/**
* Returns traps for a proxy that will get the properties for the specified cell
* @param id The grid cell ID to get properties from.
* @see {@link getGridHandler}
* @see {@link createGridProxy}
*/
function getCellHandler(id: string): ProxyHandler<GenericGrid> {
const keys = [
"id",
@ -175,47 +189,90 @@ function getCellHandler(id: string): ProxyHandler<GenericGrid> {
};
}
/**
* Represents a cell within a grid. These properties will typically be accessed via a cell proxy that calls functions on the grid to get the properties for a specific cell.
* @see {@link createGridProxy}
*/
export interface GridCell {
/** A unique identifier for the grid cell. */
id: string;
/** Whether this cell should be visible. */
visibility: Visibility | boolean;
/** Whether this cell can be clicked. */
canClick: boolean;
/** The initial persistent state of this cell. */
startState: State;
/** The persistent state of this cell. */
state: State;
/** CSS to apply to this feature. */
style?: StyleValue;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Record<string, boolean>;
/** A header to appear at the top of the display. */
title?: CoercableComponent;
/** The main text that appears in the display. */
display: CoercableComponent;
/** A function that is called when the cell is clicked. */
onClick?: (e?: MouseEvent | TouchEvent) => void;
/** A function that is called when the cell is held down. */
onHold?: VoidFunction;
}
/**
* An object that configures a {@link Grid}.
*/
export interface GridOptions {
/** Whether this grid should be visible. */
visibility?: Computable<Visibility | boolean>;
/** The number of rows in the grid. */
rows: Computable<number>;
/** The number of columns in the grid. */
cols: Computable<number>;
/** A computable to determine the visibility of a cell. */
getVisibility?: CellComputable<Visibility | boolean>;
/** A computable to determine if a cell can be clicked. */
getCanClick?: CellComputable<boolean>;
/** A computable to get the initial persistent state of a cell. */
getStartState: Computable<State> | ((id: string | number) => State);
/** A computable to get the CSS styles for a cell. */
getStyle?: CellComputable<StyleValue>;
/** A computable to get the CSS classes for a cell. */
getClasses?: CellComputable<Record<string, boolean>>;
/** A computable to get the title component for a cell. */
getTitle?: CellComputable<CoercableComponent>;
/** A computable to get the display component for a cell. */
getDisplay: CellComputable<CoercableComponent>;
/** A function that is called when a cell is clicked. */
onClick?: (id: string | number, state: State, e?: MouseEvent | TouchEvent) => void;
/** A function that is called when a cell is held down. */
onHold?: (id: string | number, state: State) => void;
}
/**
* The properties that are added onto a processed {@link BoardOptions} to create a {@link Board}.
*/
export interface BaseGrid {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** Get the auto-generated ID for identifying a specific cell of this grid that appears in the DOM. Will not persist between refreshes or updates. */
getID: (id: string | number, state: State) => string;
/** Get the persistent state of the given cell. */
getState: (id: string | number) => State;
/** Set the persistent state of the given cell. */
setState: (id: string | number, state: State) => void;
/** A dictionary of cells within this grid. */
cells: Record<string | number, GridCell>;
/** The persistent state of this grid, which is a dictionary of cell states. */
cellState: Persistent<Record<string | number, State>>;
/** A symbol that helps identify features of the same type. */
type: typeof GridType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that is a grid of cells that all behave according to the same rules. */
export type Grid<T extends GridOptions> = Replace<
T & BaseGrid,
{
@ -232,6 +289,7 @@ export type Grid<T extends GridOptions> = Replace<
}
>;
/** A type that matches any valid {@link Grid} object. */
export type GenericGrid = Replace<
Grid<GridOptions>,
{
@ -241,6 +299,10 @@ export type GenericGrid = Replace<
}
>;
/**
* Lazily creates a grid with the given options.
* @param optionsFunc Grid options.
*/
export function createGrid<T extends GridOptions>(
optionsFunc: OptionsFunc<T, BaseGrid, GenericGrid>
): Grid<T> {

View file

@ -15,20 +15,34 @@ import { createLazyProxy } from "util/proxies";
import { shallowReactive, unref } from "vue";
import Hotkey from "components/Hotkey.vue";
/** A dictionary of all hotkeys. */
export const hotkeys: Record<string, GenericHotkey | undefined> = shallowReactive({});
/** A symbol used to identify {@link Hotkey} features. */
export const HotkeyType = Symbol("Hotkey");
/**
* An object that configures a {@link Hotkey}.
*/
export interface HotkeyOptions {
/** Whether or not this hotkey is currently enabled. */
enabled?: Computable<boolean>;
/** The key tied to this hotkey */
key: string;
/** The description of this hotkey, to display in the settings. */
description: Computable<string>;
/** What to do upon pressing the key. */
onPress: VoidFunction;
}
/**
* The properties that are added onto a processed {@link HotkeyOptions} to create an {@link Hotkey}.
*/
export interface BaseHotkey {
/** A symbol that helps identify features of the same type. */
type: typeof HotkeyType;
}
/** An object that represents a hotkey shortcut that performs an action upon a key sequence being pressed. */
export type Hotkey<T extends HotkeyOptions> = Replace<
T & BaseHotkey,
{
@ -37,6 +51,7 @@ export type Hotkey<T extends HotkeyOptions> = Replace<
}
>;
/** A type that matches any valid {@link Hotkey} object. */
export type GenericHotkey = Replace<
Hotkey<HotkeyOptions>,
{
@ -46,6 +61,10 @@ export type GenericHotkey = Replace<
const uppercaseNumbers = [")", "!", "@", "#", "$", "%", "^", "&", "*", "("];
/**
* Lazily creates a hotkey with the given options.
* @param optionsFunc Hotkey options.
*/
export function createHotkey<T extends HotkeyOptions>(
optionsFunc: OptionsFunc<T, BaseHotkey, GenericHotkey>
): Hotkey<T> {

View file

@ -19,27 +19,48 @@ import { processComputable } from "util/computed";
import { createLazyProxy } from "util/proxies";
import { unref } from "vue";
/** A symbol used to identify {@link Infobox} features. */
export const InfoboxType = Symbol("Infobox");
/**
* An object that configures an {@link Infobox}.
*/
export interface InfoboxOptions {
/** Whether this clickable should be visible. */
visibility?: Computable<Visibility | boolean>;
/** The background color of the Infobox. */
color?: Computable<string>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** CSS to apply to the title of the infobox. */
titleStyle?: Computable<StyleValue>;
/** CSS to apply to the body of the infobox. */
bodyStyle?: Computable<StyleValue>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** A header to appear at the top of the display. */
title: Computable<CoercableComponent>;
/** The main text that appears in the display. */
display: Computable<CoercableComponent>;
}
/**
* The properties that are added onto a processed {@link InfoboxOptions} to create an {@link Infobox}.
*/
export interface BaseInfobox {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** Whether or not this infobox is collapsed. */
collapsed: Persistent<boolean>;
/** A symbol that helps identify features of the same type. */
type: typeof InfoboxType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that displays information in a collapsible way. */
export type Infobox<T extends InfoboxOptions> = Replace<
T & BaseInfobox,
{
@ -54,6 +75,7 @@ export type Infobox<T extends InfoboxOptions> = Replace<
}
>;
/** A type that matches any valid {@link Infobox} object. */
export type GenericInfobox = Replace<
Infobox<InfoboxOptions>,
{
@ -61,6 +83,10 @@ export type GenericInfobox = Replace<
}
>;
/**
* Lazily creates an infobox with the given options.
* @param optionsFunc Infobox options.
*/
export function createInfobox<T extends InfoboxOptions>(
optionsFunc: OptionsFunc<T, BaseInfobox, GenericInfobox>
): Infobox<T> {

View file

@ -7,8 +7,10 @@ import { createLazyProxy } from "util/proxies";
import type { SVGAttributes } from "vue";
import LinksComponent from "./Links.vue";
/** A symbol used to identify {@link Links} features. */
export const LinksType = Symbol("Links");
/** Represents a link between two nodes. It will be displayed as an SVG line, and can take any appropriate properties for an SVG line element. */
export interface Link extends SVGAttributes {
startNode: { id: string };
endNode: { id: string };
@ -16,16 +18,25 @@ export interface Link extends SVGAttributes {
offsetEnd?: Position;
}
/** An object that configures a {@link Links}. */
export interface LinksOptions {
/** The list of links to display. */
links: Computable<Link[]>;
}
/**
* The properties that are added onto a processed {@link LinksOptions} to create an {@link Links}.
*/
export interface BaseLinks {
/** A symbol that helps identify features of the same type. */
type: typeof LinksType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a list of links between nodes, which are the elements in the DOM for any renderable feature. */
export type Links<T extends LinksOptions> = Replace<
T & BaseLinks,
{
@ -33,6 +44,7 @@ export type Links<T extends LinksOptions> = Replace<
}
>;
/** A type that matches any valid {@link Links} object. */
export type GenericLinks = Replace<
Links<LinksOptions>,
{
@ -40,6 +52,10 @@ export type GenericLinks = Replace<
}
>;
/**
* Lazily creates links with the given options.
* @param optionsFunc Links options.
*/
export function createLinks<T extends LinksOptions>(
optionsFunc: OptionsFunc<T, BaseLinks, GenericLinks>
): Links<T> {

View file

@ -8,24 +8,49 @@ import type { Computable, GetComputableType } from "util/computed";
import { createLazyProxy } from "util/proxies";
import { Ref, shallowRef, unref } from "vue";
/** A symbol used to identify {@link Particles} features. */
export const ParticlesType = Symbol("Particles");
/**
* An object that configures {@link Particles}.
*/
export interface ParticlesOptions {
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** A function that is called when the particles canvas is resized. */
onContainerResized?: (boundingRect: DOMRect) => void;
/** A function that is called whenever the particles element is reloaded during development. For restarting particle effects. */
onHotReload?: VoidFunction;
}
/**
* The properties that are added onto a processed {@link ParticlesOptions} to create an {@link Particles}.
*/
export interface BaseParticles {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** The Pixi.JS Application powering this particles canvas. */
app: Ref<null | Application>;
/**
* A function to asynchronously add an emitter to the canvas.
* The returned emitter can then be positioned as appropriate and started.
* @see {@link Particles}
*/
addEmitter: (config: EmitterConfigV3) => Promise<Emitter>;
/** A symbol that helps identify features of the same type. */
type: typeof ParticlesType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/**
* An object that represents a feature that display particle effects on the screen.
* The config should typically be gotten by designing the effect using the [online particle effect editor](https://pixijs.io/pixi-particles-editor/) and passing it into the {@link upgradeConfig} from @pixi/particle-emitter.
*/
export type Particles<T extends ParticlesOptions> = Replace<
T & BaseParticles,
{
@ -34,8 +59,13 @@ export type Particles<T extends ParticlesOptions> = Replace<
}
>;
/** A type that matches any valid {@link Particles} object. */
export type GenericParticles = Particles<ParticlesOptions>;
/**
* Lazily creates particles with the given options.
* @param optionsFunc Particles options.
*/
export function createParticles<T extends ParticlesOptions>(
optionsFunc?: OptionsFunc<T, BaseParticles, GenericParticles>
): Particles<T> {

View file

@ -76,7 +76,7 @@ export interface RepeatableOptions {
* The properties that are added onto a processed {@link RepeatableOptions} to create a {@link Repeatable}.
*/
export interface BaseRepeatable {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persistent between refreshes or updates. */
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** The current amount this repeatable has. */
amount: Persistent<DecimalSource>;

View file

@ -11,19 +11,32 @@ import { processComputable } from "util/computed";
import { createLazyProxy } from "util/proxies";
import { isRef, unref } from "vue";
/** A symbol used to identify {@link Reset} features. */
export const ResetType = Symbol("Reset");
/**
* An object that configures a {@link Clickable}.
*/
export interface ResetOptions {
/** List of things to reset. Can include objects which will be recursed over for persistent values. */
thingsToReset: Computable<Record<string, unknown>[]>;
/** A function that is called when the reset is performed. */
onReset?: VoidFunction;
}
/**
* The properties that are added onto a processed {@link ResetOptions} to create an {@link Reset}.
*/
export interface BaseReset {
/** An auto-generated ID for identifying which reset is being performed. Will not persist between refreshes or updates. */
id: string;
/** Trigger the reset. */
reset: VoidFunction;
/** A symbol that helps identify features of the same type. */
type: typeof ResetType;
}
/** An object that represents a reset mechanic, which resets progress back to its initial state. */
export type Reset<T extends ResetOptions> = Replace<
T & BaseReset,
{
@ -31,8 +44,13 @@ export type Reset<T extends ResetOptions> = Replace<
}
>;
/** A type that matches any valid {@link Reset} object. */
export type GenericReset = Reset<ResetOptions>;
/**
* Lazily creates a reset with the given options.
* @param optionsFunc Reset options.
*/
export function createReset<T extends ResetOptions>(
optionsFunc: OptionsFunc<T, BaseReset, GenericReset>
): Reset<T> {
@ -66,6 +84,11 @@ export function createReset<T extends ResetOptions>(
}
const listeners: Record<string, Unsubscribe | undefined> = {};
/**
* Track the time since the specified reset last occured.
* @param layer The layer the reset is attached to
* @param reset The reset mechanic to track the time since
*/
export function trackResetTime(layer: BaseLayer, reset: GenericReset): Persistent<Decimal> {
const resetTime = persistent<Decimal>(new Decimal(0));
globalBus.on("addLayer", layerBeingAdded => {

View file

@ -8,12 +8,23 @@ import { loadingSave } from "util/save";
import type { ComputedRef, Ref } from "vue";
import { computed, isRef, ref, unref, watch } from "vue";
/** An object that represents a named and quantifiable resource in the game. */
export interface Resource<T = DecimalSource> extends Ref<T> {
/** The name of this resource. */
displayName: string;
/** When displaying the value of this resource, how many significant digits to display. */
precision: number;
/** Whether or not to display very small values using scientific notation, or rounding to 0. */
small?: boolean;
}
/**
* Creates a resource.
* @param defaultValue The initial value of the resource
* @param displayName The human readable name of this resource
* @param precision The number of significant digits to display by default
* @param small Whether or not to display very small values or round to 0, by default
*/
export function createResource<T extends State>(
defaultValue: T,
displayName?: string,
@ -49,6 +60,7 @@ export function createResource<T extends State>(
return resource as Resource<T>;
}
/** Returns a reference to the highest amount of the resource ever owned, which is updated automatically. */
export function trackBest(resource: Resource): Ref<DecimalSource> {
const best = persistent(resource.value);
watch(resource, amount => {
@ -62,6 +74,7 @@ export function trackBest(resource: Resource): Ref<DecimalSource> {
return best;
}
/** Returns a reference to the total amount of the resource gained, updated automatically. "Refunds" count as gain. */
export function trackTotal(resource: Resource): Ref<DecimalSource> {
const total = persistent(resource.value);
watch(resource, (amount, prevAmount) => {
@ -77,6 +90,7 @@ export function trackTotal(resource: Resource): Ref<DecimalSource> {
const tetra8 = new Decimal("10^^8");
const e100 = new Decimal("1e100");
/** Returns a reference to the amount of resource being gained in terms of orders of magnitude per second, calcualted over the last tick. Useful for situations where the gain rate is increasing very rapidly. */
export function trackOOMPS(
resource: Resource,
pointGain?: ComputedRef<DecimalSource>
@ -135,6 +149,7 @@ export function trackOOMPS(
return oompsString;
}
/** Utility for displaying a resource with the correct precision. */
export function displayResource(resource: Resource, overrideAmount?: DecimalSource): string {
const amount = overrideAmount ?? resource.value;
if (Decimal.eq(resource.precision, 0)) {
@ -143,6 +158,7 @@ export function displayResource(resource: Resource, overrideAmount?: DecimalSour
return format(amount, resource.precision, resource.small);
}
/** Utility for unwrapping a resource that may or may not be inside a ref. */
export function unwrapResource(resource: ProcessedComputable<Resource>): Resource {
if ("displayName" in resource) {
return resource;

View file

@ -10,21 +10,39 @@ import TabComponent from "features/tabs/Tab.vue";
import type { Computable, GetComputableType } from "util/computed";
import { createLazyProxy } from "util/proxies";
/** A symbol used to identify {@link Tab} features. */
export const TabType = Symbol("Tab");
/**
* An object that configures a {@link Tab}.
*/
export interface TabOptions {
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** The display to use for this tab. */
display: Computable<CoercableComponent>;
}
/**
* The properties that are added onto a processed {@link TabOptions} to create an {@link Tab}.
*/
export interface BaseTab {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** A symbol that helps identify features of the same type. */
type: typeof TabType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/**
* An object representing a tab of content in a tabbed interface.
* @see {@link TabFamily}
*/
export type Tab<T extends TabOptions> = Replace<
T & BaseTab,
{
@ -34,8 +52,13 @@ export type Tab<T extends TabOptions> = Replace<
}
>;
/** A type that matches any valid {@link Tab} object. */
export type GenericTab = Tab<TabOptions>;
/**
* Lazily creates a tab with the given options.
* @param optionsFunc Tab options.
*/
export function createTab<T extends TabOptions>(
optionsFunc: OptionsFunc<T, BaseTab, GenericTab>
): Tab<T> {

View file

@ -29,23 +29,43 @@ import type { Ref } from "vue";
import { computed, unref } from "vue";
import type { GenericTab } from "./tab";
/** A symbol used to identify {@link TabButton} features. */
export const TabButtonType = Symbol("TabButton");
/** A symbol used to identify {@link TabFamily} features. */
export const TabFamilyType = Symbol("TabFamily");
/**
* An object that configures a {@link TabButton}.
*/
export interface TabButtonOptions {
/** Whether this tab button should be visible. */
visibility?: Computable<Visibility | boolean>;
/** The tab to display when this button is clicked. */
tab: Computable<GenericTab | CoercableComponent>;
/** The label on this button. */
display: Computable<CoercableComponent>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** The color of the glow effect to display when this button is active. */
glowColor?: Computable<string>;
}
/**
* The properties that are added onto a processed {@link TabButtonOptions} to create an {@link TabButton}.
*/
export interface BaseTabButton {
/** A symbol that helps identify features of the same type. */
type: typeof TabButtonType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
}
/**
* An object that represents a button that can be clicked to change tabs in a tabbed interface.
* @see {@link TabFamily}
*/
export type TabButton<T extends TabButtonOptions> = Replace<
T & BaseTabButton,
{
@ -58,6 +78,7 @@ export type TabButton<T extends TabButtonOptions> = Replace<
}
>;
/** A type that matches any valid {@link TabButton} object. */
export type GenericTabButton = Replace<
TabButton<TabButtonOptions>,
{
@ -65,24 +86,46 @@ export type GenericTabButton = Replace<
}
>;
/**
* An object that configures a {@link TabFamily}.
*/
export interface TabFamilyOptions {
/** Whether this tab button should be visible. */
visibility?: Computable<Visibility | boolean>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** A dictionary of CSS classes to apply to the list of buttons for changing tabs. */
buttonContainerClasses?: Computable<Record<string, boolean>>;
/** CSS to apply to the list of buttons for changing tabs. */
buttonContainerStyle?: Computable<StyleValue>;
}
/**
* The properties that are added onto a processed {@link TabFamilyOptions} to create an {@link TabFamily}.
*/
export interface BaseTabFamily {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** All the tabs within this family. */
tabs: Record<string, TabButtonOptions>;
/** The currently active tab, if any. */
activeTab: Ref<GenericTab | CoercableComponent | null>;
/** The name of the tab that is currently active. */
selected: Persistent<string>;
/** A symbol that helps identify features of the same type. */
type: typeof TabFamilyType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/**
* An object that represents a tabbed interface.
* @see {@link TabFamily}
*/
export type TabFamily<T extends TabFamilyOptions> = Replace<
T & BaseTabFamily,
{
@ -91,6 +134,7 @@ export type TabFamily<T extends TabFamilyOptions> = Replace<
}
>;
/** A type that matches any valid {@link TabFamily} object. */
export type GenericTabFamily = Replace<
TabFamily<TabFamilyOptions>,
{
@ -98,6 +142,10 @@ export type GenericTabFamily = Replace<
}
>;
/**
* Lazily creates a tab family with the given options.
* @param optionsFunc Tab family options.
*/
export function createTabFamily<T extends TabFamilyOptions>(
tabs: Record<string, () => TabButtonOptions>,
optionsFunc?: OptionsFunc<T, BaseTabFamily, GenericTabFamily>

View file

@ -21,20 +21,34 @@ declare module "@vue/runtime-dom" {
}
}
/**
* An object that configures a {@link Tooltip}.
*/
export interface TooltipOptions {
/** Whether or not this tooltip can be pinned, meaning it'll stay visible even when not hovered. */
pinnable?: boolean;
/** The text to display inside the tooltip. */
display: Computable<CoercableComponent>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** The direction in which to display the tooltip */
direction?: Computable<Direction>;
/** The x offset of the tooltip, in px. */
xoffset?: Computable<string>;
/** The y offset of the tooltip, in px. */
yoffset?: Computable<string>;
}
/**
* The properties that are added onto a processed {@link TooltipOptions} to create an {@link Tooltip}.
*/
export interface BaseTooltip {
pinned?: Ref<boolean>;
}
/** An object that represents a tooltip that appears when hovering over an element. */
export type Tooltip<T extends TooltipOptions> = Replace<
T & BaseTooltip,
{
@ -49,6 +63,7 @@ export type Tooltip<T extends TooltipOptions> = Replace<
}
>;
/** A type that matches any valid {@link Tooltip} object. */
export type GenericTooltip = Replace<
Tooltip<TooltipOptions>,
{
@ -58,6 +73,11 @@ export type GenericTooltip = Replace<
}
>;
/**
* Creates a tooltip on the given element with the given options.
* @param element The renderable feature to display the tooltip on.
* @param optionsFunc Clickable options.
*/
export function addTooltip<T extends TooltipOptions>(
element: VueFeature,
options: T & ThisType<Tooltip<T>> & Partial<BaseTooltip>

View file

@ -25,30 +25,54 @@ import { createLazyProxy } from "util/proxies";
import type { Ref } from "vue";
import { computed, ref, shallowRef, unref } from "vue";
/** A symbol used to identify {@link TreeNode} features. */
export const TreeNodeType = Symbol("TreeNode");
/** A symbol used to identify {@link Tree} features. */
export const TreeType = Symbol("Tree");
/**
* An object that configures a {@link TreeNode}.
*/
export interface TreeNodeOptions {
/** Whether this tree node should be visible. */
visibility?: Computable<Visibility | boolean>;
/** Whether or not this tree node can be clicked. */
canClick?: Computable<boolean>;
/** The background color for this node. */
color?: Computable<string>;
/** The label to display on this tree node. */
display?: Computable<CoercableComponent>;
/** The color of the glow effect shown to notify the user there's something to do with this node. */
glowColor?: Computable<string>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** Shows a marker on the corner of the feature. */
mark?: Computable<boolean | string>;
/** A reset object attached to this node, used for propagating resets through the tree. */
reset?: GenericReset;
/** A function that is called when the tree node is clicked. */
onClick?: (e?: MouseEvent | TouchEvent) => void;
/** A function that is called when the tree node is held down. */
onHold?: VoidFunction;
}
/**
* The properties that are added onto a processed {@link TreeNodeOptions} to create an {@link TreeNode}.
*/
export interface BaseTreeNode {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** A symbol that helps identify features of the same type. */
type: typeof TreeNodeType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a node on a tree. */
export type TreeNode<T extends TreeNodeOptions> = Replace<
T & BaseTreeNode,
{
@ -63,6 +87,7 @@ export type TreeNode<T extends TreeNodeOptions> = Replace<
}
>;
/** A type that matches any valid {@link TreeNode} object. */
export type GenericTreeNode = Replace<
TreeNode<TreeNodeOptions>,
{
@ -71,6 +96,10 @@ export type GenericTreeNode = Replace<
}
>;
/**
* Lazily creates a tree node with the given options.
* @param optionsFunc Tree Node options.
*/
export function createTreeNode<T extends TreeNodeOptions>(
optionsFunc?: OptionsFunc<T, BaseTreeNode, GenericTreeNode>
): TreeNode<T> {
@ -141,32 +170,52 @@ export function createTreeNode<T extends TreeNodeOptions>(
});
}
/** Represents a branch between two nodes in a tree. */
export interface TreeBranch extends Omit<Link, "startNode" | "endNode"> {
startNode: GenericTreeNode;
endNode: GenericTreeNode;
}
/**
* An object that configures a {@link Tree}.
*/
export interface TreeOptions {
/** Whether this clickable should be visible. */
visibility?: Computable<Visibility | boolean>;
/** The nodes within the tree, in a 2D array. */
nodes: Computable<GenericTreeNode[][]>;
/** Nodes to show on the left side of the tree. */
leftSideNodes?: Computable<GenericTreeNode[]>;
/** Nodes to show on the right side of the tree. */
rightSideNodes?: Computable<GenericTreeNode[]>;
/** The branches between nodes within this tree. */
branches?: Computable<TreeBranch[]>;
/** How to propagate resets through the tree. */
resetPropagation?: ResetPropagation;
/** A function that is called when a node within the tree is reset. */
onReset?: (node: GenericTreeNode) => void;
}
export interface BaseTree {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** The link objects for each of the branches of the tree. */
links: Ref<Link[]>;
/** Cause a reset on this node and propagate it through the tree according to {@link resetPropagation}. */
reset: (node: GenericTreeNode) => void;
/** A flag that is true while the reset is still propagating through the tree. */
isResetting: Ref<boolean>;
/** A reference to the node that caused the currently propagating reset. */
resettingNode: Ref<GenericTreeNode | null>;
/** A symbol that helps identify features of the same type. */
type: typeof TreeType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that is a tree of nodes with branches between them. Contains support for reset mechanics that can propagate through the tree. */
export type Tree<T extends TreeOptions> = Replace<
T & BaseTree,
{
@ -178,6 +227,7 @@ export type Tree<T extends TreeOptions> = Replace<
}
>;
/** A type that matches any valid {@link Tree} object. */
export type GenericTree = Replace<
Tree<TreeOptions>,
{
@ -185,6 +235,10 @@ export type GenericTree = Replace<
}
>;
/**
* Lazily creates a tree with the given options.
* @param optionsFunc Tree options.
*/
export function createTree<T extends TreeOptions>(
optionsFunc: OptionsFunc<T, BaseTree, GenericTree>
): Tree<T> {
@ -227,10 +281,12 @@ export function createTree<T extends TreeOptions>(
});
}
/** A function that is used to propagate resets through a tree. */
export type ResetPropagation = {
(tree: GenericTree, resettingNode: GenericTreeNode): void;
};
/** Propagate resets down the tree by resetting every node in a lower row. */
export const defaultResetPropagation = function (
tree: GenericTree,
resettingNode: GenericTreeNode
@ -242,6 +298,7 @@ export const defaultResetPropagation = function (
}
};
/** Propagate resets down the tree by resetting every node in a lower row. */
export const invertedResetPropagation = function (
tree: GenericTree,
resettingNode: GenericTreeNode
@ -253,6 +310,7 @@ export const invertedResetPropagation = function (
}
};
/** Propagate resets down the branches of the tree. */
export const branchedResetPropagation = function (
tree: GenericTree,
resettingNode: GenericTreeNode
@ -288,6 +346,10 @@ export const branchedResetPropagation = function (
}
};
/**
* Utility for creating a tooltip for a tree node that displays a resource-based unlock requirement, and after unlock shows the amount of another resource.
* It sounds oddly specific, but comes up a lot.
*/
export function createResourceTooltip(
resource: Resource,
requiredResource: Resource | null = null,

View file

@ -36,35 +36,60 @@ import { createLazyProxy } from "util/proxies";
import type { Ref } from "vue";
import { computed, unref } from "vue";
/** A symbol used to identify {@link Upgrade} features. */
export const UpgradeType = Symbol("Upgrade");
/**
* An object that configures a {@link Upgrade}.
*/
export interface UpgradeOptions {
/** Whether this clickable should be visible. */
visibility?: Computable<Visibility | boolean>;
/** Dictionary of CSS classes to apply to this feature. */
classes?: Computable<Record<string, boolean>>;
/** CSS to apply to this feature. */
style?: Computable<StyleValue>;
/** Shows a marker on the corner of the feature. */
mark?: Computable<boolean | string>;
/** The display to use for this clickable. */
display?: Computable<
| CoercableComponent
| {
/** A header to appear at the top of the display. */
title?: CoercableComponent;
/** The main text that appears in the display. */
description: CoercableComponent;
/** A description of the current effect of the achievement. Useful when the effect changes dynamically. */
effectDisplay?: CoercableComponent;
}
>;
/** The requirements to purchase this upgrade. */
requirements: Requirements;
mark?: Computable<boolean | string>;
/** A function that is called when the upgrade is purchased. */
onPurchase?: VoidFunction;
}
/**
* The properties that are added onto a processed {@link UpgradeOptions} to create an {@link Upgrade}.
*/
export interface BaseUpgrade {
/** An auto-generated ID for identifying features that appear in the DOM. Will not persist between refreshes or updates. */
id: string;
/** Whether or not this upgrade has been purchased. */
bought: Persistent<boolean>;
/** Whether or not the upgrade can currently be purchased. */
canPurchase: Ref<boolean>;
/** Purchase the upgrade */
purchase: VoidFunction;
/** A symbol that helps identify features of the same type. */
type: typeof UpgradeType;
/** The Vue component used to render this feature. */
[Component]: GenericComponent;
/** A function to gather the props the vue component requires for this feature. */
[GatherProps]: () => Record<string, unknown>;
}
/** An object that represents a feature that can be purchased a single time. */
export type Upgrade<T extends UpgradeOptions> = Replace<
T & BaseUpgrade,
{
@ -77,6 +102,7 @@ export type Upgrade<T extends UpgradeOptions> = Replace<
}
>;
/** A type that matches any valid {@link Upgrade} object. */
export type GenericUpgrade = Replace<
Upgrade<UpgradeOptions>,
{
@ -84,6 +110,10 @@ export type GenericUpgrade = Replace<
}
>;
/**
* Lazily creates an upgrade with the given options.
* @param optionsFunc Upgrade options.
*/
export function createUpgrade<T extends UpgradeOptions>(
optionsFunc: OptionsFunc<T, BaseUpgrade, GenericUpgrade>
): Upgrade<T> {
@ -151,6 +181,12 @@ export function createUpgrade<T extends UpgradeOptions>(
});
}
/**
* Utility to auto purchase a list of upgrades whenever they're affordable.
* @param layer The layer the upgrades are apart of
* @param autoActive Whether or not the upgrades should currently be auto-purchasing
* @param upgrades The specific upgrades to upgrade. If unspecified, uses all upgrades on the layer.
*/
export function setupAutoPurchase(
layer: GenericLayer,
autoActive: Computable<boolean>,