From 8fff8f283545148a8fc93e8f4c67ee1032a2dd22 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 17 Aug 2021 08:06:30 -0500 Subject: [PATCH 01/49] setup basic mod info --- saves/safff.txt | 1 - src/components/system/Tabs.vue | 8 +- src/data/layers/aca/a.ts | 103 -- src/data/layers/aca/c.ts | 573 -------- src/data/layers/aca/f.ts | 151 -- src/data/layers/demo-infinity.ts | 354 ----- src/data/layers/demo.ts | 2301 ------------------------------ src/data/layers/main.ts | 11 + src/data/mod.ts | 156 +- src/data/modInfo.json | 8 +- 10 files changed, 25 insertions(+), 3641 deletions(-) delete mode 100644 saves/safff.txt delete mode 100644 src/data/layers/aca/a.ts delete mode 100644 src/data/layers/aca/c.ts delete mode 100644 src/data/layers/aca/f.ts delete mode 100644 src/data/layers/demo-infinity.ts delete mode 100644 src/data/layers/demo.ts create mode 100644 src/data/layers/main.ts diff --git a/saves/safff.txt b/saves/safff.txt deleted file mode 100644 index 7a1451d..0000000 --- a/saves/safff.txt +++ /dev/null @@ -1 +0,0 @@ -eyJpZCI6InRtdC14LTEwNSIsIm5hbWUiOiJEZWZhdWx0IFNhZmZmZiAtIHNvbWV0aGluZyBlbHNlIiwidGFicyI6WyJtYWluIiwiYyJdLCJ0aW1lIjoxNjI0MjQ1MjYxMDg3LCJhdXRvc2F2ZSI6dHJ1ZSwib2ZmbGluZVByb2QiOnRydWUsInRpbWVQbGF5ZWQiOiIzNDQ4LjYxNTc4MTcwOTAxIiwia2VlcEdvaW5nIjpmYWxzZSwibGFzdFRlblRpY2tzIjpbMC4wNTEsMC4wNSwwLjA0OSwwLjA1LDAuMDUsMC4wNTEsMC4wNDksMC4wNSwwLjA1LDAuMDUxXSwic2hvd1RQUyI6dHJ1ZSwibXNEaXNwbGF5IjoiYWxsIiwiaGlkZUNoYWxsZW5nZXMiOmZhbHNlLCJ0aGVtZSI6InBhcGVyIiwic3VidGFicyI6e30sIm1pbmltaXplZCI6e30sIm1vZElEIjoidG10LXgiLCJtb2RWZXJzaW9uIjoiMC4wIiwicG9pbnRzIjoiMzMwMC4zNzc3NzM4NTkwNTUiLCJtYWluIjp7InVwZ3JhZGVzIjpbXSwiYWNoaWV2ZW1lbnRzIjpbXSwibWlsZXN0b25lcyI6W10sImluZm9ib3hlcyI6e319LCJmIjp7InVwZ3JhZGVzIjpbXSwiYWNoaWV2ZW1lbnRzIjpbXSwibWlsZXN0b25lcyI6W10sImluZm9ib3hlcyI6e30sImNsaWNrYWJsZXMiOnsiMTEiOiJTdGFydCJ9LCJ1bmxvY2tlZCI6ZmFsc2UsInBvaW50cyI6IjAiLCJib29wIjpmYWxzZX0sImMiOnsidXBncmFkZXMiOlsiMTEiXSwiYWNoaWV2ZW1lbnRzIjpbXSwibWlsZXN0b25lcyI6W10sImluZm9ib3hlcyI6e30sImJ1eWFibGVzIjp7IjExIjoiMCJ9LCJjaGFsbGVuZ2VzIjp7IjExIjoiMCJ9LCJ1bmxvY2tlZCI6dHJ1ZSwicG9pbnRzIjoiMCIsImJlc3QiOiIxIiwidG90YWwiOiIwIiwiYmVlcCI6ZmFsc2UsInRoaW5neSI6InBvaW50eSIsIm90aGVyVGhpbmd5IjoxMCwic3BlbnRPbkJ1eWFibGVzIjoiMCJ9LCJhIjp7InVwZ3JhZGVzIjpbXSwiYWNoaWV2ZW1lbnRzIjpbIjExIl0sIm1pbGVzdG9uZXMiOltdLCJpbmZvYm94ZXMiOnt9LCJ1bmxvY2tlZCI6dHJ1ZSwicG9pbnRzIjoiMCJ9LCJnIjp7InVwZ3JhZGVzIjpbXSwiYWNoaWV2ZW1lbnRzIjpbXSwibWlsZXN0b25lcyI6W10sImluZm9ib3hlcyI6e319LCJoIjp7InVwZ3JhZGVzIjpbXSwiYWNoaWV2ZW1lbnRzIjpbXSwibWlsZXN0b25lcyI6W10sImluZm9ib3hlcyI6e319LCJzcG9vayI6eyJ1cGdyYWRlcyI6W10sImFjaGlldmVtZW50cyI6W10sIm1pbGVzdG9uZXMiOltdLCJpbmZvYm94ZXMiOnt9fSwib29tcHNNYWciOjAsImxhc3RQb2ludHMiOiIzMzAwLjM3Nzc3Mzg1OTA1NSJ9 \ No newline at end of file diff --git a/src/components/system/Tabs.vue b/src/components/system/Tabs.vue index 94fc880..ec69f0e 100644 --- a/src/components/system/Tabs.vue +++ b/src/components/system/Tabs.vue @@ -14,7 +14,7 @@ :layer="tab" :index="index" v-else-if="tab in components" - :minimizable="true" + :minimizable="minimizable[tab]" :tab="() => $refs[`tab-${index}`]" /> @@ -47,6 +47,12 @@ export default defineComponent({ }, {} ); + }, + minimizable() { + return Object.keys(layers).reduce((acc: Record, curr) => { + acc[curr] = layers[curr].minimizable !== false; + return acc; + }, {}); } } }); diff --git a/src/data/layers/aca/a.ts b/src/data/layers/aca/a.ts deleted file mode 100644 index a18fdab..0000000 --- a/src/data/layers/aca/a.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* eslint-disable */ -import player from "@/game/player"; -import { GridCell } from "@/typings/features/grid"; -import { RawLayer } from "@/typings/layer"; -import Decimal from "@/util/bignum"; - -export default { - id: "a", - startData() { - return { - unlocked: true, - points: new Decimal(0) - }; - }, - color: "yellow", - modal: true, - name: "Achievements", - resource: "achievement power", - row: "side", - tooltip() { - // Optional, tooltip displays when the layer is locked - return "Achievements"; - }, - achievementPopups: true, - achievements: { - data: { - 11: { - image: "https://unsoftcapped2.github.io/The-Modding-Tree-2/discord.png", - name: "Get me!", - done() { - return true; - }, // This one is a freebie - goalTooltip: "How did this happen?", // Shows when achievement is not completed - doneTooltip: "You did it!" // Showed when the achievement is completed - }, - 12: { - name: "Impossible!", - done() { - return false; - }, - goalTooltip: "Mwahahaha!", // Shows when achievement is not completed - doneTooltip: "HOW????", // Showed when the achievement is completed - style: { color: "#04e050" } - }, - 13: { - name: "EIEIO", - done() { - return player.layers.f.points.gte(1); - }, - tooltip: - "Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).", // Showed when the achievement is completed - onComplete() { - console.log("Bork bork bork!"); - } - } - } - }, - midsection: "", - grids: { - data: { - test: { - maxRows: 3, - rows: 2, - cols: 2, - getStartData(cell: string) { - return cell; - }, - getUnlocked() { - // Default - return true; - }, - getCanClick() { - return player.points.eq(10); - }, - getStyle(cell) { - return { backgroundColor: "#" + ((Number((this[cell] as GridCell).data) * 1234) % 999999) }; - }, - click(cell) { - // Don't forget onHold - (this[cell] as GridCell).data = ((this[cell] as GridCell).data as number) + 1; - }, - getTitle(cell) { - let direction; - if (cell === "101") { - direction = "top"; - } else if (cell === "102") { - direction = "bottom"; - } else if (cell === "201") { - direction = "left"; - } else if (cell === "202") { - direction = "right"; - } - return ` -

Gridable #${cell}

-
`; - }, - getDisplay(cell) { - return (this[cell] as GridCell).data; - } - } - } - } -} as RawLayer; diff --git a/src/data/layers/aca/c.ts b/src/data/layers/aca/c.ts deleted file mode 100644 index b291172..0000000 --- a/src/data/layers/aca/c.ts +++ /dev/null @@ -1,573 +0,0 @@ -/* eslint-disable */ -import { Direction } from "@/game/enums"; -import { layers } from "@/game/layers"; -import player from "@/game/player"; -import { DecimalSource } from "@/lib/break_eternity"; -import { RawLayer } from "@/typings/layer"; -import Decimal, { format, formatWhole } from "@/util/bignum"; -import { - buyableEffect, - challengeCompletions, - getBuyableAmount, - hasMilestone, - hasUpgrade, - setBuyableAmount, - upgradeEffect -} from "@/util/features"; -import { resetLayer, resetLayerData } from "@/util/layers"; - -export default { - id: "c", // This is assigned automatically, both to the layer and all upgrades, etc. Shown here so you know about it - name: "Candies", // This is optional, only used in a few places, If absent it just uses the layer id. - symbol: "C", // This appears on the layer's node. Default is the id with the first letter capitalized - position: 0, // Horizontal position within a row. By default it uses the layer id and sorts in alphabetical order - startData() { - return { - unlocked: true, - points: new Decimal(0), - best: new Decimal(0), - total: new Decimal(0), - beep: false, - thingy: "pointy", - otherThingy: 10, - spentOnBuyables: new Decimal(0) - }; - }, - minWidth: 800, - color: "#4BDC13", - requires: new Decimal(10), // Can be a function that takes requirement increases into account - resource: "lollipops", // Name of prestige currency - baseResource: "points", // Name of resource prestige is based on - baseAmount() { - return player.points; - }, // Get the current amount of baseResource - type: "normal", // normal: cost to gain currency depends on amount gained. static: cost depends on how much you already have - exponent: 0.5, // Prestige currency exponent - base: 5, // Only needed for static layers, base of the formula (b^(x^exp)) - roundUpCost: false, // True if the cost needs to be rounded up (use when baseResource is static?) - - // For normal layers, gain beyond [softcap] points is put to the [softcapPower]th power - softcap: new Decimal(1e100), - softcapPower: new Decimal(0.5), - canBuyMax() {}, // Only needed for static layers with buy max - gainMult() { - // Calculate the multiplier for main currency from bonuses - let mult = new Decimal(1); - /* - if (hasUpgrade(this.layer, 166)) mult = mult.times(2); // These upgrades don't exist - if (hasUpgrade(this.layer, 120)) - mult = mult.times(upgradeEffect(this.layer, 120) as DecimalSource); - */ - return mult; - }, - gainExp() { - // Calculate the exponent on main currency from bonuses - return new Decimal(1); - }, - row: 0, // Row the layer is in on the tree (0 is the first row) - effect() { - return { - // Formulas for any boosts inherent to resources in the layer. Can return a single value instead of an object if there is just one effect - waffleBoost: Decimal.pow(player.layers[this.layer].points, 0.2), - icecreamCap: player.layers[this.layer].points.times(10) - }; - }, - effectDisplay() { - // Optional text to describe the effects - const eff = this.effect as { waffleBoost: Decimal; icecreamCap: Decimal }; - const waffleBoost = eff.waffleBoost.times( - (buyableEffect(this.layer, 11) as { first: Decimal, second: Decimal }).first - ); - return ( - "which are boosting waffles by " + - format(waffleBoost) + - " and increasing the Ice Cream cap by " + - format(eff.icecreamCap) - ); - }, - infoboxes: { - data: { - coolInfo: { - title: "Lore", - titleStyle: { color: "#FE0000" }, - body: "DEEP LORE!", - bodyStyle: { "background-color": "#0000EE" } - } - } - }, - milestones: { - data: { - 0: { - requirementDisplay: "3 Lollipops", - done() { - return (player.layers[this.layer].best as Decimal).gte(3); - }, // Used to determine when to give the milestone - effectDisplay: "Unlock the next milestone" - }, - 1: { - requirementDisplay: "4 Lollipops", - unlocked() { - return hasMilestone(this.layer, 0); - }, - done() { - return (player.layers[this.layer].best as Decimal).gte(4); - }, - effectDisplay: "You can toggle beep and boop (which do nothing)", - optionsDisplay: ` -
- - -
- `, - style() { - if (hasMilestone(this.layer, this.id)) - return { - backgroundColor: "#1111DD" - }; - } - } - } - }, - challenges: { - data: { - 11: { - name: "Fun", - completionLimit: 3, - challengeDescription() { - return ( - "Makes the game 0% harder
" + - challengeCompletions(this.layer, this.id) + - "/" + - this.completionLimit + - " completions" - ); - }, - unlocked() { - return (player.layers[this.layer].best as Decimal).gt(0); - }, - goalDescription: "Have 20 points I guess", - canComplete() { - return player.points.gte(20); - }, - effect() { - const ret = player.layers[this.layer].points.add(1).tetrate(0.02); - return ret; - }, - rewardDisplay() { - return format(this.effect as Decimal) + "x"; - }, - countsAs: [12, 21], // Use this for if a challenge includes the effects of other challenges. Being in this challenge "counts as" being in these. - rewardDescription: "Says hi", - onComplete() { - console.log("hiii"); - }, // Called when you successfully complete the challenge - onEnter() { - console.log("So challenging"); - }, - onExit() { - console.log("Sweet freedom!"); - } - } - } - }, - upgrades: { - data: { - 11: { - title: "Generator of Genericness", - description: "Gain 1 Point every second.", - cost: new Decimal(1), - unlocked() { - return player.layers[this.layer].unlocked; - } // The upgrade is only visible when this is true - }, - 12: { - description: - "Point generation is faster based on your unspent Lollipops.", - cost: new Decimal(1), - unlocked() { - return hasUpgrade(this.layer, 11); - }, - effect() { - // Calculate bonuses from the upgrade. Can return a single value or an object with multiple values - let ret = player.layers[this.layer].points - .add(1) - .pow( - player.layers[this.layer].upgrades!.includes(24) - ? 1.1 - : player.layers[this.layer].upgrades!.includes(14) - ? 0.75 - : 0.5 - ); - if (ret.gte("1e20000000")) ret = ret.sqrt().times("1e10000000"); - return ret; - }, - effectDisplay() { - return format(this.effect as Decimal) + "x"; - } // Add formatting to the effect - }, - 13: { - unlocked() { - return hasUpgrade(this.layer, 12); - }, - onPurchase() { - // This function triggers when the upgrade is purchased - player.layers[this.layer].unlockOrder = 0; - }, - style() { - if (hasUpgrade(this.layer, this.id)) - return { - "background-color": "#1111dd" - }; - else if (!this.canAfford) { - return { - "background-color": "#dd1111" - }; - } // Otherwise use the default - }, - canAfford() { - return player.points.lte(7); - }, - pay() { - player.points = player.points.add(7); - }, - fullDisplay: - "Only buyable with less than 7 points, and gives you 7 more. Unlocks a secret subtab." - }, - 22: { - title: "This upgrade doesn't exist", - description: "Or does it?.", - currencyLocation() { - return player.layers[this.layer].buyables; - }, // The object in player data that the currency is contained in - currencyDisplayName: "exhancers", // Use if using a nonstandard currency - currencyInternalName: 11, // Use if using a nonstandard currency - - cost: new Decimal(3), - unlocked() { - return player.layers[this.layer].unlocked; - } // The upgrade is only visible when this is true - } - } - }, - buyables: { - showBRespecButton: true, - respec() { - // Optional, reset things and give back your currency. Having this function makes a respec button appear - player.layers[this.layer].points = player.layers[this.layer].points.add( - player.layers[this.layer].spentOnBuyables as Decimal - ); // A built-in thing to keep track of this but only keeps a single value - this.reset(); - resetLayer(this.layer, true); // Force a reset - }, - respecButtonDisplay: "Respec Thingies", // Text on Respec button, optional - respecWarningDisplay: - "Are you sure? Respeccing these doesn't accomplish much.", - data: { - 11: { - title: "Exhancers", // Optional, displayed at the top in a larger font - cost() { - // cost for buying xth buyable, can be an object if there are multiple currencies - let x = this.amount; - if (x.gte(25)) x = x.pow(2).div(25); - const cost = Decimal.pow(2, x.pow(1.5)); - return cost.floor(); - }, - effect() { - // Effects of owning x of the items, x is a decimal - const x = this.amount; - const eff = {} as { first?: Decimal; second?: Decimal }; - if (x.gte(0)) eff.first = Decimal.pow(25, x.pow(1.1)); - else eff.first = Decimal.pow(1 / 25, x.times(-1).pow(1.1)); - - if (x.gte(0)) eff.second = x.pow(0.8); - else - eff.second = x - .times(-1) - .pow(0.8) - .times(-1); - return eff; - }, - display() { - // Everything else displayed in the buyable button after the title - return ( - "Cost: " + - format(this.cost!) + - " lollipops\n\ - Amount: " + - player.layers[this.layer].buyables![this.id] + - "/4\n\ - Adds + " + - format((this.effect as { first: Decimal; second: Decimal }).first) + - " things and multiplies stuff by " + - format((this.effect as { first: Decimal; second: Decimal }).second) - ); - }, - unlocked() { - return player.layers[this.layer].unlocked; - }, - canAfford() { - return player.layers[this.layer].points.gte(this.cost!); - }, - buy() { - const cost = this.cost!; - player.layers[this.layer].points = player.layers[ - this.layer - ].points.sub(cost); - player.layers[this.layer].buyables![this.id] = player.layers[ - this.layer - ].buyables![this.id].add(1); - player.layers[this.layer].spentOnBuyables = (player.layers[ - this.layer - ].spentOnBuyables as Decimal).add(cost); // This is a built-in system that you can use for respeccing but it only works with a single Decimal value - }, - buyMax() {}, // You'll have to handle this yourself if you want - style: { height: "222px" }, - purchaseLimit: new Decimal(4), - sellOne() { - const amount = getBuyableAmount(this.layer, this.id)!; - if (amount.lte(0)) return; // Only sell one if there is at least one - setBuyableAmount(this.layer, this.id, amount.sub(1)); - player.layers[this.layer].points = player.layers[ - this.layer - ].points.add(this.cost!); - } - } - } - }, - onReset(resettingLayer: string) { - // Triggers when this layer is being reset, along with the layer doing the resetting. Not triggered by lower layers resetting, but is by layers on the same row. - if ( - layers[resettingLayer].row != undefined && - this.row != undefined && - layers[resettingLayer].row! > this.row! - ) - resetLayerData(this.layer, ["points"]); // This is actually the default behavior - }, - automate() {}, // Do any automation inherent to this layer if appropriate - resetsNothing() { - return false; - }, - onPrestige() { - return; - }, // Useful for if you gain secondary resources or have other interesting things happen to this layer when you reset it. You gain the currency after this function ends. - - hotkeys: [ - { - key: "c", - description: "reset for lollipops or whatever", - press() { - if (layers[this.layer].canReset) resetLayer(this.layer); - } - }, - { - key: "ctrl+c", - description: "respec things", - press() { - layers[this.layer].buyables!.respec!(); - }, - unlocked() { - return hasUpgrade("c", "22"); - } - } - ], - increaseUnlockOrder: [], // Array of layer names to have their order increased when this one is first unlocked - - microtabs: { - stuff: { - data: { - first: { - display: ` - -
confirmed
` - }, - second: { - embedLayer: "f" - } - } - }, - otherStuff: { - // There could be another set of microtabs here - data: {} - } - }, - - bars: { - data: { - longBoi: { - fillStyle: { "background-color": "#FFFFFF" }, - baseStyle: { "background-color": "#696969" }, - textStyle: { color: "#04e050" }, - - borderStyle() { - return {}; - }, - direction: Direction.Right, - width: 300, - height: 30, - progress() { - return player.points - .add(1) - .log(10) - .div(10) - .toNumber(); - }, - display() { - return format(player.points) + " / 1e10 points"; - }, - unlocked: true - }, - tallBoi: { - fillStyle: { "background-color": "#4BEC13" }, - baseStyle: { "background-color": "#000000" }, - textStyle: { "text-shadow": "0px 0px 2px #000000" }, - - borderStyle() { - return { "border-width": "7px" }; - }, - direction: Direction.Up, - width: 50, - height: 200, - progress() { - return player.points.div(100); - }, - display() { - return formatWhole(player.points.div(1).min(100)) + "%"; - }, - unlocked: true - }, - flatBoi: { - fillStyle: { "background-color": "#FE0102" }, - baseStyle: { "background-color": "#222222" }, - textStyle: { "text-shadow": "0px 0px 2px #000000" }, - - borderStyle() { - return {}; - }, - direction: Direction.Up, - width: 100, - height: 30, - progress() { - return player.layers.c.points.div(50); - }, - unlocked: true - } - } - }, - - // Optional, lets you format the tab yourself by listing components. You can create your own components in v.js. - subtabs: { - "main tab": { - buttonStyle() { - return { color: "orange" }; - }, - notify: true, - display: ` - - - - - -
Name your points!
- - I have {{ format(player.points) }} {{ player.layers.c.thingy }} points! -
- - - - `, - glowColor: "blue" - }, - thingies: { - resetNotify: true, - style() { - return { "background-color": "#222222", "--background": "#222222" }; - }, - buttonStyle() { - return { "border-color": "orange" }; - }, - display: ` - - - - - -
Beep
- - - - - - -
- - ` - }, - jail: { - display: ` - - - - - -
Sugar level:
-
- - -
idk
- - -
-
- -
It's jail because "bars"! So funny! Ha ha!
- ` - }, - illuminati: { - unlocked() { - return hasUpgrade("c", 13); - }, - display: ` -

C O N F I R M E D

- - -
Adjust how many points H gives you!
- ` - } - }, - style() { - return { - //'background-color': '#3325CC' - }; - }, - nodeStyle() { - return { - // Style on the layer node - color: "#3325CC", - "text-decoration": "underline" - }; - }, - glowColor: "orange", // If the node is highlighted, it will be this color (default is red) - componentStyles: { - challenge() { - return { height: "200px" }; - }, - "prestige-button"() { - return { color: "#AA66AA" }; - } - }, - tooltip() { - // Optional, tooltip displays when the layer is unlocked - let tooltip = "{{ formatWhole(player.layers.c.points) }} {{ layers.c.resource }}"; - if (player.layers[this.layer].buyables![11].gt(0)) - tooltip += - "



{{ formatWhole(player.layers.c.buyables![11]) }} Exhancers
"; - return tooltip; - }, - shouldNotify() { - // Optional, layer will be highlighted on the tree if true. - // Layer will automatically highlight if an upgrade is purchasable. - return player.layers.c.buyables![11] == new Decimal(1); - }, - mark: "https://unsoftcapped2.github.io/The-Modding-Tree-2/discord.png", - resetDescription: "Melt your points into " -} as RawLayer; diff --git a/src/data/layers/aca/f.ts b/src/data/layers/aca/f.ts deleted file mode 100644 index 95c2bdd..0000000 --- a/src/data/layers/aca/f.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* eslint-disable */ -import { layers as tmp } from "@/game/layers"; -import player from "@/game/player"; -import { RawLayer } from "@/typings/layer"; -import Decimal, { formatWhole } from "@/util/bignum"; -import { getClickableState } from "@/util/features"; - -export default { - id: "f", - infoboxes: { - data: { - coolInfo: { - title: "Lore", - titleStyle: { color: "#FE0000" }, - body: "DEEP LORE!", - bodyStyle: { "background-color": "#0000EE" } - } - } - }, - - startData() { - return { - unlocked: false, - points: new Decimal(0), - boop: false, - clickables: { [11]: "Start" } // Optional default Clickable state - }; - }, - color: "#FE0102", - requires() { - return new Decimal(10); - }, - resource: "farm points", - baseResource: "points", - baseAmount() { - return player.points; - }, - type: "static", - exponent: 0.5, - base: 3, - roundUpCost: true, - canBuyMax() { - return false; - }, - name: "Farms", - //directMult() {return new Decimal(player.c.otherThingy)}, - - row: 1, - branches: [ - { - target: "c", - "stroke-width": "25px", - stroke: "blue", - style: "filter: blur(5px)" - } - ], // When this layer appears, a branch will appear from this layer to any layers here. Each entry can be a pair consisting of a layer id and a color. - - tooltipLocked() { - // Optional, tooltip displays when the layer is locked - return "This weird farmer dinosaur will only see you if you have at least {{layers.f.requires}} points. You only have {{ formatWhole(player.points) }}"; - }, - midsection: - '

Bork Bork!
', - // The following are only currently used for "custom" Prestige type: - prestigeButtonDisplay() { - //Is secretly HTML - if (!this.canBuyMax) - return ( - "Hi! I'm a weird dinosaur and I'll give you a Farm Point in exchange for all of your points and lollipops! (At least " + - formatWhole(tmp[this.layer].nextAt) + - " points)" - ); - if (this.canBuyMax) - return ( - "Hi! I'm a weird dinosaur and I'll give you " + - formatWhole(tmp[this.layer].resetGain) + - " Farm Points in exchange for all of your points and lollipops! (You'll get another one at " + - formatWhole(tmp[this.layer].nextAt) + - " points)" - ); - }, - canReset() { - return Decimal.gte(tmp[this.layer].baseAmount!, tmp[this.layer].nextAt); - }, - // This is also non minimal, a Clickable! - clickables: { - masterButtonClick() { - if (getClickableState(this.layer, 11) == "Borkened...") - player.layers[this.layer].clickables![11] = "Start"; - }, - masterButtonDisplay() { - return getClickableState(this.layer, 11) == "Borkened..." - ? "Fix the clickable!" - : "Does nothing"; - }, // Text on Respec button, optional - data: { - 11: { - title: "Clicky clicky!", // Optional, displayed at the top in a larger font - display() { - // Everything else displayed in the buyable button after the title - const data = getClickableState(this.layer, this.id); - return "Current state:
" + data; - }, - unlocked() { - return player.layers[this.layer].unlocked; - }, - canClick() { - return getClickableState(this.layer, this.id) !== "Borkened..."; - }, - click() { - switch (getClickableState(this.layer, this.id)) { - case "Start": - player.layers[this.layer].clickables![this.id] = "A new state!"; - break; - case "A new state!": - player.layers[this.layer].clickables![this.id] = "Keep going!"; - break; - case "Keep going!": - player.layers[this.layer].clickables![this.id] = - "Maybe that's a bit too far..."; - break; - case "Maybe that's a bit too far...": - //makeParticles(coolParticle, 4) - player.layers[this.layer].clickables![this.id] = "Borkened..."; - break; - default: - player.layers[this.layer].clickables![this.id] = "Start"; - break; - } - }, - hold() { - console.log("Clickkkkk..."); - }, - style() { - switch (getClickableState(this.layer, this.id)) { - case "Start": - return { "background-color": "green" }; - case "A new state!": - return { "background-color": "yellow" }; - case "Keep going!": - return { "background-color": "orange" }; - case "Maybe that's a bit too far...": - return { "background-color": "red" }; - default: - return {}; - } - } - } - } - } -} as RawLayer; diff --git a/src/data/layers/demo-infinity.ts b/src/data/layers/demo-infinity.ts deleted file mode 100644 index 6e62446..0000000 --- a/src/data/layers/demo-infinity.ts +++ /dev/null @@ -1,354 +0,0 @@ -/* eslint-disable */ -import { layers } from "@/game/layers"; -import player from "@/game/player"; -import { Layer, RawLayer } from "@/typings/layer"; -import Decimal, { format } from "@/util/bignum"; -import { - getBuyableAmount, hasChallenge, hasMilestone, hasUpgrade, setBuyableAmount -} from "@/util/features"; -import { resetLayer } from "@/util/layers"; - -export default { - id: "i", - position: 2, // Horizontal position within a row. By default it uses the layer id and sorts in alphabetical order - startData() { - return { - unlocked: false, - points: new Decimal(0) - }; - }, - branches: ["p"], - color: "#964B00", - requires() { - const require = new Decimal(8).plus( - player.layers.i.points - .div(10) - .floor() - .times(2) - ); - return require; - }, // Can be a function that takes requirement increases into account - effectDisplay() { - return ( - "Multiplying points and prestige points by " + - format( - player.layers[this.layer].points - .plus(1) - .pow(hasUpgrade("p", 235) ? 6.942 : 1) - ) - ); - }, - resource: "Infinity", // Name of prestige currency - baseResource: "pointy points", // Name of resource prestige is based on - baseAmount() { - return player.layers.p.buyables![21]; - }, // Get the current amount of baseResource - type: "custom", // normal: cost to gain currency depends on amount gained. static: cost depends on how much you already have - resetGain() { - if (hasMilestone("p", 12)) { - return getBuyableAmount("p", 21)! - .div(2) - .floor() - .times(2) - .times(5) - .sub(30) - .sub(player.layers.i.points); - } - return player.layers.p.buyables![21].gte(layers.i.requires!) ? 1 : 0; - }, // Prestige currency exponent - getNextAt() { - return new Decimal(100); - }, - canReset() { - return player.layers.p.buyables![21].gte(layers.i.requires!); - }, - prestigeButtonDisplay() { - return ( - "Reset everything for +" + - format(layers.i.resetGain) + - " Infinity.
You need " + - format(layers.i.requires!) + - " pointy points to reset." - ); - }, - row: 1, // Row the layer is in on the tree (0 is the first row) - hotkeys: [ - { - key: "i", - description: "I: Infinity", - press() { - if (layers.i.canReset) resetLayer(this.layer); - } - } - ], - layerShown() { - return ( - player.layers[this.layer].unlocked || - new Decimal(player.layers.p.buyables[21]).gte(8) - ); - }, - milestones: { - data: { - 0: { - requirementDisplay: "2 Infinity points", - effectDisplay: "Keep ALL milestones on reset", - done() { - return player.layers[this.layer].points.gte(2); - } - }, - 1: { - requirementDisplay: "3 Infinity points", - effectDisplay: "Pointy points don't reset generators", - done() { - return player.layers[this.layer].points.gte(3); - }, - unlocked() { - return hasMilestone(this.layer, Number(this.id) - 1); - } - }, - 2: { - requirementDisplay: "4 Infinity points", - effectDisplay: - "Start with 6 Time Dilation, 3 Point, and 1 of the other 2 challenges", - done() { - return player.layers[this.layer].points.gte(4); - }, - unlocked() { - return hasMilestone(this.layer, Number(this.id) - 1); - } - }, - 3: { - requirementDisplay: "5 Infinity points", - effectDisplay: "Start with 40 upgrades and 6 boosts", - done() { - return player.layers[this.layer].points.gte(5); - }, - unlocked() { - return hasMilestone(this.layer, Number(this.id) - 1); - } - }, - 4: { - requirementDisplay: "6 Infinity points", - effectDisplay: - "You can choose all of the 14th row upgrades, and remove the respec button", - done() { - return player.layers[this.layer].points.gte(6); - }, - unlocked() { - return hasMilestone(this.layer, Number(this.id) - 1); - } - }, - 5: { - requirementDisplay: "8 Infinity points", - effectDisplay: "Keep all upgrades and 7 Time dilation", - done() { - return player.layers[this.layer].points.gte(8); - }, - unlocked() { - return hasMilestone(this.layer, Number(this.id) - 1); - } - }, - 6: { - requirementDisplay: "10 Infinity points", - effectDisplay: "Infinity reset nothing and auto prestige", - done() { - return player.layers[this.layer].points.gte(10); - }, - unlocked() { - return hasMilestone(this.layer, Number(this.id) - 1); - } - } - } - }, - resetsNothing() { - return hasMilestone(this.layer, 6); - }, - update(this: Layer) { - if (hasMilestone(this.layer, 0)) { - if (!hasMilestone("p", 0)) { - player.layers.p.milestones!.push(0); - player.layers.p.milestones!.push(1); - player.layers.p.milestones!.push(2); - player.layers.p.milestones!.push(3); - player.layers.p.milestones!.push(4); - player.layers.p.milestones!.push(5); - player.layers.p.milestones!.push(6); - player.layers.p.milestones!.push(7); - player.layers.p.milestones!.push(8); - } - } - if (hasMilestone(this.layer, 2)) { - if (!hasChallenge("p", 11)) { - player.layers.p.challenges![11] = new Decimal( - hasMilestone(this.layer, 5) ? 7 : 6 - ); - player.layers.p.challenges![12] = new Decimal(3); - player.layers.p.challenges![21] = new Decimal(1); - player.layers.p.challenges![22] = new Decimal(1); - } - } - if (hasMilestone(this.layer, 3)) { - if (!hasUpgrade("p", 71)) { - player.layers.p.upgrades = [ - 11, - 12, - 13, - 14, - 21, - 22, - 23, - 24, - 31, - 32, - 33, - 34, - 41, - 42, - 43, - 44, - 51, - 52, - 53, - 54, - 61, - 62, - 63, - 64, - 71, - 72, - 73, - 74, - 81, - 82, - 83, - 84, - 91, - 92, - 93, - 94, - 101, - 102, - 103, - 104 - ]; - } - if (getBuyableAmount("p", 11)!.lt(6)) { - setBuyableAmount("p", 11, new Decimal(6)); - } - } - if (hasUpgrade(this.layer, 13)) { - for ( - let i = 0; - i < (hasUpgrade("p", 222) ? 100 : hasUpgrade("p", 215) ? 10 : 1); - i++ - ) { - if (layers.p.buyables!.data[12].canAfford) layers.p.buyables!.data[12].buy(); - if (layers.p.buyables!.data[13].canAfford) layers.p.buyables!.data[13].buy(); - if ( - layers.p.buyables!.data[14].canAfford && - layers.p.buyables!.data[14].unlocked - ) - layers.p.buyables!.data[14].buy(); - if (layers.p.buyables!.data[21].canAfford) layers.p.buyables!.data[21].buy(); - } - } - if (hasUpgrade("p", 223)) { - if (hasMilestone("p", 14)) - player.layers.p.buyables![22] = player.layers.p.buyables![22].max( - player.layers.p.buyables![21].sub(7) - ); - else if (layers.p.buyables!.data[22].canAfford) layers.p.buyables!.data[22].buy(); - } - if (hasMilestone(this.layer, 5) && !hasUpgrade("p", 111)) { - player.layers.p.upgrades = [ - 11, - 12, - 13, - 14, - 21, - 22, - 23, - 24, - 31, - 32, - 33, - 34, - 41, - 42, - 43, - 44, - 51, - 52, - 53, - 54, - 61, - 62, - 63, - 64, - 71, - 72, - 73, - 74, - 81, - 82, - 83, - 84, - 91, - 92, - 93, - 94, - 101, - 102, - 103, - 104, - 111, - 121, - 122, - 131, - 132, - 141, - 142, - 143 - ]; - } - if (hasMilestone(this.layer, 6)) { - this.reset(); - } - }, - upgrades: { - rows: 999, - cols: 5, - data: { - 11: { - title: "Prestige", - description: "Gain 100% of prestige points per second", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasMilestone(this.layer, 4); - } - }, - 12: { - title: "Automation", - description: "Remove the nerf of upgrade Active", - cost() { - return new Decimal(2); - }, - unlocked() { - return hasUpgrade(this.layer, 11); - } - }, - 13: { - title: "Pointy", - description: "Automatically buy generators and pointy points", - cost() { - return new Decimal(5); - }, - unlocked() { - return hasUpgrade(this.layer, 11); - } - } - } - } -} as RawLayer; diff --git a/src/data/layers/demo.ts b/src/data/layers/demo.ts deleted file mode 100644 index 329ac6f..0000000 --- a/src/data/layers/demo.ts +++ /dev/null @@ -1,2301 +0,0 @@ -/* eslint-disable */ -import { layers } from "@/game/layers"; -import player from "@/game/player"; -import { DecimalSource } from "@/lib/break_eternity"; -import { RawLayer } from "@/typings/layer"; -import Decimal, { format } from "@/util/bignum"; -import { - getBuyableAmount, hasChallenge, hasMilestone, hasUpgrade, setBuyableAmount -} from "@/util/features"; -import { resetLayer } from "@/util/layers"; - -export default { - id: "p", - position: 2, - startData() { - return { - unlocked: true, - points: new Decimal(0), - gp: new Decimal(0), - g: new Decimal(0), - geff: new Decimal(1), - cmult: new Decimal(1) - }; - }, - color: "#4BDC13", - requires() { - let require = new Decimal(68.99); - if (hasMilestone(this.layer, 0)) require = require.plus(0.01); - if (hasUpgrade(this.layer, 21)) - require = require.tetrate( - hasUpgrade("p", 34) - ? new Decimal(1) - .div( - new Decimal(1).plus( - layers.p.upgrades!.data[34].effect as Decimal - ) - ) - .toNumber() - : 1 - ); - if (hasUpgrade(this.layer, 22)) - require = require.pow( - hasUpgrade("p", 34) - ? new Decimal(1).div( - new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal) - ) - : 1 - ); - if (hasUpgrade(this.layer, 23)) - require = require.div( - hasUpgrade("p", 34) - ? new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal) - : 1 - ); - if (hasUpgrade(this.layer, 24)) - require = require.sub( - hasUpgrade("p", 34) - ? new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal) - : 1 - ); - return require.max(1); - }, - resource: "prestige points", - baseResource: "points", - baseAmount() { - return player.points; - }, // Get the current amount of baseResource - type: "normal", // normal: cost to gain currency depends on amount gained. static: cost depends on how much you already have - exponent: 0.5, // Prestige currency exponent - gainMult() { - // Calculate the multiplier for main currency from bonuses - let mult = new Decimal(1); - if (hasUpgrade(this.layer, 131)) mult = mult.times(10); - if (player.layers.i.unlocked) - mult = mult.times( - player.layers.i.points.plus(1).pow(hasUpgrade("p", 235) ? 6.942 : 1) - ); - if (hasUpgrade(this.layer, 222)) - mult = mult.times(getBuyableAmount(this.layer, 22)!.plus(1)); - if (hasUpgrade("p", 231)) { - const asdf = hasUpgrade("p", 132) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(2)) - : hasUpgrade("p", 101) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(3)) - : hasUpgrade("p", 93) - ? (player.layers.p.gp as Decimal).plus(1).pow(0.2) - : (player.layers.p.gp as Decimal).plus(1).log10(); - mult = mult.mul(asdf.plus(1)); - } - if (hasMilestone(this.layer, 13)) - mult = mult.mul( - new Decimal(2) - .plus(layers.p.buyables!.data[33].effect as Decimal) - .pow(getBuyableAmount(this.layer, 32)!) - ); - return mult; - }, - gainExp() { - // Calculate the exponent on main currency from bonuses - return new Decimal(1); - }, - row: 0, // Row the layer is in on the tree (0 is the first row) - hotkeys: [ - { - key: "p", - description: "P: Reset for prestige points", - press() { - if (layers.p.canReset) resetLayer(this.layer); - } - } - ], - layerShown() { - return true; - }, - upgrades: { - rows: 999, - cols: 5, - data: { - 11: { - title: "Gain points", - description: "Point generation is increased by 1", - cost() { - if (hasMilestone(this.layer, 2)) return new Decimal(1); - return new Decimal(1.00001); - }, - unlocked() { - return true; - } - }, - 12: { - title: "Gain more points", - description: "Point generation is singled", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 11); - } - }, - 13: { - title: "Gain more points", - description: "Point generation is lined", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 12); - } - }, - 14: { - title: "Gain more points", - description: "Point generation is tetrated by 1", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 13); - } - }, - 21: { - title: "Lower prestige requirement", - description: "Prestige point requirement is superrooted by 1", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 14); - } - }, - 22: { - title: "Lower prestige requirement more", - description: "Prestige point requirement is line rooted", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 21); - } - }, - 23: { - title: "Lower prestige requirement more", - description: "Prestige point requirement is wholed", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 22); - } - }, - 24: { - title: "Lower prestige requirement more", - description: "Prestige point requirement is decreased by 1", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 23); - } - }, - 31: { - title: "Unlock", - description: "Unlock an upgrade", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 24); - } - }, - 32: { - title: "An", - description: "Unlock an upgrade", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 31); - } - }, - 33: { - title: "Upgrade", - description: "Unlock an upgrade", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 32); - } - }, - 34: { - title: "Increase", - description() { - return ( - "Add 0.01 to all above upgrades. Currently: +" + - format(this.effect as Decimal) - ); - }, - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 33); - }, - effect() { - let r = hasUpgrade("p", 41) - ? new Decimal(0.01).times(layers.p.upgrades!.data[41].effect as Decimal) - : new Decimal(0.01); - r = r.times( - new Decimal(1).plus( - new Decimal(player.layers[this.layer].challenges![11]) - .add(1) - .pow(hasUpgrade(this.layer, 121) ? 1.2 : 1) - ) - ); - if (hasUpgrade(this.layer, 92)) - r = r.plus( - new Decimal(0.001) - .times((player.layers[this.layer].g as Decimal).plus(1)) - .min(0.05) - ); - return r; - } - }, - 41: { - title: "Increase again", - description() { - return ( - "Multiply the previous upgrade by 1.01. Currently: x" + - format(this.effect as Decimal) - ); - }, - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 34); - }, - effect() { - return new Decimal(1.01) - .pow(hasUpgrade("p", 42) ? layers.p.upgrades!.data[42].effect as Decimal : 1) - .times(hasUpgrade("p", 63) ? 2 : 1); - } - }, - 42: { - title: "Increase again", - description() { - return ( - "Exponentiate the previous upgrade by 1.01. Currently: ^" + - format(this.effect as Decimal) - ); - }, - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 41); - }, - effect() { - return new Decimal(1.01) - .tetrate(hasUpgrade("p", 43) ? (layers.p.upgrades!.data[43].effect as Decimal).toNumber() : 1) - .times(hasUpgrade("p", 63) ? 2 : 1) - .times(hasUpgrade("p", 64) ? 2 : 1); - } - }, - 43: { - title: "Increase again", - description() { - return ( - "Tetrate the previous upgrade by 1.01. Currently: ^^" + - format(this.effect as Decimal) - ); - }, - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 42); - }, - effect() { - return new Decimal(1.01) - .pentate(hasUpgrade("p", 44) ? (layers.p.upgrades!.data[44].effect as Decimal).toNumber() : 1) - .times(hasUpgrade("p", 63) ? 2 : 1) - .times(hasUpgrade("p", 64) ? 2 : 1); - } - }, - 44: { - title: "Increase again", - description() { - return ( - "Pentate the previous upgrade by 1.01. Currently: ^^^" + - format(this.effect as Decimal) - ); - }, - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 43); - }, - effect() { - return new Decimal(1.01) - .times(hasUpgrade("p", 63) ? 2 : 1) - .times(hasUpgrade("p", 64) ? 2 : 1); - } - }, - 51: { - title: "Challenging", - description: "This upgrade doesn't unlock a challenge", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 44); - } - }, - 52: { - title: "Not challenging", - description: "This upgrade doesn't add 1 to the completion limit", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 51); - } - }, - 53: { - title: "Not not challenging", - description: "This upgrade doesn't add 1 to the completion limit", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 52); - } - }, - 54: { - title: "(not^3) challenging", - description: - "Fix the bug where you can't buy upgrades when you have 1 prestige point", - cost() { - return new Decimal(0.99999); - }, - unlocked() { - return hasUpgrade(this.layer, 53); - }, - onPurchase() { - player.layers.p.points = player.layers.p.points.round(); - } - }, - 61: { - title: "(not^4) challenging", - description: "Doesn't unlock a second challenge", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 54) && hasUpgrade(this.layer, 53); - } - }, - 62: { - title: "Infinity points", - description: "You can now complete Time Dilation 4 more times", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 61); - } - }, - 63: { - title: "Eternity points", - description: "Double all fourth row upgrade effects", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 62); - } - }, - 64: { - title: "Reality points", - description: "Previous upgrade, but only to the last 3 upgrades", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 63); - } - }, - 71: { - title: "1", - description: "Add 1.1 to point gain, but reset all above upgrades", - cost() { - return new Decimal(1); - }, - unlocked() { - return hasUpgrade(this.layer, 64); - }, - onPurchase() { - if (!hasMilestone(this.layer, 0)) - player.layers[this.layer].upgrades = [71]; - } - }, - 72: { - title: "2", - description: "Multiply point gain by 1.1, but reset all above upgrades", - cost() { - return new Decimal(2); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 64) && - hasUpgrade(this.layer, Number(this.id) - 1) - ); - }, - onPurchase() { - if (!hasMilestone(this.layer, 1)) - player.layers[this.layer].upgrades = [71, 72]; - } - }, - 73: { - title: "3", - description: "Raise point gain by ^1.1, but reset all above upgrades", - cost() { - return new Decimal(4); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 64) && - hasUpgrade(this.layer, Number(this.id) - 1) - ); - }, - onPurchase() { - if (!hasMilestone(this.layer, 1)) - player.layers[this.layer].upgrades = [71, 72, 73]; - } - }, - 74: { - title: "4", - description: "Tetrate point gain by 1.1, but reset all above upgrades", - cost() { - return new Decimal(8); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 64) && - hasUpgrade(this.layer, Number(this.id) - 1) - ); - }, - onPurchase() { - if (!hasMilestone(this.layer, 2)) - player.layers[this.layer].upgrades = [71, 72, 73, 74]; - if (hasMilestone(this.layer, 1) && !hasMilestone(this.layer, 2)) { - player.layers[this.layer].upgrades = [ - 11, - 12, - 13, - 14, - 21, - 22, - 23, - 24, - 71, - 72, - 73, - 74 - ]; - } - } - }, - 81: { - title: "5", - description: "Generator efficiency is increased by 2", - cost() { - return new Decimal(1); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 74) && - (player.layers[this.layer].buyables![12].gt(0) || - player.layers[this.layer].buyables![21].gt(0)) - ); - } - }, - 82: { - title: "6", - description: "Unlock another way to buy generators", - cost() { - return new Decimal(1); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 81) && - (player.layers[this.layer].buyables![12].gt(0) || - player.layers[this.layer].buyables![21].gt(0)) - ); - } - }, - 83: { - title: "7", - description: "Generator efficiency is boosted by prestige points", - cost() { - return new Decimal(3); - }, - unlocked() { - return hasUpgrade(this.layer, 82); - } - }, - 84: { - title: "8", - description: "You can complete Point one more time", - cost() { - return new Decimal(3); - }, - unlocked() { - return hasUpgrade(this.layer, 83); - } - }, - 91: { - title: "9", - description: "New Challenge Time", - cost() { - return new Decimal(20); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 84) && - new Decimal(player.layers[this.layer].challenges![12]).gte(3) - ); - } - }, - 92: { - title: "10", - description: - "Each of the first 50 generators adds 0.001 to Increase", - cost() { - return new Decimal(5); - }, - unlocked() { - return hasUpgrade(this.layer, 91) && hasChallenge(this.layer, 21); - } - }, - 93: { - title: "11", - description: - "Change the tree trunk in generator effect to a hypertessaract root", - cost() { - return new Decimal(7); - }, - unlocked() { - return hasUpgrade(this.layer, 92); - } - }, - 94: { - title: "12", - description: "Unlock a clickable in generators", - cost() { - return new Decimal(50); - }, - unlocked() { - return hasUpgrade(this.layer, 93); - } - }, - 101: { - title: "10th row????", - description: "Decrease the dimensions of 11 by 2", - cost() { - return new Decimal(10); - }, - unlocked() { - return hasUpgrade(this.layer, 94); - } - }, - 102: { - title: "2 Tree Trunks", - description: - "Double log of generator points adds to generator efficiency", - cost() { - return new Decimal(25); - }, - unlocked() { - return hasUpgrade(this.layer, 101); - } - }, - 103: { - title: "(not^5) challenging", - description: "Unlock the last challenge", - cost() { - return new Decimal(103); - }, - unlocked() { - return hasUpgrade(this.layer, 102); - } - }, - 104: { - title: "2 layers tree", - description: "Prestige points boost points, and unlock another tab", - cost() { - return new Decimal(100); - }, - unlocked() { - return hasUpgrade(this.layer, 103) && hasChallenge(this.layer, 22); - } - }, - 111: { - title: "not (hardcapped)", - description: - "Remove the generator clickable hardcap, and you can only pick one upgrade on each row below this", - cost() { - return new Decimal(110); - }, - unlocked() { - return hasUpgrade(this.layer, 104) && hasMilestone(this.layer, 6); - } - }, - 112: { - title: "Respec button", - description: "Respec all lower upgrades, but you don't get points back", - cost() { - return new Decimal(100); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 111) && - (hasUpgrade(this.layer, 121) || hasUpgrade(this.layer, 122)) && - !hasMilestone("i", 4) - ); - }, - onPurchase() { - player.layers.p.upgrades = player.layers.p.upgrades!.filter((i: string | number) => { - return Number(i) < 112; - }); - } - }, - 121: { - title: "Timers", - description: "Raise the Time Dilation reward effect to the 1.2", - cost() { - return new Decimal(500); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 111) && - (!hasUpgrade(this.layer, 122) || hasMilestone(this.layer, 7)) - ); - } - }, - 122: { - title: "Generators", - description: - "Decrease the first generator buyable cost scaling base by 2", - cost() { - return new Decimal(500); - }, - unlocked() { - return ( - hasUpgrade(this.layer, 111) && - (!hasUpgrade(this.layer, 121) || hasMilestone(this.layer, 7)) - ); - } - }, - 131: { - title: "Prestige", - description: "Gain 10x more prestige points", - cost() { - return new Decimal(5000); - }, - unlocked() { - return ( - (hasUpgrade(this.layer, 121) || hasUpgrade(this.layer, 122)) && - (!hasUpgrade(this.layer, 132) || hasMilestone(this.layer, 7)) - ); - } - }, - 132: { - title: "One and a half", - description: "Raise generator effect to the 1.5", - cost() { - return new Decimal(5000); - }, - unlocked() { - return ( - (hasUpgrade(this.layer, 121) || hasUpgrade(this.layer, 122)) && - (!hasUpgrade(this.layer, 131) || hasMilestone(this.layer, 7)) - ); - } - }, - - 141: { - title: "Active", - description: - "Multiply generator efficiency now increases by 1, but it doesn't automatically click.", - cost() { - return new Decimal(50000); - }, - unlocked() { - return ( - (hasUpgrade(this.layer, 131) || hasUpgrade(this.layer, 132)) && - ((!hasUpgrade(this.layer, 142) && !hasUpgrade(this.layer, 143)) || - hasMilestone("i", 4)) - ); - } - }, - 142: { - title: "Passive", - description: "Gain 5x more points", - cost() { - return new Decimal(50000); - }, - unlocked() { - return ( - (hasUpgrade(this.layer, 131) || hasUpgrade(this.layer, 132)) && - ((!hasUpgrade(this.layer, 141) && !hasUpgrade(this.layer, 143)) || - hasMilestone("i", 4)) - ); - } - }, - 143: { - title: "Idle", - description: "Hours played multiply generator power", - cost() { - return new Decimal(50000); - }, - unlocked() { - return ( - (hasUpgrade(this.layer, 131) || hasUpgrade(this.layer, 132)) && - ((!hasUpgrade(this.layer, 142) && !hasUpgrade(this.layer, 141)) || - hasMilestone("i", 4)) - ); - } - }, - 211: { - title: "Prestige", - description: "Pointy points multiply points", - cost() { - return new Decimal(1); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && player.subtabs.p.mainTabs != "Upgrades" - ); - } - }, - 212: { - title: "Pointy", - description: - "Pointy prestige points reduce the cost scaling of pointy points", - cost() { - return new Decimal(2); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 211) - ); - } - }, - 213: { - title: "Time", - description: "Generator power also multiplies point gain", - cost() { - return new Decimal(6); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 212) - ); - } - }, - 214: { - title: "^0", - description: "Further reduce the pointy point scaling", - cost() { - return new Decimal(11); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 213) - ); - } - }, - 215: { - title: "bulk", - description: "Auto-pointy points now buys 10 per tick", - cost() { - return new Decimal(27); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 214) - ); - } - }, - 221: { - title: "^-1", - description: "^0 is even more powerful", - cost() { - return new Decimal(28); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 215) - ); - } - }, - 222: { - title: "???", - description: - "square bulk and pointy prestige points multiply prestige points", - cost() { - return new Decimal(90); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 221) - ); - } - }, - 223: { - title: "more automation", - description: "Automatically gain pointy prestige points", - cost() { - return new Decimal(96); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 222) - ); - } - }, - 224: { - title: "Generation", - description: "Generator costs are divided by generator effect", - cost() { - return new Decimal(100); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 223) - ); - } - }, - 225: { - title: "Boosters", - description: "Unlock boosters (next update)", - cost() { - return new Decimal(135); - }, - canAfford() { - return getBuyableAmount(this.layer, 22)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 22, - getBuyableAmount(this.layer, 22)!.sub(this.cost) - ); - }, - unlocked() { - return ( - hasMilestone("i", 5) && - player.subtabs.p.mainTabs != "Upgrades" && - hasUpgrade(this.layer, 224) - ); - } - }, - 231: { - title: "Blue", - description: "The generator effect also affects prestige points", - cost() { - return new Decimal(4); - }, - canAfford() { - return getBuyableAmount(this.layer, 23)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 23, - getBuyableAmount(this.layer, 23)!.sub(this.cost) - ); - }, - unlocked() { - return ( - player.subtabs.p.mainTabs != "Upgrades" && - hasMilestone(this.layer, 11) - ); - }, - currencyDisplayName: "pointy boosters" - }, - 232: { - title: "Red", - description: "Unlock a third way to buy generators", - cost() { - return new Decimal(5); - }, - canAfford() { - return getBuyableAmount(this.layer, 23)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 23, - getBuyableAmount(this.layer, 23)!.sub(this.cost) - ); - }, - unlocked() { - return ( - player.subtabs.p.mainTabs != "Upgrades" && - hasMilestone(this.layer, 12) - ); - }, - currencyDisplayName: "pointy boosters" - }, - 233: { - title: "Green", - description: - "Prestige points do not reset your pointy points and boosters don't reset generators", - cost() { - return new Decimal(5); - }, - canAfford() { - return getBuyableAmount(this.layer, 23)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 23, - getBuyableAmount(this.layer, 23)!.sub(this.cost) - ); - }, - unlocked() { - return ( - player.subtabs.p.mainTabs != "Upgrades" && - hasMilestone(this.layer, 12) - ); - }, - currencyDisplayName: "pointy boosters" - }, - 234: { - title: "Yellow", - description: - "Divide the cost of the third generator buyable based on boosters", - cost() { - return new Decimal(6); - }, - canAfford() { - return getBuyableAmount(this.layer, 23)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 23, - getBuyableAmount(this.layer, 23)!.sub(this.cost) - ); - }, - unlocked() { - return ( - player.subtabs.p.mainTabs != "Upgrades" && - hasMilestone(this.layer, 12) - ); - }, - currencyDisplayName: "pointy boosters" - }, - 235: { - title: "Orange", - description: "Raise the Infinity effect to the 6.9420th power", - cost() { - return new Decimal(8); - }, - canAfford() { - return getBuyableAmount(this.layer, 23)!.gte(this.cost); - }, - pay() { - setBuyableAmount( - this.layer, - 23, - getBuyableAmount(this.layer, 23)!.sub(this.cost) - ); - }, - unlocked() { - return ( - player.subtabs.p.mainTabs != "Upgrades" && - hasMilestone(this.layer, 12) - ); - }, - currencyDisplayName: "pointy boosters" - } - } - }, - - clickables: { - rows: 1, - cols: 1, - data: { - 11: { - display() { - return ( - "Multiply generator efficiency by " + - format(player.layers.p.cmult as Decimal) + - ((player.layers.p.cmult as Decimal).min(100).eq(100) && !hasUpgrade(this.layer, 111) - ? " (hardcapped)" - : "") - ); - }, - unlocked() { - return hasUpgrade("p", 94); - }, - click() { - player.layers.p.cmult = (player.layers.p.cmult as Decimal).plus(hasUpgrade("p", 141) ? 1 : 0.01); - if (!hasUpgrade(this.layer, 111)) - player.layers.p.cmult = (player.layers.p.cmult as Decimal).min(100); - }, - canClick() { - return (player.layers.p.cmult as Decimal).lt(100) || hasUpgrade(this.layer, 111); - } - } - } - }, - - challenges: { - rows: 99, - cols: 2, - data: { - 11: { - name: "Time dilation", - challengeDescription() { - return "Point gain exponent is raised to the ^0.75"; - }, - goal() { - return new Decimal(100).times( - new Decimal(10).pow( - new Decimal(player.layers[this.layer].challenges![this.id]) - .times( - new Decimal(1).sub( - new Decimal( - layers[this.layer].challenges!.data[12].effect as number - ).div(100) - ) - ) - .pow(2) - ) - ); - }, - rewardDescription() { - return ( - "You have completed this challenge " + - player.layers[this.layer].challenges![this.id] + - "/" + - this.completionLimit + - " times. Multiply Increase's effect by challenge completions+1. Currently: x" + - format( - new Decimal(player.layers[this.layer].challenges![this.id]) - .add(1) - .pow(hasUpgrade(this.layer, 121) ? 1.2 : 1) - ) - ); - }, - unlocked() { - return hasUpgrade("p", 51) || hasChallenge(this.layer, this.id); - }, - completionLimit() { - if (hasUpgrade("p", 62)) return 7; - if (hasUpgrade("p", 53)) return 3; - if (hasUpgrade("p", 52)) return 2; - return 1; - } - }, - 12: { - name: "Point", - challengeDescription: "Points are pointed", - goal() { - return new Decimal(100); - }, - rewardDescription() { - return ( - "You have completed this challenge " + - player.layers[this.layer].challenges![this.id] + - "/" + - this.completionLimit + - " times, making previous challenge goal scale " + - layers[this.layer].challenges!.data[this.id].effect + - "% slower." - ); - }, - unlocked() { - return hasUpgrade("p", 61) || hasChallenge(this.layer, this.id); - }, - effect() { - if (!hasChallenge(this.layer, this.id)) return 0; - if (player.layers[this.layer].challenges![this.id] == new Decimal(1)) - return 50; - if (player.layers[this.layer].challenges![this.id] == new Decimal(2)) - return 60; - if (player.layers[this.layer].challenges![this.id] == new Decimal(3)) - return 70; - }, - completionLimit() { - let l = new Decimal(1); - if (hasUpgrade("p", 84)) l = l.plus(1); - if (hasMilestone("p", 3)) l = l.plus(1); - return l; - } - }, - 21: { - name: "Time Points", - challengeDescription: "You are stuck in all above challenges", - goal() { - return new Decimal(308.25); - }, - rewardDescription() { - return "Lower the first generator buyable cost base by 6"; - }, - unlocked() { - return hasUpgrade("p", 91) || hasChallenge(this.layer, this.id); - } - }, - 22: { - name: "Last Challenge", - challengeDescription: "Generator points do nothing", - goal() { - return new Decimal(9999); - }, - rewardDescription() { - return "Autoclick the clickable and reduce 2 Tree Trunks by 1"; - }, - unlocked() { - return hasUpgrade("p", 103) || hasChallenge(this.layer, this.id); - } - } - } - }, - buyables: { - rows: 99, - cols: 4, - data: { - 11: { - cost() { - return new Decimal(0); - }, - display() { - return ( - "Reset all upgrades and challenges, but get a boost. You have reset " + - getBuyableAmount(this.layer, this.id) + - " times.
" + - (getBuyableAmount(this.layer, this.id)!.eq(6) - ? "You can't buy more than 6 boosts!" - : "You need all upgrades to reset.") - ); - }, - canAfford() { - return ( - player.layers[this.layer].points.gte(this.cost!) && - hasUpgrade(this.layer, 74) && - hasUpgrade(this.layer, 64) && - getBuyableAmount(this.layer, this.id)!.lt(6) - ); - }, - buy() { - player.layers[this.layer].points = player.layers[ - this.layer - ].points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - player.layers[this.layer].points = new Decimal(0); - player.layers[this.layer].upgrades = []; - if (hasMilestone(this.layer, 1)) - player.layers[this.layer].upgrades = [ - 11, - 12, - 13, - 14, - 21, - 22, - 23, - 24 - ]; - if (hasMilestone(this.layer, 3)) - player.layers[this.layer].upgrades = [ - 11, - 12, - 13, - 14, - 21, - 22, - 23, - 24, - 31, - 32, - 33, - 34, - 41, - 42, - 43, - 44, - 51, - 52, - 53, - 54, - 61, - 62, - 63, - 64 - ]; - if (!hasMilestone(this.layer, 2)) { - for (const c in layers[this.layer].challenges) { - player.layers[this.layer].challenges![c] = new Decimal(0); - } - } - }, - unlocked() { - return ( - (hasUpgrade(this.layer, 74) && hasUpgrade(this.layer, 64)) || - hasMilestone(this.layer, 0) - ); - } - }, - 12: { - cost() { - return new Decimal(1) - .times( - new Decimal(hasChallenge(this.layer, 21) ? 4 : 10) - .sub(hasUpgrade(this.layer, 122) ? 2 : 0) - .pow(player.layers.p.buyables![this.id]) - ) - .div( - hasUpgrade(this.layer, 224) - ? hasUpgrade("p", 132) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(2)) - : hasUpgrade("p", 101) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(3)) - : hasUpgrade("p", 93) - ? (player.layers.p.gp as Decimal).plus(1).pow(0.2) - : (player.layers.p.gp as Decimal).plus(1).log10() - : 1 - ); - }, - display() { - return "Buy a generator for " + format(this.cost!) + " points"; - }, - canAfford() { - return player.points.gte(this.cost!) && hasMilestone(this.layer, 5); - }, - buy() { - if (!hasMilestone("p", 13)) - player.points = player.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - player.layers[this.layer].g = (player.layers[this.layer].g as Decimal).plus(1); - }, - unlocked() { - return hasMilestone(this.layer, 5); - } - }, - 13: { - cost() { - return new Decimal(1) - .times(new Decimal(2).pow(player.layers.p.buyables![this.id])) - .div( - hasUpgrade(this.layer, 224) - ? hasUpgrade("p", 132) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(2)) - : hasUpgrade("p", 101) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(3)) - : hasUpgrade("p", 93) - ? (player.layers.p.gp as Decimal).plus(1).pow(0.2) - : (player.layers.p.gp as Decimal).plus(1).log10() - : 1 - ); - }, - display() { - return ( - "Buy a generator for " + format(this.cost!) + " prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasUpgrade("p", 82); - }, - buy() { - if (!hasMilestone("p", 13)) - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - player.layers[this.layer].g = (player.layers[this.layer].g as Decimal).plus(1); - }, - unlocked() { - return hasUpgrade(this.layer, 82); - } - }, - 14: { - cost() { - return new Decimal(900) - .mul(new Decimal(1.01).pow(getBuyableAmount(this.layer, this.id)!)) - .round() - .div( - hasUpgrade(this.layer, 234) - ? getBuyableAmount(this.layer, 23)! - .pow(0.3) - .plus(1) - : 1 - ); - }, - display() { - return ( - "Buy a generator for " + format(this.cost!) + " Infinity points" - ); - }, - canAfford() { - return player.layers.i.points.gte(this.cost!) && hasUpgrade("p", 232); - }, - buy() { - if (!hasMilestone("p", 13)) - player.layers.i.points = player.layers.i.points.sub(this.cost!).round(); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - player.layers[this.layer].g = (player.layers[this.layer].g as Decimal).plus(1); - }, - unlocked() { - return hasUpgrade(this.layer, 232); - } - }, - 21: { - cost() { - return new Decimal(20).plus( - getBuyableAmount(this.layer, this.id)!.pow( - new Decimal(2).sub( - new Decimal( - hasUpgrade(this.layer, 221) - ? 0.9 - : hasUpgrade(this.layer, 214) - ? 0.6 - : 0.3 - ).times( - hasUpgrade(this.layer, 212) - ? new Decimal(1).sub( - new Decimal(0.75).pow(getBuyableAmount(this.layer, 22)!) - ) - : 0 - ) - ) - ) - ); - }, - display() { - return ( - "Reset your generators for +1 pointy point! Cost: " + - format(this.cost!) + - " Generators" - ); - }, - canAfford() { - return (player.layers.p.g as Decimal).gte(this.cost!) && hasUpgrade("p", 104); - }, - buy() { - if (!hasMilestone("i", 1)) player.layers.p.g = new Decimal(0); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - if (!hasMilestone("i", 1)) - setBuyableAmount(this.layer, 12, new Decimal(0)); - if (!hasMilestone("i", 1)) - setBuyableAmount(this.layer, 13, new Decimal(0)); - if (!hasMilestone("i", 1)) player.layers.p.gp = new Decimal(0); - }, - unlocked() { - return hasUpgrade(this.layer, 104); - } - }, - 22: { - cost() { - return new Decimal(8).plus(getBuyableAmount(this.layer, this.id)!); - }, - display() { - return ( - "Gain a pointy prestige point. Cost: " + - format(this.cost!) + - " Pointy Points" - ); - }, - canAfford() { - return ( - getBuyableAmount(this.layer, 21)!.gte(this.cost!) && - hasMilestone("i", 5) - ); - }, - buy() { - if (!hasUpgrade(this.layer, 233)) - setBuyableAmount( - this.layer, - 21, - getBuyableAmount(this.layer, 21)!.sub(this.cost!) - ); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return hasMilestone("i", 5); - } - }, - 23: { - cost() { - return new Decimal(124).plus( - getBuyableAmount(this.layer, this.id)! - .times(2) - .pow(2) - ); - }, - display() { - return ( - "Gain a booster. Cost: " + format(this.cost!) + " Pointy Points" - ); - }, - canAfford() { - return ( - getBuyableAmount(this.layer, 21)!.gte(this.cost!) && - hasMilestone("i", 5) - ); - }, - buy() { - if (!hasMilestone(this.layer, 15)) - setBuyableAmount( - this.layer, - 21, - getBuyableAmount(this.layer, 21)!.sub(this.cost!) - ); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - if (!hasMilestone(this.layer, 15)) { - if (!hasMilestone(this.layer, 12)) { - player.layers.p.upgrades = player.layers.p.upgrades!.filter((x: string | Number) => { - return Number(x) < 200 || Number(x) > 230; - }); - if (hasMilestone(this.layer, 11)) { - player.layers.p.upgrades.push(215); - player.layers.p.upgrades.push(225); - player.layers.p.upgrades.push(223); - player.layers.p.upgrades.push(222); - } - } - setBuyableAmount("p", 21, new Decimal(0)); - setBuyableAmount("p", 22, new Decimal(0)); - if (!hasUpgrade("p", 233)) { - setBuyableAmount("p", 12, new Decimal(0)); - setBuyableAmount("p", 13, new Decimal(0)); - setBuyableAmount("p", 14, new Decimal(0)); - - player.layers.p.g = new Decimal(0); - } - player.layers.p.gp = new Decimal(0); - } - }, - unlocked() { - return hasUpgrade("p", 225) || getBuyableAmount("p", 23)!.gt(0); - } - }, - 31: { - cost() { - return new Decimal(1e93) - .times(new Decimal(1.5).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(1.1).pow( - getBuyableAmount(this.layer, this.id)!.pow(2) - ) - ); - }, - effect() { - return new Decimal(2) - .plus(layers.p.buyables!.data[33].effect as Decimal) - .pow( - getBuyableAmount(this.layer, this.id)!.plus( - layers.p.buyables!.data[51].effect as Decimal - ) - ); - }, - display() { - return ( - "Double point gain. \nCurrently: x" + - format(this.effect as Decimal) + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasMilestone("p", 13); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return hasMilestone("p", 13); - } - }, - 32: { - cost() { - return new Decimal(1e95) - .times(new Decimal(2).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(1.01).pow( - getBuyableAmount(this.layer, this.id)!.pow(2) - ) - ); - }, - display() { - return ( - "Double prestige point gain. \nCurrently: x" + - format( - new Decimal(2) - .plus(layers.p.buyables!.data[33].effect as Decimal) - .pow(getBuyableAmount(this.layer, this.id)!) - ) + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasMilestone("p", 13); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return ( - hasMilestone("p", 13) && getBuyableAmount(this.layer, 31)!.gte(5) - ); - } - }, - 33: { - cost() { - return new Decimal(1e100) - .times(new Decimal(10).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(1.01).pow( - getBuyableAmount(this.layer, this.id)!.pow(2) - ) - ); - }, - effect() { - return new Decimal(0.01) - .mul(getBuyableAmount(this.layer, this.id)!) - .times(layers.p.buyables!.data[43].effect as Decimal); - }, - display() { - return ( - "Add 0.01 to the previous 2 buyable bases. \nCurrently: +" + - format(this.effect as Decimal) + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasMilestone("p", 13); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return ( - hasMilestone("p", 13) && - (getBuyableAmount(this.layer, this.id)!.gt(0) || - player.layers.p.points.gte(1e100)) - ); - } - }, - 41: { - cost() { - return new Decimal(1e110) - .times(new Decimal(10).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(10).pow(getBuyableAmount(this.layer, this.id)!.pow(2)) - ); - }, - effect() { - return new Decimal(0.01).mul( - getBuyableAmount(this.layer, this.id)!.plus( - layers.p.buyables!.data[51].effect as Decimal - ) - ); - }, - display() { - return ( - "Add 0.01 to the booster effect base. \nCurrently: +" + - format(this.effect as Decimal) + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasMilestone("p", 13); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return ( - hasMilestone("p", 13) && - (getBuyableAmount(this.layer, this.id)!.gt(0) || - player.layers.p.points.gte(1e110)) - ); - } - }, - 42: { - cost() { - const c = new Decimal(1e270) - .times(new Decimal(2).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(1.01).pow( - getBuyableAmount(this.layer, this.id)!.pow(2) - ) - ); - - return c; - }, - effect() { - let f = new Decimal(1.001).pow( - getBuyableAmount(this.layer, this.id)! - ); - if (f.gte(1.1)) f = f.pow(0.8).times(new Decimal(1.1).pow(0.2)); - if (f.gte(1.35)) f = f.pow(0.5).times(new Decimal(1.35).pow(0.5)); - if (f.gte(3)) f = new Decimal(3); - return f; - }, - display() { - return ( - "Raise point gain to the 1.001 \nCurrently: ^" + - format(this.effect as Decimal) + - ((this.effect as Decimal).eq(3) ? "(hardcapped)" : "") + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return ( - player.layers.p.points.gte(this.cost!) && - hasMilestone("p", 13) && - (this.effect as Decimal).lt(3) - ); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return ( - hasMilestone("p", 13) && - (getBuyableAmount(this.layer, this.id)!.gt(0) || - player.layers.p.points.gte(1e270)) - ); - } - }, - 43: { - cost() { - return new Decimal("1e375") - .times(new Decimal(10).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(10).pow(getBuyableAmount(this.layer, this.id)!.pow(2)) - ); - }, - effect() { - return new Decimal(0.01) - .mul(getBuyableAmount(this.layer, this.id)!) - .plus(1); - }, - display() { - return ( - "Multiply the above buyable effect. \nCurrently: *" + - format(this.effect as Decimal) + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasMilestone("p", 13); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return ( - hasMilestone("p", 13) && - (getBuyableAmount(this.layer, this.id)!.gt(0) || - player.layers.p.points.gte("1e375")) - ); - } - }, - 51: { - cost() { - return new Decimal("1e1740") - .times(new Decimal(10).pow(getBuyableAmount(this.layer, this.id)!)) - .times( - new Decimal(1e10).pow( - getBuyableAmount(this.layer, this.id)!.pow(2) - ) - ); - }, - effect() { - return getBuyableAmount(this.layer, this.id)!.pow(0.55); - }, - display() { - return ( - "Add free levels to the above 2 buyables \nCurrently: " + - format(this.effect as Decimal) + - "\nCost: " + - format(this.cost!) + - " Prestige points" - ); - }, - canAfford() { - return player.layers.p.points.gte(this.cost!) && hasMilestone("p", 13); - }, - buy() { - player.layers.p.points = player.layers.p.points.sub(this.cost!); - setBuyableAmount( - this.layer, - this.id, - getBuyableAmount(this.layer, this.id)!.add(1) - ); - }, - unlocked() { - return ( - hasMilestone("p", 15) && - (getBuyableAmount(this.layer, this.id)!.gt(0) || - player.layers.p.points.gte("1e1700")) - ); - } - } - } - }, - milestones: { - data: { - 0: { - requirementDisplay: "1 reset", - effectDisplay: - "Add 0.01 to base point gain and prestige requirement, and 1 doesn't reset upgrades", - done() { - return getBuyableAmount("p", 11)!.gte(1); - }, - unlocked() { - return layers.p.activeSubtab?.id == "Pointy points"; - } - }, - 1: { - requirementDisplay: "2 resets", - effectDisplay: - "
2 and 3 don't reset upgrades, and start with the first 8 upgrades on reset
", - done() { - return getBuyableAmount("p", 11)!.gte(2); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 2: { - requirementDisplay: "3 resets", - effectDisplay: - "
4 doesn't reset upgrades, and permanently fix the bug where you can't buy upgrades when you have 1 prestige point
", - done() { - return getBuyableAmount("p", 11)!.gte(3); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 3: { - requirementDisplay: "4 resets", - effectDisplay: - "Don't reset challenges, add 1 to Point maximum completions, and start with 24 upgrades", - done() { - return getBuyableAmount("p", 11)!.gte(4); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 4: { - requirementDisplay: "5 resets", - effectDisplay: "Each useless upgrade adds 0.1 to base point gain", - done() { - return getBuyableAmount("p", 11)!.gte(5); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 5: { - requirementDisplay: "6 resets", - effectDisplay: "Unlock something", - done() { - return getBuyableAmount("p", 11)!.gte(6); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 6: { - requirementDisplay: "1 pointy point", - effectDisplay: "Unlock the upgrade tree", - done() { - return getBuyableAmount("p", 21)!.gte(1); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - (hasUpgrade(this.layer, 104) || player.layers.i.unlocked) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 7: { - requirementDisplay: "7 pointy points", - effectDisplay: - "You can now buy both first and second row upgrade tree upgrades", - done() { - return getBuyableAmount("p", 21)!.gte(7); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - (hasUpgrade(this.layer, 111) || player.layers.i.unlocked) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 8: { - requirementDisplay: "8 pointy points", - effectDisplay: "Unlock another layer", - done() { - return getBuyableAmount("p", 21)!.gte(8); - }, - unlocked() { - return ( - hasMilestone(this.layer, Number(this.id) - 1) && - (hasUpgrade(this.layer, 141) || - hasUpgrade(this.layer, 143) || - hasUpgrade(this.layer, 142) || - player.layers.i.unlocked) && - layers.p.activeSubtab?.id == "Pointy points" - ); - } - }, - 11: { - requirementDisplay: "3 boosters", - effectDisplay: "Keep automation on booster reset", - done() { - return getBuyableAmount("p", 23)!.gte(3); - }, - unlocked() { - return ( - getBuyableAmount("p", 23)!.gt(0) || - hasMilestone(this.layer, this.id) - ); - } - }, - 12: { - requirementDisplay: "5 boosters", - effectDisplay: - "Keep all prestige upgrades on booster reset and buy max infinity points", - done() { - return getBuyableAmount("p", 23)!.gte(5); - }, - unlocked() { - return ( - getBuyableAmount("p", 23)!.gt(0) || - hasMilestone(this.layer, this.id) - ); - } - }, - 13: { - requirementDisplay: "10 boosters", - effectDisplay: "Generators cost nothing", - done() { - return getBuyableAmount("p", 23)!.gte(10); - }, - unlocked() { - return ( - getBuyableAmount("p", 23)!.gt(0) || - hasMilestone(this.layer, this.id) - ); - } - }, - 14: { - requirementDisplay: "15 boosters", - effectDisplay: - "Auto buy the first 3 buyables and buy max pointy prestige points", - done() { - return getBuyableAmount("p", 23)!.gte(15); - }, - unlocked() { - return ( - getBuyableAmount("p", 41)!.gt(0) || - hasMilestone(this.layer, this.id) - ); - } - }, - 15: { - requirementDisplay: "20 boosters", - effectDisplay: "Boosters reset nothing and auto booster", - done() { - return getBuyableAmount("p", 23)!.gte(16); - }, - unlocked() { - return ( - getBuyableAmount("p", 41)!.gt(0) || - hasMilestone(this.layer, this.id) - ); - } - } - } - }, - passiveGeneration() { - return hasUpgrade("i", 11) ? 1 : 0; - }, - update(diff) { - if (hasMilestone(this.layer, 2) && !hasUpgrade(this.layer, 54)) { - player.layers[this.layer].upgrades!.push(54); - } - if ( - hasMilestone(this.layer, 1) && - !hasUpgrade(this.layer, 11) && - !hasMilestone(this.layer, 3) - ) { - player.layers[this.layer].upgrades = [11, 12, 13, 14, 21, 22, 23, 24]; - } - if (hasMilestone(this.layer, 3) && !hasUpgrade(this.layer, 31)) { - player.layers[this.layer].upgrades = [ - 11, - 12, - 13, - 14, - 21, - 22, - 23, - 24, - 31, - 32, - 33, - 34, - 41, - 42, - 43, - 44, - 51, - 52, - 53, - 54, - 61, - 62, - 63, - 64 - ]; - } - if (hasMilestone(this.layer, 5)) { - player.layers[this.layer].gp = (player.layers[this.layer].gp as Decimal).plus( - (player.layers.p.g as Decimal).times(diff).times(player.layers.p.geff as Decimal) - ); - } - let geff = new Decimal(1); - if (hasUpgrade("p", 81)) geff = geff.plus(2); - if (hasUpgrade("p", 102)) - geff = geff.plus( - hasChallenge("p", 22) - ? (player.layers.p.gp as Decimal).plus(1).log(10) - : (player.layers.p.gp as Decimal) - .plus(1) - .log(10) - .plus(1) - .log(10) - ); - if (hasUpgrade("p", 83)) - geff = geff.times( - player.layers.p.points - .plus(1) - .log(10) - .plus(1) - ); - if (hasUpgrade("p", 94)) geff = geff.times(player.layers.p.cmult as Decimal); - if (hasUpgrade("p", 104)) - geff = geff.times(new Decimal(player.layers.p.buyables![21]).plus(1)); - if (hasUpgrade("p", 143)) - geff = geff.times(new Decimal(player.timePlayed).div(3600).max(1)); - if (hasUpgrade("p", 225)) - geff = geff.pow( - new Decimal(player.layers.p.buyables![23]) - .div(10) - .mul( - new Decimal(0.1) - .plus(layers.p.buyables!.data[41].effect as Decimal) - .times(10) - ) - .plus(1) - ); - player.layers.p.geff = geff; - if (hasChallenge("p", 22) && (!hasUpgrade("p", 141) || hasUpgrade("i", 12))) - player.layers.p.cmult = (player.layers.p.cmult as Decimal).plus(hasUpgrade("p", 141) ? 1 : 0.01); - if (!hasUpgrade("p", 111)) player.layers.p.cmult = (player.layers.p.cmult as Decimal).min(100); - if (hasMilestone(this.layer, 14)) { - if (layers.p.buyables!.data[31].canAfford) - layers.p.buyables!.data[31].buy(); - if (layers.p.buyables!.data[32].canAfford) - layers.p.buyables!.data[32].buy(); - if (layers.p.buyables!.data[33].canAfford) - layers.p.buyables!.data[33].buy(); - } - if (hasMilestone(this.layer, 15)) { - if (layers.p.buyables!.data[23].canAfford) - layers.p.buyables!.data[23].buy(); - } - }, - subtabs: { - Upgrades: { - display: ` - - - - - - ` - }, - Challenges: { - unlocked() { - return hasUpgrade("p", 51) || hasMilestone("p", 0); - }, - display: ` - - - ` - }, - "Buyables and Milestones": { - unlocked() { - return hasUpgrade("p", 74) || hasMilestone("p", 0); - }, - display: ` - - - - -
Your boosts are making the point challenge {{ getBuyableAmount('p', 11).plus(1) }}x less pointy
- - ` - }, - Generators: { - unlocked() { - return hasMilestone("p", 5) || player.layers.i.points.gte(1); - }, - display: ` - -
You have {{ format(player.layers.p.gp) }} generator points, adding {{ format(hasUpgrade("p",132)?player.layers.p.gp.plus(1).pow(new Decimal(1).div(2)):hasUpgrade("p",101)?player.layers.p.gp.plus(1).pow(new Decimal(1).div(3)):hasUpgrade("p",93)?player.layers.p.gp.plus(1).pow(0.2):player.layers.p.gp.plus(1).log10()) }} to point gain
-
You have {{ format(player.layers.p.g) }} generators, generating {{ format(player.layers.p.g.times(player.layers.p.geff)) }} generator points per second
-
Generator efficiency is {{ format(player.layers.p.geff) }}
- - - - ` - }, - "Pointy Points": { - unlocked() { - return hasUpgrade("p", 104) || player.layers.i.points.gte(1); - }, - display: ` -
{{ format(player.layers.p.buyables![21]) }} pointy points
-
My pointy points are multiplying generator efficiency by {{ format(new Decimal(player.layers.p.buyables![21]).plus(1)) }}
- - - -
I have {{ format(player.layers.p.buyables![22]) }} pointy prestige points
- - - - -
I have {{ format(player.layers.p.buyables![23]) }} pointy boosters!
- -
My pointy boosters are raising generator efficiency to the ^{{ format(new Decimal(player.layers.p.buyables![23]).div(10).mul(new Decimal(0.1).plus(layers.p.buyables[41].effect).times(10)).plus(1)) }}
- - -
Booster upgrades
- ` - }, - Buyables: { - unlocked() { - return hasMilestone("p", 13); - }, - display: ` - - ` - } - } -} as RawLayer; diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts new file mode 100644 index 0000000..0206502 --- /dev/null +++ b/src/data/layers/main.ts @@ -0,0 +1,11 @@ +import { RawLayer } from "@/typings/layer"; + +export default { + id: "main", + display: ` +
Game Paused
+
Dev Speed: {{ format(player.devSpeed) }}x
+
TODO: Board
+ `, + minimizable: false +} as RawLayer; diff --git a/src/data/mod.ts b/src/data/mod.ts index 6dfbc4e..1c3ef96 100644 --- a/src/data/mod.ts +++ b/src/data/mod.ts @@ -1,97 +1,13 @@ -import { layers } from "@/game/layers"; -import player from "@/game/player"; import { RawLayer } from "@/typings/layer"; import { PlayerData } from "@/typings/player"; import Decimal from "@/util/bignum"; -import { - getBuyableAmount, - hasMilestone, - hasUpgrade, - inChallenge, - upgradeEffect -} from "@/util/features"; import { computed } from "vue"; -import a from "./layers/aca/a"; -import c from "./layers/aca/c"; -import f from "./layers/aca/f"; -import demoLayer from "./layers/demo"; -import demoInfinityLayer from "./layers/demo-infinity"; - -// Import initial layers - -const g = { - id: "g", - symbol: "TH", - branches: ["c"], - color: "#6d3678", - shown: true, - canClick() { - return player.points.gte(10); - }, - tooltip: "Thanos your points", - click() { - player.points = player.points.div(2); - console.log(this.layer); - } -} as RawLayer; -const h = { - id: "h", - branches: [ - "g", - () => ({ - target: "flatBoi", - featureType: "bar", - endOffset: { - x: - -50 + - 100 * - (layers.c.bars!.data.flatBoi.progress instanceof Number - ? (layers.c.bars!.data.flatBoi.progress as number) - : (layers.c.bars!.data.flatBoi.progress as Decimal).toNumber()) - } - }) - ], - tooltip() { - return "Restore your points to {{ player.c.otherThingy }}"; - }, - row: "side", - position: 3, - canClick() { - return player.points.lt(player.layers.c.otherThingy as Decimal); - }, - click() { - player.points = new Decimal(player.layers.c.otherThingy as Decimal); - } -} as RawLayer; -const spook = { - id: "spook", - row: 1, - layerShown: "ghost" -} as RawLayer; - -const main = { - id: "main", - display: ` -
Game Paused
-
Dev Speed: {{ format(player.devSpeed) }}x
-
Offline Time: {{ formatTime(player.offTime.remain) }}
-
- You have -

{{ format(player.points) }}

- points -
-
- ({{ player.oompsMag != 0 ? format(player.oomps) + " OOM" + (player.oompsMag < 0 ? "^OOM" : player.oompsMag > 1 ? "^" + player.oompsMag : "") + "s" : formatSmall(pointGain) }}/sec) -
- - `, - name: "Tree" -} as RawLayer; +import main from "./layers/main"; export const getInitialLayers = ( /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ playerData: Partial -): Array => [main, f, c, a, g, h, spook, demoLayer, demoInfinityLayer]; +): Array => [main]; export function getStartingData(): Record { return { @@ -104,73 +20,7 @@ export const hasWon = computed(() => { }); export const pointGain = computed(() => { - if (!hasUpgrade("c", 11)) return new Decimal(0); - let gain = new Decimal(3.19); - if (hasUpgrade("c", 12)) gain = gain.times(upgradeEffect("c", 12) as Decimal); - if (hasMilestone("p", 0)) gain = gain.plus(0.01); - if (hasMilestone("p", 4)) { - if (hasUpgrade("p", 12)) gain = gain.plus(0.1); - if (hasUpgrade("p", 13)) gain = gain.plus(0.1); - if (hasUpgrade("p", 14)) gain = gain.plus(0.1); - if (hasUpgrade("p", 21)) gain = gain.plus(0.1); - if (hasUpgrade("p", 22)) gain = gain.plus(0.1); - if (hasUpgrade("p", 23)) gain = gain.plus(0.1); - if (hasUpgrade("p", 31)) gain = gain.plus(0.1); - if (hasUpgrade("p", 32)) gain = gain.plus(0.1); - if (hasUpgrade("p", 33)) gain = gain.plus(0.1); - } - if (hasUpgrade("p", 11)) - gain = gain.plus( - hasUpgrade("p", 34) - ? new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal) - : 1 - ); - if (hasUpgrade("p", 12)) - gain = gain.times( - hasUpgrade("p", 34) - ? new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal) - : 1 - ); - if (hasUpgrade("p", 13)) - gain = gain.pow( - hasUpgrade("p", 34) - ? new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal) - : 1 - ); - if (hasUpgrade("p", 14)) - gain = gain.tetrate( - hasUpgrade("p", 34) - ? new Decimal(1).plus(layers.p.upgrades!.data[34].effect as Decimal).toNumber() - : 1 - ); - - if (hasUpgrade("p", 71)) gain = gain.plus(1.1); - if (hasUpgrade("p", 72)) gain = gain.times(1.1); - if (hasUpgrade("p", 73)) gain = gain.pow(1.1); - if (hasUpgrade("p", 74)) gain = gain.tetrate(1.1); - if (hasMilestone("p", 5) && !inChallenge("p", 22)) { - const asdf = hasUpgrade("p", 132) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(2)) - : hasUpgrade("p", 101) - ? (player.layers.p.gp as Decimal).plus(1).pow(new Decimal(1).div(3)) - : hasUpgrade("p", 93) - ? (player.layers.p.gp as Decimal).plus(1).pow(0.2) - : (player.layers.p.gp as Decimal).plus(1).log10(); - gain = gain.plus(asdf); - if (hasUpgrade("p", 213)) gain = gain.mul(asdf.plus(1)); - } - if (hasUpgrade("p", 104)) gain = gain.times(player.layers.p.points.plus(1).pow(0.5)); - if (hasUpgrade("p", 142)) gain = gain.times(5); - if (player.layers.i.unlocked) - gain = gain.times(player.layers.i.points.plus(1).pow(hasUpgrade("p", 235) ? 6.942 : 1)); - if (inChallenge("p", 11) || inChallenge("p", 21)) - gain = new Decimal(10).pow(gain.log10().pow(0.75)); - if (inChallenge("p", 12) || inChallenge("p", 21)) - gain = gain.pow(new Decimal(1).sub(new Decimal(1).div(getBuyableAmount("p", 11)!.plus(1)))); - if (hasUpgrade("p", 211)) gain = gain.times(getBuyableAmount("p", 21)!.plus(1)); - if (hasMilestone("p", 13)) gain = gain.times(layers.p.buyables!.data[31].effect as Decimal); - if (hasMilestone("p", 13)) gain = gain.pow(layers.p.buyables!.data[42].effect as Decimal); - return gain; + return new Decimal(0); }); /* eslint-disable @typescript-eslint/no-unused-vars */ diff --git a/src/data/modInfo.json b/src/data/modInfo.json index 8a6d164..42c9ed0 100644 --- a/src/data/modInfo.json +++ b/src/data/modInfo.json @@ -1,6 +1,6 @@ { - "title": "The Modding Tree X", - "id": "tmt-x", + "title": "Side Project", + "id": "side-project", "author": "thepaperpilot", "discordName": "The Paper Pilot Community", "discordLink": "https://discord.gg/WzejVAx", @@ -14,8 +14,8 @@ "useHeader": true, "banner": null, "logo": null, - "initialTabs": [ "main", "c" ], + "initialTabs": [ "main" ], "maxTickLength": 3600, - "offlineLimit": 1 + "offlineLimit": 0 } From 78ca3713a19bfb600f1e43b05ecbb5bd03cdd219 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 17 Aug 2021 18:39:11 -0500 Subject: [PATCH 02/49] Added type predicate to setDefault --- src/game/layers.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/game/layers.ts b/src/game/layers.ts index 2ce627a..c4c9783 100644 --- a/src/game/layers.ts +++ b/src/game/layers.ts @@ -96,7 +96,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { RawGridFeatures, Upgrade>, GridFeatures, Upgrade - >(layer.id, layer.upgrades!); + >(layer.id, layer.upgrades); setRowCol(layer.upgrades); for (const id in layer.upgrades.data) { layer.upgrades.data[id].bought = function() { @@ -193,7 +193,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { RawGridFeatures, Achievement>, GridFeatures, Achievement - >(layer.id, layer.achievements!); + >(layer.id, layer.achievements); setRowCol(layer.achievements); for (const id in layer.achievements.data) { layer.achievements.data[id].earned = function() { @@ -461,8 +461,8 @@ export function addLayer(layer: RawLayer, player?: Partial): void { ); }; setDefault(player, "subtabs", {}); - setDefault(player.subtabs!, layer.id, {}); - setDefault(player.subtabs![layer.id], "mainTabs", Object.keys(layer.subtabs)[0]); + setDefault(player.subtabs, layer.id, {}); + setDefault(player.subtabs[layer.id], "mainTabs", Object.keys(layer.subtabs)[0]); for (const id in layer.subtabs) { layer.subtabs[id].active = function() { return playerProxy.subtabs[this.layer].mainTabs === this.id; @@ -471,7 +471,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } if (layer.microtabs) { setDefault(player, "subtabs", {}); - setDefault(player.subtabs!, layer.id, {}); + setDefault(player.subtabs, layer.id, {}); for (const family in layer.microtabs) { if (Object.keys(layer.microtabs[family]).length === 0) { console.warn( @@ -497,7 +497,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { return firstUnlocked != undefined ? this[firstUnlocked] : undefined; }; setDefault( - player.subtabs![layer.id], + player.subtabs[layer.id], family, Object.keys(layer.microtabs[family]).find(tab => tab !== "activeMicrotab")! ); @@ -594,7 +594,12 @@ function setupFeatures, R extends Features, S ext } } -function setDefault(object: T, key: K, value: T[K], forceCached?: boolean) { +function setDefault( + object: T, + key: K, + value: T[K], + forceCached?: boolean +): asserts object is Exclude & Required> { if (object[key] == undefined && value != undefined) { object[key] = value; } From 6e1536930e11020281d34310b6fca726cf87968f Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 17 Aug 2021 22:30:49 -0500 Subject: [PATCH 03/49] Made setupFeatures use more accurate types --- src/game/layers.ts | 41 ++++++++++++++++++++--------------------- src/typings/layer.d.ts | 4 ++-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/game/layers.ts b/src/game/layers.ts index c4c9783..ccf4292 100644 --- a/src/game/layers.ts +++ b/src/game/layers.ts @@ -92,11 +92,10 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.upgrades) { - setupFeatures< - RawGridFeatures, Upgrade>, - GridFeatures, - Upgrade - >(layer.id, layer.upgrades); + setupFeatures, NonNullable, Upgrade>( + layer.id, + layer.upgrades + ); setRowCol(layer.upgrades); for (const id in layer.upgrades.data) { layer.upgrades.data[id].bought = function() { @@ -190,8 +189,8 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } if (layer.achievements) { setupFeatures< - RawGridFeatures, Achievement>, - GridFeatures, + NonNullable, + NonNullable, Achievement >(layer.id, layer.achievements); setRowCol(layer.achievements); @@ -209,8 +208,8 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } if (layer.challenges) { setupFeatures< - RawGridFeatures, Challenge>, - GridFeatures, + NonNullable, + NonNullable, Challenge >(layer.id, layer.challenges); setRowCol(layer.challenges); @@ -301,11 +300,10 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.buyables) { - setupFeatures< - RawGridFeatures, Buyable>, - GridFeatures, - Buyable - >(layer.id, layer.buyables); + setupFeatures, NonNullable, Buyable>( + layer.id, + layer.buyables + ); setRowCol(layer.buyables); setDefault(layer.buyables, "respec", undefined, false); setDefault( @@ -353,8 +351,8 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } if (layer.clickables) { setupFeatures< - RawGridFeatures, Clickable>, - GridFeatures, + NonNullable, + NonNullable, Clickable >(layer.id, layer.clickables); setRowCol(layer.clickables); @@ -375,10 +373,11 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.milestones) { - setupFeatures, Milestone>, Features, Milestone>( - layer.id, - layer.milestones - ); + setupFeatures< + NonNullable, + NonNullable, + Milestone + >(layer.id, layer.milestones); for (const id in layer.milestones.data) { layer.milestones.data[id].earned = function() { return ( @@ -416,7 +415,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.grids) { - setupFeatures, Grid>, Features, Grid>( + setupFeatures, NonNullable, Grid>( layer.id, layer.grids ); diff --git a/src/typings/layer.d.ts b/src/typings/layer.d.ts index a03bd14..9059174 100644 --- a/src/typings/layer.d.ts +++ b/src/typings/layer.d.ts @@ -37,7 +37,7 @@ export interface RawLayer extends RawFeature { subtabs?: Record>; microtabs?: Record; upgrades?: RawGridFeatures, Upgrade>; - startData?: () => Record; + startData?: () => Record; } export interface Layer extends Feature { @@ -115,7 +115,7 @@ export interface Layer extends Feature { activeSubtab?: Subtab | undefined; microtabs?: Record; upgrades?: GridFeatures; - startData?: () => Record; + startData?: () => Record; click?: () => void; automate?: () => void; reset: (force?: boolean) => void; From c8651adb6b5d29af7e8ef9f1d58822b5fd143862 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Wed, 18 Aug 2021 00:18:23 -0500 Subject: [PATCH 04/49] cleaned up setupFeatures --- src/components/tree/Tree.vue | 40 ++++++++---------- src/game/layers.ts | 67 +++++++++++-------------------- src/typings/features/feature.d.ts | 6 +-- 3 files changed, 43 insertions(+), 70 deletions(-) diff --git a/src/components/tree/Tree.vue b/src/components/tree/Tree.vue index 3a522ef..770135f 100644 --- a/src/components/tree/Tree.vue +++ b/src/components/tree/Tree.vue @@ -44,7 +44,7 @@ export default defineComponent({ }; }, props: { - nodes: Object as PropType>>, + nodes: Object as PropType>>, append: Boolean }, inject: ["tab"], @@ -55,31 +55,25 @@ export default defineComponent({ } return layers[this.modal].name || this.modal; }, - rows(): Record> { + rows(): Record> { if (this.nodes != undefined) { return this.nodes; } - const rows = Object.keys(layers).reduce( - (acc: Record>, curr) => { - if (!(layers[curr].displayRow in acc)) { - acc[layers[curr].displayRow] = []; - } - if (layers[curr].position != undefined) { - acc[layers[curr].displayRow][layers[curr].position!] = curr; - } else { - acc[layers[curr].displayRow].push(curr); - } - return acc; - }, - {} - ); - return Object.keys(rows).reduce( - (acc: Record>, curr) => { - acc[curr] = rows[curr].filter(layer => layer); - return acc; - }, - {} - ); + const rows = Object.keys(layers).reduce((acc: Record>, curr) => { + if (!(layers[curr].displayRow in acc)) { + acc[layers[curr].displayRow] = []; + } + if (layers[curr].position != undefined) { + acc[layers[curr].displayRow][layers[curr].position!] = curr; + } else { + acc[layers[curr].displayRow].push(curr); + } + return acc; + }, {}); + return Object.keys(rows).reduce((acc: Record>, curr) => { + acc[curr] = rows[curr].filter(layer => layer); + return acc; + }, {}); } }, methods: { diff --git a/src/game/layers.ts b/src/game/layers.ts index ccf4292..41c688e 100644 --- a/src/game/layers.ts +++ b/src/game/layers.ts @@ -58,7 +58,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { layer = clone(layer); setDefault(player, "layers", {}); - player.layers![layer.id] = applyPlayerData( + player.layers[layer.id] = applyPlayerData( { points: new Decimal(0), unlocked: false, @@ -74,7 +74,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { confirmRespecBuyables: false, ...(layer.startData?.() || {}) }, - player.layers![layer.id] + player.layers[layer.id] ); // Set default property values @@ -92,10 +92,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.upgrades) { - setupFeatures, NonNullable, Upgrade>( - layer.id, - layer.upgrades - ); + setupFeatures, Upgrade>(layer.id, layer.upgrades); setRowCol(layer.upgrades); for (const id in layer.upgrades.data) { layer.upgrades.data[id].bought = function() { @@ -188,11 +185,10 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.achievements) { - setupFeatures< - NonNullable, - NonNullable, - Achievement - >(layer.id, layer.achievements); + setupFeatures, Achievement>( + layer.id, + layer.achievements + ); setRowCol(layer.achievements); for (const id in layer.achievements.data) { layer.achievements.data[id].earned = function() { @@ -207,11 +203,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.challenges) { - setupFeatures< - NonNullable, - NonNullable, - Challenge - >(layer.id, layer.challenges); + setupFeatures, Challenge>(layer.id, layer.challenges); setRowCol(layer.challenges); layer.activeChallenge = function() { return Object.values(this.challenges!.data).find( @@ -300,10 +292,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.buyables) { - setupFeatures, NonNullable, Buyable>( - layer.id, - layer.buyables - ); + setupFeatures, Buyable>(layer.id, layer.buyables); setRowCol(layer.buyables); setDefault(layer.buyables, "respec", undefined, false); setDefault( @@ -350,11 +339,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.clickables) { - setupFeatures< - NonNullable, - NonNullable, - Clickable - >(layer.id, layer.clickables); + setupFeatures, Clickable>(layer.id, layer.clickables); setRowCol(layer.clickables); setDefault(layer.clickables, "masterButtonClick", undefined, false); if (layer.clickables.masterButtonDisplay != undefined) { @@ -373,11 +358,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.milestones) { - setupFeatures< - NonNullable, - NonNullable, - Milestone - >(layer.id, layer.milestones); + setupFeatures, Milestone>(layer.id, layer.milestones); for (const id in layer.milestones.data) { layer.milestones.data[id].earned = function() { return ( @@ -415,12 +396,9 @@ export function addLayer(layer: RawLayer, player?: Partial): void { } } if (layer.grids) { - setupFeatures, NonNullable, Grid>( - layer.id, - layer.grids - ); + setupFeatures, Grid>(layer.id, layer.grids); for (const id in layer.grids.data) { - setDefault(player.layers![layer.id].grids, id, {}); + setDefault(player.layers[layer.id].grids, id, {}); layer.grids.data[id].getData = function(cell): State { if (playerProxy.layers[this.layer].grids[id][cell] != undefined) { return playerProxy.layers[this.layer].grids[id][cell]; @@ -578,17 +556,18 @@ function setRowCol, S extends Feature>(features: RawGr features.cols = maxCol; } -function setupFeatures, R extends Features, S extends Feature>( - layer: string, - features: T -) { +function setupFeatures< + T extends RawFeatures, + S extends Feature, + R extends Features = Features +>(layer: string, features: T) { features.layer = layer; for (const id in features.data) { const feature = features.data[id]; - (feature as Feature).id = id; - (feature as Feature).layer = layer; - if (feature.unlocked == undefined) { - (feature as Feature).unlocked = true; + (feature as S).id = id; + (feature as S).layer = layer; + if ((feature as S).unlocked == undefined) { + (feature as S).unlocked = true; } } } @@ -599,7 +578,7 @@ function setDefault( value: T[K], forceCached?: boolean ): asserts object is Exclude & Required> { - if (object[key] == undefined && value != undefined) { + if (object[key] === undefined && value != undefined) { object[key] = value; } if (object[key] != undefined && isFunction(object[key]) && forceCached != undefined) { diff --git a/src/typings/features/feature.d.ts b/src/typings/features/feature.d.ts index 4fa74ea..d1eb6a8 100644 --- a/src/typings/features/feature.d.ts +++ b/src/typings/features/feature.d.ts @@ -9,16 +9,16 @@ export interface Feature { [key: string]: unknown; } -export interface RawFeatures, S extends Feature> +export interface RawFeatures, S extends Feature, R = RawFeature> extends Partial, "data">>, ThisType { layer?: string; - data: Record>; + data: Record; } export interface Features { layer: string; - data: Record; + data: Record; [key: string]: unknown; } From d47ce3525d9895c52966a66c995cb1bb5e9bd1b7 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 19 Aug 2021 00:25:49 -0500 Subject: [PATCH 05/49] Implemented most of the basic features for new Board component --- package-lock.json | 83 ++++++++++++ package.json | 1 + src/components/board/Board.vue | 80 ++++++++++++ src/components/board/BoardNode.vue | 203 +++++++++++++++++++++++++++++ src/components/index.ts | 2 + src/game/enums.ts | 5 + src/game/layers.ts | 29 +++++ src/typings/features/board.d.ts | 45 +++++++ src/typings/layer.d.ts | 4 + src/typings/player.d.ts | 18 +-- src/typings/theme.d.ts | 14 +- src/util/layers.ts | 15 +++ src/util/proxies.ts | 1 - 13 files changed, 490 insertions(+), 10 deletions(-) create mode 100644 src/components/board/Board.vue create mode 100644 src/components/board/BoardNode.vue create mode 100644 src/typings/features/board.d.ts diff --git a/package-lock.json b/package-lock.json index 82536ac..b496392 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "vue": "^3.2.2", "vue-class-component": "^8.0.0-rc.1", "vue-next-select": "^2.9.0", + "vue-panzoom": "^1.1.6", "vue-sortable": "github:Netbel/vue-sortable#master-fix", "vue-textarea-autosize": "^1.1.1", "vue-transition-expand": "^0.1.0" @@ -14925,6 +14926,14 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "node_modules/amator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz", + "integrity": "sha1-CMa2C8k67Cthu/wMTWd9MDI8wPE=", + "dependencies": { + "bezier-easing": "^2.0.3" + } + }, "node_modules/ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", @@ -15495,6 +15504,11 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha1-wE3+i5JtbsrKGBPWn/F5t8ICXYY=" + }, "node_modules/bfj": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", @@ -22071,6 +22085,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ngraph.events": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.1.tgz", + "integrity": "sha512-D4C+nXH/RFxioGXQdHu8ELDtC6EaCiNsZtih0IvyGN81OZSUby4jXoJ5+RNWasfsd0FnKxxpAROyUMzw64QNsw==" + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -22736,6 +22755,16 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, + "node_modules/panzoom": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.2.tgz", + "integrity": "sha512-sQLr0t6EmNFXpZHag0HQVtOKqF9xjF7iZdgWg3Ss1o7uh2QZLvcrz7S0Cl8M0d2TkPZ69JfPJdknXN3I0e/2aQ==", + "dependencies": { + "amator": "^1.1.0", + "ngraph.events": "^1.2.1", + "wheel": "^1.0.0" + } + }, "node_modules/parallel-transform": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", @@ -27245,6 +27274,14 @@ "vue": "^3.0.0" } }, + "node_modules/vue-panzoom": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/vue-panzoom/-/vue-panzoom-1.1.6.tgz", + "integrity": "sha512-yEE60C/gnc5NGL6YBD++CErD820va7fkBJE5dCWZZzXX2aMGklj/UKmtqu1u5xDkuOIjnGUr412LNHwOOE711w==", + "dependencies": { + "panzoom": "^9.4.1" + } + }, "node_modules/vue-sortable": { "version": "0.1.3", "resolved": "git+ssh://git@github.com/Netbel/vue-sortable.git#f4d4870ace71ea59bd79252eb2ec1cf6bfb02fe7", @@ -28083,6 +28120,11 @@ "node": ">=0.8.0" } }, + "node_modules/wheel": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wheel/-/wheel-1.0.0.tgz", + "integrity": "sha512-XiCMHibOiqalCQ+BaNSwRoZ9FDTAvOsXxGHXChBugewDj7HC8VBIER71dEOiRH1fSdLbRCQzngKTSiZ06ZQzeA==" + }, "node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -31140,6 +31182,14 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "amator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz", + "integrity": "sha1-CMa2C8k67Cthu/wMTWd9MDI8wPE=", + "requires": { + "bezier-easing": "^2.0.3" + } + }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", @@ -31576,6 +31626,11 @@ "tweetnacl": "^0.14.3" } }, + "bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha1-wE3+i5JtbsrKGBPWn/F5t8ICXYY=" + }, "bfj": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", @@ -36803,6 +36858,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "ngraph.events": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.1.tgz", + "integrity": "sha512-D4C+nXH/RFxioGXQdHu8ELDtC6EaCiNsZtih0IvyGN81OZSUby4jXoJ5+RNWasfsd0FnKxxpAROyUMzw64QNsw==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -37323,6 +37383,16 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, + "panzoom": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.2.tgz", + "integrity": "sha512-sQLr0t6EmNFXpZHag0HQVtOKqF9xjF7iZdgWg3Ss1o7uh2QZLvcrz7S0Cl8M0d2TkPZ69JfPJdknXN3I0e/2aQ==", + "requires": { + "amator": "^1.1.0", + "ngraph.events": "^1.2.1", + "wheel": "^1.0.0" + } + }, "parallel-transform": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", @@ -41002,6 +41072,14 @@ "integrity": "sha512-GjX4pHqZXXitquDeSAtLaf85jXdMUOKyCNzo+EF3xRr4DebGwbST4CtmRvL0TX3EhwLHQjUlAc3JcJX+azpLHg==", "requires": {} }, + "vue-panzoom": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/vue-panzoom/-/vue-panzoom-1.1.6.tgz", + "integrity": "sha512-yEE60C/gnc5NGL6YBD++CErD820va7fkBJE5dCWZZzXX2aMGklj/UKmtqu1u5xDkuOIjnGUr412LNHwOOE711w==", + "requires": { + "panzoom": "^9.4.1" + } + }, "vue-sortable": { "version": "git+ssh://git@github.com/Netbel/vue-sortable.git#f4d4870ace71ea59bd79252eb2ec1cf6bfb02fe7", "from": "vue-sortable@github:Netbel/vue-sortable#master-fix", @@ -41687,6 +41765,11 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "wheel": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wheel/-/wheel-1.0.0.tgz", + "integrity": "sha512-XiCMHibOiqalCQ+BaNSwRoZ9FDTAvOsXxGHXChBugewDj7HC8VBIER71dEOiRH1fSdLbRCQzngKTSiZ06ZQzeA==" + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index e65641f..d09e8ea 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "vue": "^3.2.2", "vue-class-component": "^8.0.0-rc.1", "vue-next-select": "^2.9.0", + "vue-panzoom": "^1.1.6", "vue-sortable": "github:Netbel/vue-sortable#master-fix", "vue-textarea-autosize": "^1.1.1", "vue-transition-expand": "^0.1.0" diff --git a/src/components/board/Board.vue b/src/components/board/Board.vue new file mode 100644 index 0000000..f490b60 --- /dev/null +++ b/src/components/board/Board.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue new file mode 100644 index 0000000..bec3081 --- /dev/null +++ b/src/components/board/BoardNode.vue @@ -0,0 +1,203 @@ + + + + + diff --git a/src/components/index.ts b/src/components/index.ts index 9619597..408338f 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -6,6 +6,7 @@ import VueTextareaAutosize from "vue-textarea-autosize"; import Sortable from "vue-sortable"; import VueNextSelect from "vue-next-select"; import "vue-next-select/dist/index.css"; +import panZoom from "vue-panzoom"; import { App } from "vue"; export function registerComponents(vue: App): void { @@ -23,4 +24,5 @@ export function registerComponents(vue: App): void { vue.use(VueTextareaAutosize); vue.use(Sortable); vue.component("vue-select", VueNextSelect); + vue.use(panZoom); } diff --git a/src/game/enums.ts b/src/game/enums.ts index f175079..a9047d3 100644 --- a/src/game/enums.ts +++ b/src/game/enums.ts @@ -28,3 +28,8 @@ export enum ImportingStatus { WrongID = "WRONG_ID", Force = "FORCE" } + +export enum ProgressDisplay { + Outline = "Outline", + Fill = "Fill" +} diff --git a/src/game/layers.ts b/src/game/layers.ts index 41c688e..d20d094 100644 --- a/src/game/layers.ts +++ b/src/game/layers.ts @@ -1,5 +1,6 @@ import { CacheableFunction } from "@/typings/cacheableFunction"; import { Achievement } from "@/typings/features/achievement"; +import { Board } from "@/typings/features/board"; import { Buyable } from "@/typings/features/buyable"; import { Challenge } from "@/typings/features/challenge"; import { Clickable } from "@/typings/features/clickable"; @@ -23,6 +24,7 @@ import Decimal, { DecimalSource } from "@/util/bignum"; import { isFunction } from "@/util/common"; import { defaultLayerProperties, + getStartingBoards, getStartingBuyables, getStartingChallenges, getStartingClickables, @@ -32,6 +34,7 @@ import { createGridProxy, createLayerProxy } from "@/util/proxies"; import { applyPlayerData } from "@/util/save"; import clone from "lodash.clonedeep"; import { isRef } from "vue"; +import { ProgressDisplay } from "./enums"; import { default as playerProxy } from "./player"; export const layers: Record> = {}; @@ -70,6 +73,7 @@ export function addLayer(layer: RawLayer, player?: Partial): void { buyables: getStartingBuyables(layer.buyables?.data), clickables: getStartingClickables(layer.clickables?.data), challenges: getStartingChallenges(layer.challenges?.data), + boards: getStartingBoards(layer.boards?.data), grids: {}, confirmRespecBuyables: false, ...(layer.startData?.() || {}) @@ -423,6 +427,31 @@ export function addLayer(layer: RawLayer, player?: Partial): void { layer.grids.data[id] = createGridProxy(layer.grids.data[id]) as Grid; } } + if (layer.boards) { + setupFeatures, Board>(layer.id, layer.boards); + for (const id in layer.boards.data) { + setDefault(layer.boards.data[id], "width", "100%"); + setDefault(layer.boards.data[id], "height", "400px"); + for (const nodeType in layer.boards.data[id].types) { + layer.boards.data[id].types[nodeType].layer = layer.id; + layer.boards.data[id].types[nodeType].id = id; + layer.boards.data[id].types[nodeType].type = nodeType; + setDefault(layer.boards.data[id].types[nodeType], "size", 50); + setDefault(layer.boards.data[id].types[nodeType], "draggable", false); + setDefault(layer.boards.data[id].types[nodeType], "canAccept", false); + setDefault( + layer.boards.data[id].types[nodeType], + "progressDisplay", + ProgressDisplay.Fill + ); + setDefault(layer.boards.data[id].types[nodeType], "nodes", function() { + return playerProxy.layers[this.layer].boards[this.id].filter( + node => node.type === this.type + ); + }); + } + } + } if (layer.subtabs) { layer.activeSubtab = function() { if ( diff --git a/src/typings/features/board.d.ts b/src/typings/features/board.d.ts new file mode 100644 index 0000000..520411e --- /dev/null +++ b/src/typings/features/board.d.ts @@ -0,0 +1,45 @@ +import { State } from "../state"; +import { Feature, RawFeature } from "./feature"; + +export interface BoardNode { + position: { + x: number; + y: number; + }; + type: string; + data?: State; +} + +export interface CardOption { + text: string; + selected: (node: BoardNode) => void; +} + +export interface Board extends Feature { + startNodes: () => BoardNode[]; + style?: Partial; + height: string; + width: string; + types: Record; +} + +export type RawBoard = Omit, "types"> & { + startNodes: () => BoardNode[]; + types: Record>; +}; + +export interface NodeType extends Feature { + tooltip?: string | ((node: BoardNode) => string); + title: string | ((node: BoardNode) => string); + size: number | ((node: BoardNode) => number); + draggable: boolean | ((node: BoardNode) => boolean); + canAccept: boolean | ((node: BoardNode, otherNode: BoardNode) => boolean); + progress?: number | ((node: BoardNode) => number); + progressDisplay: ProgressDisplay | ((node: BoardNode) => ProgressDisplay); + progressColor: string | ((node: BoardNode) => string); + fillColor?: string | ((node: BoardNode) => string); + outlineColor?: string | ((node: BoardNode) => string); + titleColor?: string | ((node: BoardNode) => string); + onClick: (node: BoardNode) => void; + nodes: BoardNode[]; +} diff --git a/src/typings/layer.d.ts b/src/typings/layer.d.ts index 9059174..9dfd56a 100644 --- a/src/typings/layer.d.ts +++ b/src/typings/layer.d.ts @@ -3,6 +3,7 @@ import Decimal, { DecimalSource } from "@/util/bignum"; import { CoercableComponent } from "./component"; import { Achievement } from "./features/achievement"; import { Bar } from "./features/bar"; +import { Board, RawBoard } from "./features/board"; import { Buyable } from "./features/buyable"; import { Challenge } from "./features/challenge"; import { Clickable } from "./features/clickable"; @@ -31,6 +32,7 @@ export interface RawLayer extends RawFeature { challenges?: RawGridFeatures, Challenge>; clickables?: RawGridFeatures, Clickable>; grids?: RawFeatures, Grid>; + boards?: RawFeatures, Board, RawBoard>; hotkeys?: RawFeature[]; infoboxes?: RawFeatures, Infoboxe>; milestones?: RawFeatures, Milestone>; @@ -108,6 +110,7 @@ export interface Layer extends Feature { showMasterButton?: boolean; }; grids?: Features; + boards?: Features; hotkeys?: Hotkey[]; infoboxes?: Features; milestones?: Features; @@ -142,5 +145,6 @@ export interface ComponentStyles { "prestige-button"?: Partial; "respec-button"?: Partial; upgrade?: Partial; + board?: Partial; "tab-button"?: Partial; } diff --git a/src/typings/player.d.ts b/src/typings/player.d.ts index f45c2cc..b75d2f3 100644 --- a/src/typings/player.d.ts +++ b/src/typings/player.d.ts @@ -1,6 +1,7 @@ import { Themes } from "@/data/themes"; import { DecimalSource } from "@/lib/break_eternity"; import Decimal from "@/util/bignum"; +import { BoardNode } from "./features/board"; import { MilestoneDisplay } from "./features/milestone"; import { State } from "./state"; @@ -53,14 +54,15 @@ export interface LayerSaveData { unlockOrder?: number; forceTooltip?: boolean; resetTime: Decimal; - upgrades: Array; - achievements: Array; - milestones: Array; - infoboxes: Record; - buyables: Record; - clickables: Record; - challenges: Record; - grids: Record>; + upgrades: Array; + achievements: Array; + milestones: Array; + infoboxes: Record; + buyables: Record; + clickables: Record; + challenges: Record; + grids: Record>; + boards: Record>; confirmRespecBuyables: boolean; [index: string]: unknown; } diff --git a/src/typings/theme.d.ts b/src/typings/theme.d.ts index d05ddbb..b3236e4 100644 --- a/src/typings/theme.d.ts +++ b/src/typings/theme.d.ts @@ -1,6 +1,18 @@ export interface Theme { variables: { - [index: string]: string; + "--background": string; + "--background-tooltip": string; + "--secondary-background": string; + "--color": string; + "--points": string; + "--locked": string; + "--bought": string; + "--link": string; + "--separator": string; + "--border-radius": string; + "--danger": string; + "--modal-border": string; + "--feature-margin": string; }; stackedInfoboxes: boolean; floatingTabs: boolean; diff --git a/src/util/layers.ts b/src/util/layers.ts index 5bbb2e2..519ca43 100644 --- a/src/util/layers.ts +++ b/src/util/layers.ts @@ -1,6 +1,7 @@ import { hotkeys, layers } from "@/game/layers"; import player from "@/game/player"; import { CacheableFunction } from "@/typings/cacheableFunction"; +import { Board, BoardNode, RawBoard } from "@/typings/features/board"; import { Buyable } from "@/typings/features/buyable"; import { Challenge } from "@/typings/features/challenge"; import { Clickable } from "@/typings/features/clickable"; @@ -70,6 +71,20 @@ export function getStartingChallenges( : {}; } +export function getStartingBoards( + boards?: Record | Record | undefined +): Record> { + return boards + ? Object.keys(boards).reduce((acc: Record>, curr: string): Record< + string, + Array + > => { + acc[curr] = boards[curr].startNodes?.() || []; + return acc; + }, {}) + : {}; +} + export function resetLayerData(layer: string, keep: Array = []): void { keep.push("unlocked", "forceTooltip", "noRespecConfirm"); const keptData = keep.reduce((acc: Record, curr: string): Record => { diff --git a/src/util/proxies.ts b/src/util/proxies.ts index 57fa533..83c1c58 100644 --- a/src/util/proxies.ts +++ b/src/util/proxies.ts @@ -13,7 +13,6 @@ export function createLayerProxy(object: Record): Record): Record { if (object.isProxy) { console.warn( From f3b934337f94d94a01f4307df38596967943b9fc Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 19 Aug 2021 00:26:34 -0500 Subject: [PATCH 06/49] Added board with basic time resource node --- src/data/layers/main.ts | 69 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 0206502..f6a2046 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -1,11 +1,72 @@ +import player from "@/game/player"; +import Decimal, { DecimalSource } from "@/lib/break_eternity"; import { RawLayer } from "@/typings/layer"; +import themes from "../themes"; + +type ResourceNodeData = { + resourceType: string; + amount: DecimalSource; + maxAmount: DecimalSource; +}; export default { id: "main", display: ` -
Game Paused
-
Dev Speed: {{ format(player.devSpeed) }}x
+
Game Paused
+
Dev Speed: {{ format(player.devSpeed) }}x
TODO: Board
- `, - minimizable: false + + `, + minimizable: false, + componentStyles: { + board: { + position: "absolute", + top: "0", + left: "0" + } + }, + boards: { + data: { + main: { + height: "100%", + startNodes() { + return [ + { + position: { x: 0, y: 0 }, + type: "resource", + data: { + resourceType: "time", + amount: new Decimal(24 * 60 * 60), + maxAmount: new Decimal(24 * 60 * 60) + } + } + ]; + }, + types: { + resource: { + title(node) { + return (node.data as ResourceNodeData).resourceType; + }, + draggable: true, + progress(node) { + const data = node.data as ResourceNodeData; + return Decimal.div(data.amount, data.maxAmount).toNumber(); + }, + fillColor() { + return themes[player.theme].variables["--background"]; + }, + progressColor(node) { + const data = node.data as ResourceNodeData; + switch (data.resourceType) { + case "time": + return "#0FF3"; + default: + return "none"; + } + } + } + } + } + } + } } as RawLayer; From 02443bbb0ce4aa223d342992a1d9c6a4348bd760 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Fri, 20 Aug 2021 00:47:56 -0500 Subject: [PATCH 07/49] Implemented dropping nodes into each other Also improved node z-ordering and other related things --- src/components/board/Board.vue | 133 ++++++++++++++++++++++++--- src/components/board/BoardNode.vue | 140 ++++++++++++----------------- src/data/layers/main.ts | 28 ++++++ src/game/player.ts | 6 ++ src/typings/features/board.d.ts | 8 +- src/typings/player.d.ts | 2 +- src/util/features.ts | 20 +++++ src/util/layers.ts | 12 ++- 8 files changed, 249 insertions(+), 100 deletions(-) diff --git a/src/components/board/Board.vue b/src/components/board/Board.vue index f490b60..21e966d 100644 --- a/src/components/board/Board.vue +++ b/src/components/board/Board.vue @@ -2,18 +2,35 @@ + @@ -23,24 +40,30 @@ diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 9b9f41b..d15d95c 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -4,36 +4,34 @@ import Decimal, { DecimalSource } from "@/lib/break_eternity"; import { RawLayer } from "@/typings/layer"; import { camelToTitle } from "@/util/common"; import themes from "../themes"; +import Main from "./Main.vue"; -type ResourceNodeData = { +export type ResourceNodeData = { resourceType: string; amount: DecimalSource; maxAmount: DecimalSource; }; -type ItemNodeData = { +export type ItemNodeData = { itemType: string; amount: DecimalSource; }; -type ActionNodeData = { +export type ActionNodeData = { actionType: string; + log: string[]; }; export default { id: "main", - display: ` -
Game Paused
-
Dev Speed: {{ format(player.devSpeed) }}x
-
TODO: Board
- - - `, + display: Main, startData() { return { - openNode: null + openNode: null, + showModal: false } as { openNode: string | null; + showModal: boolean; }; }, minimizable: false, @@ -71,7 +69,8 @@ export default { position: { x: -150, y: 150 }, type: "action", data: { - actionType: "browse" + actionType: "web", + log: [] } } ]; @@ -101,31 +100,55 @@ export default { canAccept(node, otherNode) { return otherNode.type === "item"; }, + onClick(node) { + player.layers.main.openNode = node.id; + player.layers.main.showModal = true; + }, onDrop(node, otherNode) { - const index = player.layers[this.layer].boards[this.id].indexOf( + const index = player.layers[this.layer].boards[this.id].nodes.indexOf( otherNode ); - player.layers[this.layer].boards[this.id].splice(index, 1); + player.layers[this.layer].boards[this.id].nodes.splice(index, 1); } }, item: { title(node) { return (node.data as ItemNodeData).itemType; }, + onClick(node) { + player.layers.main.openNode = node.id; + player.layers.main.showModal = true; + }, draggable: true }, action: { title(node) { return camelToTitle((node.data as ActionNodeData).actionType); }, - fillColor() { - return themes[player.theme].variables["--background-tooltip"]; - }, + fillColor: "#000", draggable: true, shape: Shape.Diamond, - size: 100, progressColor: "#0FF3", - progressDisplay: ProgressDisplay.Outline + progressDisplay: ProgressDisplay.Outline, + actions: [ + { + id: "info", + icon: "history_edu", + tooltip: "Log", + onClick(node) { + player.layers.main.openNode = node.id; + player.layers.main.showModal = true; + } + }, + { + id: "reddit", + icon: "reddit", + tooltip: "Browse Reddit", + onClick(node) { + // TODO + } + } + ] } } } diff --git a/src/game/gameLoop.ts b/src/game/gameLoop.ts index 3016185..d6c3f52 100644 --- a/src/game/gameLoop.ts +++ b/src/game/gameLoop.ts @@ -68,10 +68,10 @@ function updateLayers(diff: DecimalSource) { ); } layers[layer].update?.(diff); - if (layers[layer].boards) { - Reflect.ownKeys(player.layers[layer].boards).forEach(board => { - player.layers[layer].boards[board.toString()].forEach(node => { - const nodeType = layers[layer].boards!.data[board.toString()].types[node.type]; + if (layers[layer].boards && layers[layer].boards?.data) { + Object.values(layers[layer].boards!.data!).forEach(board => { + board.nodes.forEach(node => { + const nodeType = board.types[node.type]; nodeType.update?.(node, diff); }); }); diff --git a/src/game/layers.ts b/src/game/layers.ts index 998b91b..a1b62c1 100644 --- a/src/game/layers.ts +++ b/src/game/layers.ts @@ -432,6 +432,29 @@ export function addLayer(layer: RawLayer, player?: Partial): void { for (const id in layer.boards.data) { setDefault(layer.boards.data[id], "width", "100%"); setDefault(layer.boards.data[id], "height", "400px"); + setDefault(layer.boards.data[id], "nodes", function() { + return playerProxy.layers[this.layer].boards[this.id].nodes; + }); + setDefault(layer.boards.data[id], "selectedNode", function() { + return playerProxy.layers[this.layer].boards[this.id].nodes.find( + node => node.id === playerProxy.layers[this.layer].boards[this.id].selectedNode + ); + }); + setDefault(layer.boards.data[id], "selectedAction", function() { + if (this.selectedNode == null) { + return null; + } + const nodeType = layers[this.layer].boards!.data[this.id].types[ + this.selectedNode.type + ]; + if (nodeType.actions === null) { + return null; + } + if (typeof nodeType.actions === "function") { + return nodeType.actions(this.selectedNode); + } + return nodeType.actions; + }); for (const nodeType in layer.boards.data[id].types) { layer.boards.data[id].types[nodeType].layer = layer.id; layer.boards.data[id].types[nodeType].id = id; @@ -440,16 +463,20 @@ export function addLayer(layer: RawLayer, player?: Partial): void { setDefault(layer.boards.data[id].types[nodeType], "draggable", false); setDefault(layer.boards.data[id].types[nodeType], "shape", Shape.Circle); setDefault(layer.boards.data[id].types[nodeType], "canAccept", false); + setDefault(layer.boards.data[id].types[nodeType], "actionDistance", Math.PI / 6); setDefault( layer.boards.data[id].types[nodeType], "progressDisplay", ProgressDisplay.Fill ); setDefault(layer.boards.data[id].types[nodeType], "nodes", function() { - return playerProxy.layers[this.layer].boards[this.id].filter( + return playerProxy.layers[this.layer].boards[this.id].nodes.filter( node => node.type === this.type ); }); + setDefault(layer.boards.data[id].types[nodeType], "onClick", function(node) { + playerProxy.layers[this.layer].boards[this.id].selectedNode = node.id; + }); } } } diff --git a/src/typings/component.d.ts b/src/typings/component.d.ts index 5b3c011..52620a1 100644 --- a/src/typings/component.d.ts +++ b/src/typings/component.d.ts @@ -1,3 +1,3 @@ -import { ComponentOptions } from "vue"; +import { Component, ComponentOptions } from "vue"; -export type CoercableComponent = string | ComponentOptions; +export type CoercableComponent = string | ComponentOptions | Component; diff --git a/src/typings/features/board.d.ts b/src/typings/features/board.d.ts index 13e59ca..a10d348 100644 --- a/src/typings/features/board.d.ts +++ b/src/typings/features/board.d.ts @@ -13,9 +13,10 @@ export interface BoardNode { data?: State; } -export interface CardOption { - text: string; - selected: (node: BoardNode) => void; +export interface BoardData { + nodes: BoardNode[]; + selectedNode: string | null; + selectedAction: string | null; } export interface Board extends Feature { @@ -24,6 +25,9 @@ export interface Board extends Feature { height: string; width: string; types: Record; + nodes: BoardNode[]; + selectedNode: BoardNode | null; + selectedAction: BoardNodeAction | null; } export type RawBoard = Omit, "types" | "startNodes"> & { @@ -43,8 +47,17 @@ export interface NodeType extends Feature { fillColor?: string | ((node: BoardNode) => string); outlineColor?: string | ((node: BoardNode) => string); titleColor?: string | ((node: BoardNode) => string); + actions?: BoardNodeAction[] | ((node: BoardNode) => BoardNodeAction[]); + actionDistance: number | ((node: BoardNode) => number); onClick?: (node: BoardNode) => void; onDrop?: (node: BoardNode, otherNode: BoardNode) => void; update?: (node: BoardNode, diff: DecimalSource) => void; nodes: BoardNode[]; } + +export interface BoardNodeAction { + id: string; + icon: string; + tooltip: string; + onClick: (node: BoardNode) => void; +} diff --git a/src/typings/player.d.ts b/src/typings/player.d.ts index dc54d03..c901591 100644 --- a/src/typings/player.d.ts +++ b/src/typings/player.d.ts @@ -1,7 +1,7 @@ import { Themes } from "@/data/themes"; import { DecimalSource } from "@/lib/break_eternity"; import Decimal from "@/util/bignum"; -import { BoardNode } from "./features/board"; +import { BoardData, BoardNode } from "./features/board"; import { MilestoneDisplay } from "./features/milestone"; import { State } from "./state"; @@ -62,7 +62,7 @@ export interface LayerSaveData { clickables: Record; challenges: Record; grids: Record>; - boards: Record; + boards: Record; confirmRespecBuyables: boolean; [index: string]: unknown; } diff --git a/src/util/layers.ts b/src/util/layers.ts index d9be21b..ff4d011 100644 --- a/src/util/layers.ts +++ b/src/util/layers.ts @@ -1,7 +1,7 @@ import { hotkeys, layers } from "@/game/layers"; import player from "@/game/player"; import { CacheableFunction } from "@/typings/cacheableFunction"; -import { Board, BoardNode, RawBoard } from "@/typings/features/board"; +import { Board, BoardData, BoardNode, RawBoard } from "@/typings/features/board"; import { Buyable } from "@/typings/features/buyable"; import { Challenge } from "@/typings/features/challenge"; import { Clickable } from "@/typings/features/clickable"; @@ -73,17 +73,21 @@ export function getStartingChallenges( export function getStartingBoards( boards?: Record | Record | undefined -): Record { +): Record { return boards - ? Object.keys(boards).reduce((acc: Record, curr: string): Record< + ? Object.keys(boards).reduce((acc: Record, curr: string): Record< string, - BoardNode[] + BoardData > => { const nodes = boards[curr].startNodes?.() || []; - acc[curr] = nodes.map((node, index) => ({ - id: index.toString(), - ...node - })) as BoardNode[]; + acc[curr] = { + nodes: nodes.map((node, index) => ({ + id: index.toString(), + ...node + })), + selectedNode: null, + selectedAction: null + } as BoardData; return acc; }, {}) : {}; diff --git a/src/util/proxies.ts b/src/util/proxies.ts index 83c1c58..a541eeb 100644 --- a/src/util/proxies.ts +++ b/src/util/proxies.ts @@ -43,7 +43,8 @@ function travel( object[key] = computed(object[key].bind(objectProxy)); } else if ( (isPlainObject(object[key]) || Array.isArray(object[key])) && - !(object[key] instanceof Decimal) + !(object[key] instanceof Decimal) && + typeof object[key].render !== "function" ) { object[key] = callback(object[key]); } @@ -62,7 +63,11 @@ const layerHandler: ProxyHandler> = { if (isRef(target[key])) { return target[key].value; - } else if (target[key].isProxy || target[key] instanceof Decimal) { + } else if ( + target[key].isProxy || + target[key] instanceof Decimal || + typeof target[key].render === "function" + ) { return target[key]; } else if ( (isPlainObject(target[key]) || Array.isArray(target[key])) && diff --git a/src/util/vue.ts b/src/util/vue.ts index 28f12ad..b3d953a 100644 --- a/src/util/vue.ts +++ b/src/util/vue.ts @@ -35,7 +35,7 @@ const data = function(): Record { return { Decimal, player, layers, hasWon, pointGain, ...numberUtils }; }; export function coerceComponent( - component: string | ComponentOptions, + component: string | ComponentOptions | Component, defaultWrapper = "span" ): Component | string { if (typeof component === "string") { From c4db2a51c7ddf6842ea882c7deccbbca5f29629f Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Sun, 22 Aug 2021 02:00:38 -0500 Subject: [PATCH 18/49] Fixed hardReset not updating the active save file --- src/util/save.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/util/save.ts b/src/util/save.ts index e46b561..45ef182 100644 --- a/src/util/save.ts +++ b/src/util/save.ts @@ -187,6 +187,9 @@ window.onbeforeunload = () => { } }; window.save = save; -window.hardReset = () => { - loadSave(newSave()); +window.hardReset = async () => { + await loadSave(newSave()); + const modData = JSON.parse(decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))); + modData.active = player.id; + localStorage.setItem(modInfo.id, btoa(unescape(encodeURIComponent(JSON.stringify(modData))))); }; From 7618ee291a6c757ee1af1d425ac7996813a514d2 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Sun, 22 Aug 2021 22:57:59 -0500 Subject: [PATCH 19/49] Implemented confirmable actions (plus logs and other related features) --- src/components/board/Board.vue | 32 +++++--- src/components/board/BoardLink.vue | 55 +++++++++++++ src/components/board/BoardNode.vue | 93 +++++++++++++++++++--- src/components/tree/BranchLine.vue | 8 +- src/data/layers/Main.vue | 12 ++- src/data/layers/main.ts | 120 ++++++++++++++++++++++++++++- src/data/mod.ts | 1 + src/game/layers.ts | 22 +++++- src/typings/branches.d.ts | 3 +- src/typings/features/board.d.ts | 27 ++++++- src/util/features.ts | 12 ++- src/util/save.ts | 2 +- 12 files changed, 351 insertions(+), 36 deletions(-) create mode 100644 src/components/board/BoardLink.vue diff --git a/src/components/board/Board.vue b/src/components/board/Board.vue index 78d6ca0..1b2eb99 100644 --- a/src/components/board/Board.vue +++ b/src/components/board/Board.vue @@ -2,16 +2,24 @@ + + + + + number)(); @@ -186,6 +192,9 @@ export default defineComponent({ } this.dragging = null; + } else if (!this.hasDragged) { + player.layers[this.layer].boards[this.id].selectedNode = null; + player.layers[this.layer].boards[this.id].selectedAction = null; } } } @@ -202,4 +211,9 @@ export default defineComponent({ #g1 { transition-duration: 0s; } + +.link-enter-from, +.link-leave-to { + opacity: 0; +} diff --git a/src/components/board/BoardLink.vue b/src/components/board/BoardLink.vue new file mode 100644 index 0000000..28af0ba --- /dev/null +++ b/src/components/board/BoardLink.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index c4d5746..fb5405d 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -6,10 +6,12 @@ > + - - {{ action.icon }} + + {{ + typeof action.icon === "function" ? action.icon(node) : action.icon + }} @@ -31,7 +46,9 @@ @mouseenter="mouseEnter" @mouseleave="mouseLeave" @mousedown="mouseDown" + @touchstart="mouseDown" @mouseup="mouseUp" + @touchend="mouseUp" > {{ title }} + + + {{ label.text }} + + + + Tap again to confirm + @@ -124,14 +164,12 @@ import themes from "@/data/themes"; import { ProgressDisplay, Shape } from "@/game/enums"; import { layers } from "@/game/layers"; import player from "@/game/player"; -import { BoardNode, BoardNodeAction, NodeType } from "@/typings/features/board"; +import { BoardNode, BoardNodeAction, NodeLabel, NodeType } from "@/typings/features/board"; import { getNodeTypeProperty } from "@/util/features"; -import { InjectLayerMixin } from "@/util/vue"; import { defineComponent, PropType } from "vue"; export default defineComponent({ name: "BoardNode", - mixins: [InjectLayerMixin], data() { return { ProgressDisplay, @@ -174,6 +212,9 @@ export default defineComponent({ selected() { return this.board.selectedNode?.id === this.node.id; }, + selectedAction() { + return this.board.selectedAction; + }, actions(): BoardNodeAction[] | null | undefined { return getNodeTypeProperty(this.nodeType, this.node, "actions"); }, @@ -203,6 +244,9 @@ export default defineComponent({ title(): string { return getNodeTypeProperty(this.nodeType, this.node, "title"); }, + label(): NodeLabel | null | undefined { + return getNodeTypeProperty(this.nodeType, this.node, "label"); + }, progress(): number { return getNodeTypeProperty(this.nodeType, this.node, "progress") || 0; }, @@ -263,8 +307,14 @@ export default defineComponent({ mouseLeave() { this.hovering = false; }, - performAction(action: BoardNodeAction) { + performAction(e: MouseEvent, action: BoardNodeAction) { action.onClick(this.node); + // If the onClick function made this action selected, + // don't propagate the event (which will deselect everything) + if (this.board.selectedAction === action) { + e.preventDefault(); + e.stopPropagation(); + } } }, watch: { @@ -295,11 +345,13 @@ export default defineComponent({ transform: rotate(-90deg); } -.action:hover circle { +.action:hover circle, +.action.selected circle { r: 25; } -.action:hover text { +.action:hover text, +.action.selected text { font-size: 187.5%; /* 150% * 1.25 */ } @@ -307,6 +359,29 @@ export default defineComponent({ text-anchor: middle; dominant-baseline: central; } + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +.pulsing { + animation: pulsing 2s ease-in infinite; +} + +@keyframes pulsing { + 0% { + opacity: 0.25; + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0.25; + } +}
" + - (node.data as ActionNodeData).log.join("
") + + "
" + + (node.data as ActionNodeData).log + .map(log => { + let display = log.description; + if (log.effectDescription) { + display += `
${log.effectDescription}
`; + } + return display; + }) + .join("
") + "
" ); break; diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index d15d95c..03effcc 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -1,8 +1,10 @@ import { ProgressDisplay, Shape } from "@/game/enums"; +import { layers } from "@/game/layers"; import player from "@/game/player"; import Decimal, { DecimalSource } from "@/lib/break_eternity"; import { RawLayer } from "@/typings/layer"; import { camelToTitle } from "@/util/common"; +import { getUniqueNodeID } from "@/util/features"; import themes from "../themes"; import Main from "./Main.vue"; @@ -19,9 +21,64 @@ export type ItemNodeData = { export type ActionNodeData = { actionType: string; - log: string[]; + log: LogEntry[]; }; +export type LogEntry = { + description: string; + effectDescription?: string; +}; + +export type WeightedEvent = { + event: () => LogEntry; + weight: number; +}; + +const redditEvents = [ + { + event: () => ({ description: "You blink and half an hour has passed before you know it." }), + weight: 1 + }, + { + event: () => { + const id = getUniqueNodeID(layers.main.boards!.data.main); + player.layers.main.boards.main.nodes.push({ + id, + position: { x: 0, y: 150 }, // TODO function to get nearest unoccupied space + type: "item", + data: { + itemType: "speed", + amount: new Decimal(15 * 60) + } + }); + return { + description: "You found some funny memes and actually feel a bit refreshed.", + effectDescription: `Added Speed node` + }; + }, + weight: 0.5 + } +]; + +function getRandomEvent(events: WeightedEvent[]): LogEntry | null { + if (events.length === 0) { + return null; + } + const totalWeight = events.reduce((acc, curr) => acc + curr.weight, 0); + const random = Math.random() * totalWeight; + + let weight = 0; + for (const outcome of events) { + weight += outcome.weight; + if (random <= weight) { + return outcome.event(); + } + } + + // Should never reach here + return null; +} + export default { id: "main", display: Main, @@ -80,6 +137,21 @@ export default { title(node) { return (node.data as ResourceNodeData).resourceType; }, + label(node) { + if (player.layers[this.layer].boards[this.id].selectedAction == null) { + return null; + } + const action = player.layers[this.layer].boards[this.id].selectedAction; + switch (action) { + default: + return null; + case "reddit": + if ((node.data as ResourceNodeData).resourceType === "time") { + return { text: "30m", color: "red", pulsing: true }; + } + return null; + } + }, draggable: true, progress(node) { const data = node.data as ResourceNodeData; @@ -109,6 +181,10 @@ export default { otherNode ); player.layers[this.layer].boards[this.id].nodes.splice(index, 1); + (node.data as ResourceNodeData).amount = Decimal.add( + (node.data as ResourceNodeData).amount, + (otherNode.data as ItemNodeData).amount + ); } }, item: { @@ -134,6 +210,9 @@ export default { { id: "info", icon: "history_edu", + fillColor() { + return themes[player.theme].variables["--separator"]; + }, tooltip: "Log", onClick(node) { player.layers.main.openNode = node.id; @@ -145,7 +224,44 @@ export default { icon: "reddit", tooltip: "Browse Reddit", onClick(node) { - // TODO + if (player.layers.main.boards.main.selectedAction === this.id) { + const timeNode = player.layers.main.boards.main.nodes.find( + node => + node.type === "resource" && + (node.data as ResourceNodeData).resourceType === + "time" + ); + if (timeNode) { + (timeNode.data as ResourceNodeData).amount = Decimal.sub( + (timeNode.data as ResourceNodeData).amount, + 30 * 60 + ); + player.layers.main.boards.main.selectedAction = null; + (node.data as ActionNodeData).log.push( + getRandomEvent(redditEvents)! + ); + } + } else { + player.layers.main.boards.main.selectedAction = this.id; + } + }, + links(node) { + return [ + { + // TODO this is ridiculous and needs some utility + // function to shrink it down + from: player.layers.main.boards.main.nodes.find( + node => + node.type === "resource" && + (node.data as ResourceNodeData).resourceType === + "time" + ), + to: node, + stroke: "red", + "stroke-width": 4, + pulsing: true + } + ]; } } ] diff --git a/src/data/mod.ts b/src/data/mod.ts index 1c3ef96..3035aee 100644 --- a/src/data/mod.ts +++ b/src/data/mod.ts @@ -1,6 +1,7 @@ import { RawLayer } from "@/typings/layer"; import { PlayerData } from "@/typings/player"; import Decimal from "@/util/bignum"; +import { hardReset } from "@/util/save"; import { computed } from "vue"; import main from "./layers/main"; diff --git a/src/game/layers.ts b/src/game/layers.ts index a1b62c1..495aa50 100644 --- a/src/game/layers.ts +++ b/src/game/layers.ts @@ -450,10 +450,26 @@ export function addLayer(layer: RawLayer, player?: Partial): void { if (nodeType.actions === null) { return null; } - if (typeof nodeType.actions === "function") { - return nodeType.actions(this.selectedNode); + const actions = + typeof nodeType.actions === "function" + ? nodeType.actions(this.selectedNode) + : nodeType.actions; + return actions?.find( + action => + action.id === playerProxy.layers[this.layer].boards[this.id].selectedAction + ); + }); + setDefault(layer.boards.data[id], "links", function() { + if (this.selectedAction == null) { + return null; } - return nodeType.actions; + if (this.selectedAction.links) { + if (typeof this.selectedAction.links === "function") { + return this.selectedAction.links(this.selectedNode); + } + return this.selectedAction.links; + } + return null; }); for (const nodeType in layer.boards.data[id].types) { layer.boards.data[id].types[nodeType].layer = layer.id; diff --git a/src/typings/branches.d.ts b/src/typings/branches.d.ts index 93b263b..cfd0ee6 100644 --- a/src/typings/branches.d.ts +++ b/src/typings/branches.d.ts @@ -17,9 +17,10 @@ export interface BranchOptions { target?: string; featureType?: string; stroke?: string; - "stroke-width"?: string; + strokeWidth?: number | string; startOffset?: Position; endOffset?: Position; + [key: string]: any; } export interface Position { diff --git a/src/typings/features/board.d.ts b/src/typings/features/board.d.ts index a10d348..f5d716c 100644 --- a/src/typings/features/board.d.ts +++ b/src/typings/features/board.d.ts @@ -4,7 +4,7 @@ import { State } from "../state"; import { Feature, RawFeature } from "./feature"; export interface BoardNode { - id: string; + id: number; position: { x: number; y: number; @@ -28,6 +28,7 @@ export interface Board extends Feature { nodes: BoardNode[]; selectedNode: BoardNode | null; selectedAction: BoardNodeAction | null; + links: BoardNodeLink[] | null; } export type RawBoard = Omit, "types" | "startNodes"> & { @@ -37,7 +38,8 @@ export type RawBoard = Omit, "types" | "startNodes"> & { export interface NodeType extends Feature { title: string | ((node: BoardNode) => string); - size: number | ((node: BoardNode) => number); + label?: NodeLabel | null | ((node: BoardNode) => NodeLabel | null); + size: number | string | ((node: BoardNode) => number | string); draggable: boolean | ((node: BoardNode) => boolean); shape: Shape | ((node: BoardNode) => Shape); canAccept: boolean | ((node: BoardNode, otherNode: BoardNode) => boolean); @@ -57,7 +59,24 @@ export interface NodeType extends Feature { export interface BoardNodeAction { id: string; - icon: string; - tooltip: string; + icon: string | ((node: BoardNode) => string); + fillColor?: string | ((node: BoardNode) => string); + tooltip: string | ((node: BoardNode) => string); onClick: (node: BoardNode) => void; + links?: BoardNodeLink[] | ((node: BoardNode) => BoardNodeLink[]); +} + +export interface BoardNodeLink { + from: BoardNode; + to: BoardNode; + stroke: string; + strokeWidth: number | string; + pulsing?: boolean; + [key: string]: any; +} + +export interface NodeLabel { + text: string; + color?: string; + pulsing?: boolean; } diff --git a/src/util/features.ts b/src/util/features.ts index 40a6809..18794d9 100644 --- a/src/util/features.ts +++ b/src/util/features.ts @@ -1,5 +1,5 @@ import { layers } from "@/game/layers"; -import { NodeType, BoardNode } from "@/typings/features/board"; +import { NodeType, BoardNode, Board } from "@/typings/features/board"; import { GridCell } from "@/typings/features/grid"; import { State } from "@/typings/state"; import Decimal, { DecimalSource } from "@/util/bignum"; @@ -107,3 +107,13 @@ export function getNodeTypeProperty( ? (nodeType[property] as (node: BoardNode) => T)(node) : (nodeType[property] as T); } + +export function getUniqueNodeID(board: Board): number { + let id = 0; + board.nodes.forEach(node => { + if (node.id >= id) { + id = node.id + 1; + } + }); + return id; +} diff --git a/src/util/save.ts b/src/util/save.ts index 45ef182..0b14d81 100644 --- a/src/util/save.ts +++ b/src/util/save.ts @@ -187,7 +187,7 @@ window.onbeforeunload = () => { } }; window.save = save; -window.hardReset = async () => { +export const hardReset = window.hardReset = async () => { await loadSave(newSave()); const modData = JSON.parse(decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!)))); modData.active = player.id; From bb549044647b68685b54ee98dff7f9f15b8d037b Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Sun, 22 Aug 2021 23:16:14 -0500 Subject: [PATCH 20/49] Fixed mobile not being able to click actions --- src/components/board/BoardNode.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index fb5405d..0a370da 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -21,6 +21,7 @@ )` " @mousedown="e => performAction(e, action)" + @touchstart="e => performAction(e, action)" > Date: Mon, 23 Aug 2021 23:55:43 -0500 Subject: [PATCH 22/49] Fixed typing issues with selected node --- src/typings/features/board.d.ts | 2 +- src/util/layers.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/typings/features/board.d.ts b/src/typings/features/board.d.ts index f5d716c..234965f 100644 --- a/src/typings/features/board.d.ts +++ b/src/typings/features/board.d.ts @@ -15,7 +15,7 @@ export interface BoardNode { export interface BoardData { nodes: BoardNode[]; - selectedNode: string | null; + selectedNode: number | null; selectedAction: string | null; } diff --git a/src/util/layers.ts b/src/util/layers.ts index ff4d011..e790ee5 100644 --- a/src/util/layers.ts +++ b/src/util/layers.ts @@ -82,7 +82,7 @@ export function getStartingBoards( const nodes = boards[curr].startNodes?.() || []; acc[curr] = { nodes: nodes.map((node, index) => ({ - id: index.toString(), + id: index, ...node })), selectedNode: null, From 8a38ecf92863bd0f9293fef6c19b2fdccc3d00b2 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Mon, 23 Aug 2021 23:56:21 -0500 Subject: [PATCH 23/49] Added amount displays to resource and item nodes --- src/data/layers/main.ts | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 03effcc..e9ef1ac 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -3,6 +3,8 @@ import { layers } from "@/game/layers"; import player from "@/game/player"; import Decimal, { DecimalSource } from "@/lib/break_eternity"; import { RawLayer } from "@/typings/layer"; +import { formatTime } from "@/util/bignum"; +import { format } from "@/util/break_eternity"; import { camelToTitle } from "@/util/common"; import { getUniqueNodeID } from "@/util/features"; import themes from "../themes"; @@ -47,7 +49,7 @@ const redditEvents = [ position: { x: 0, y: 150 }, // TODO function to get nearest unoccupied space type: "item", data: { - itemType: "speed", + itemType: "time", amount: new Decimal(15 * 60) } }); @@ -118,7 +120,7 @@ export default { position: { x: 0, y: 150 }, type: "item", data: { - itemType: "speed", + itemType: "time", amount: new Decimal(5 * 60 * 60) } }, @@ -138,6 +140,13 @@ export default { return (node.data as ResourceNodeData).resourceType; }, label(node) { + if (player.layers[this.layer].boards[this.id].selectedNode == node.id) { + const data = node.data as ResourceNodeData; + if (data.resourceType === "time") { + return { text: formatTime(data.amount), color: "#0FF3" }; + } + return { text: format(data.amount), color: "#0FF3" }; + } if (player.layers[this.layer].boards[this.id].selectedAction == null) { return null; } @@ -172,10 +181,6 @@ export default { canAccept(node, otherNode) { return otherNode.type === "item"; }, - onClick(node) { - player.layers.main.openNode = node.id; - player.layers.main.showModal = true; - }, onDrop(node, otherNode) { const index = player.layers[this.layer].boards[this.id].nodes.indexOf( otherNode @@ -189,11 +194,21 @@ export default { }, item: { title(node) { - return (node.data as ItemNodeData).itemType; + switch ((node.data as ItemNodeData).itemType) { + default: + return null; + case "time": + return "speed"; + } }, - onClick(node) { - player.layers.main.openNode = node.id; - player.layers.main.showModal = true; + label(node) { + if (player.layers[this.layer].boards[this.id].selectedNode == node.id) { + const data = node.data as ItemNodeData; + if (data.itemType === "time") { + return { text: formatTime(data.amount), color: "#0FF3" }; + } + return { text: format(data.amount), color: "#0FF3" }; + } }, draggable: true }, @@ -211,7 +226,7 @@ export default { id: "info", icon: "history_edu", fillColor() { - return themes[player.theme].variables["--separator"]; + return themes[player.theme].variables["--secondary-background"]; }, tooltip: "Log", onClick(node) { From e52b3751c979333ecc5ae8a959164a14abbb08bc Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 24 Aug 2021 00:40:36 -0500 Subject: [PATCH 24/49] Improved look of log --- src/data/layers/Main.vue | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/layers/Main.vue b/src/data/layers/Main.vue index 2780aaa..3b238d6 100644 --- a/src/data/layers/Main.vue +++ b/src/data/layers/Main.vue @@ -86,3 +86,13 @@ export default defineComponent(function Main() { return { title, body, footer, showModal, closeModal, devSpeed, formattedDevSpeed }; }); + + From 4312b7ac759ba6506e036c2c29187a4cbb1cb604 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 24 Aug 2021 01:23:25 -0500 Subject: [PATCH 25/49] Fixed various node and action selection issues --- src/components/board/Board.vue | 14 ++++++++------ src/components/board/BoardNode.vue | 13 ++++++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/components/board/Board.vue b/src/components/board/Board.vue index 1b2eb99..608dd27 100644 --- a/src/components/board/Board.vue +++ b/src/components/board/Board.vue @@ -7,8 +7,8 @@ @init="onInit" @mousemove="drag" @touchmove="drag" - @mousedown="mouseDown" - @touchstart="mouseDown" + @mousedown="e => mouseDown(e)" + @touchstart="e => mouseDown(e)" @mouseup="() => endDragging(dragging)" @touchend="() => endDragging(dragging)" @mouseleave="() => endDragging(dragging)" @@ -56,7 +56,7 @@ export default defineComponent({ } as { lastMousePosition: { x: number; y: number }; dragged: { x: number; y: number }; - dragging: string | null; + dragging: number | null; hasDragged: boolean; }; }, @@ -81,7 +81,9 @@ export default defineComponent({ ]; }, draggingNode() { - return this.dragging ? this.board.nodes.find(node => node.id === this.dragging) : null; + return this.dragging == null + ? null + : this.board.nodes.find(node => node.id === this.dragging); }, nodes() { const nodes = this.board.nodes.slice(); @@ -135,7 +137,7 @@ export default defineComponent({ onInit(panzoomInstance: any) { panzoomInstance.setTransformOrigin(null); }, - mouseDown(e: MouseEvent, nodeID: string | null = null, draggable = false) { + mouseDown(e: MouseEvent, nodeID: number | null = null, draggable = false) { if (this.dragging == null) { e.preventDefault(); e.stopPropagation(); @@ -176,7 +178,7 @@ export default defineComponent({ e.stopPropagation(); } }, - endDragging(nodeID: string | null) { + endDragging(nodeID: number | null) { if (this.dragging != null && this.dragging === nodeID) { const draggingNode = this.draggingNode!; const receivingNode = this.receivingNode; diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index 0a370da..4dd2ed8 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -22,6 +22,8 @@ " @mousedown="e => performAction(e, action)" @touchstart="e => performAction(e, action)" + @mouseup="e => actionMouseUp(e, action)" + @touchend.stop="e => actionMouseUp(e, action)" > Date: Tue, 24 Aug 2021 02:54:42 -0500 Subject: [PATCH 26/49] Implemented links between resource nodes --- src/data/layers/Main.vue | 15 +--- src/data/layers/main.ts | 182 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 174 insertions(+), 23 deletions(-) diff --git a/src/data/layers/Main.vue b/src/data/layers/Main.vue index 3b238d6..c27b588 100644 --- a/src/data/layers/Main.vue +++ b/src/data/layers/Main.vue @@ -22,7 +22,7 @@ import { format } from "@/util/break_eternity"; import { camelToTitle } from "@/util/common"; import { coerceComponent } from "@/util/vue"; import { computed, defineComponent, shallowRef, watchEffect } from "vue"; -import { ActionNodeData, ResourceNodeData } from "./main"; +import { ActionNodeData } from "./main"; export default defineComponent(function Main() { const title = shallowRef(null); @@ -41,19 +41,6 @@ export default defineComponent(function Main() { default: player.layers.main.showModal = false; break; - case "resource": - switch ((node.data as ResourceNodeData).resourceType) { - default: - player.layers.main.showModal = false; - break; - case "time": - title.value = coerceComponent("

Time

"); - body.value = coerceComponent( - "The ultimate resource, that you'll never have enough of." - ); - break; - } - break; case "action": title.value = coerceComponent( camelToTitle((node.data as ActionNodeData).actionType) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index e9ef1ac..21da979 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -4,9 +4,10 @@ import player from "@/game/player"; import Decimal, { DecimalSource } from "@/lib/break_eternity"; import { RawLayer } from "@/typings/layer"; import { formatTime } from "@/util/bignum"; -import { format } from "@/util/break_eternity"; +import { format, formatWhole } from "@/util/break_eternity"; import { camelToTitle } from "@/util/common"; import { getUniqueNodeID } from "@/util/features"; +import { watch } from "vue"; import themes from "../themes"; import Main from "./Main.vue"; @@ -81,6 +82,71 @@ function getRandomEvent(events: WeightedEvent[]): LogEntry | null { return null; } +enum LinkType { + LossOnly, + GainOnly, + Both +} + +// Links cause gain/loss of one resource to also affect other resources +const links = { + time: [ + { resource: "social", amount: 1 / 60, linkType: LinkType.LossOnly }, + { resource: "mental", amount: 1 / 120, linkType: LinkType.LossOnly } + ] +} as Record< + string, + { + resource: string; + amount: DecimalSource; + linkType: LinkType; + }[] +>; + +for (const resource in links) { + const resourceLinks = links[resource]; + watch( + () => + (player.layers.main?.boards.main.nodes.find( + node => + node.type === "resource" && + (node.data as ResourceNodeData).resourceType === resource + )?.data as ResourceNodeData | null)?.amount, + (amount, oldAmount) => { + if (amount == null || oldAmount == null) { + return; + } + const resourceGain = Decimal.sub(amount, oldAmount); + resourceLinks.forEach(link => { + switch (link.linkType) { + case LinkType.LossOnly: + if (Decimal.gt(amount, oldAmount)) { + return; + } + break; + case LinkType.GainOnly: + if (Decimal.lt(amount, oldAmount)) { + return; + } + break; + } + const node = player.layers.main.boards.main.nodes.find( + node => + node.type === "resource" && + (node.data as ResourceNodeData).resourceType === link.resource + ); + if (node) { + const data = node.data as ResourceNodeData; + data.amount = Decimal.add( + data.amount, + Decimal.times(link.amount, resourceGain) + ).clamp(0, data.maxAmount); + } + }); + } + ); +} + export default { id: "main", display: Main, @@ -116,6 +182,33 @@ export default { maxAmount: new Decimal(24 * 60 * 60) } }, + { + position: { x: 0, y: 0 }, + type: "resource", + data: { + resourceType: "mental", + amount: new Decimal(100), + maxAmount: new Decimal(100) + } + }, + { + position: { x: 0, y: 0 }, + type: "resource", + data: { + resourceType: "social", + amount: new Decimal(100), + maxAmount: new Decimal(100) + } + }, + { + position: { x: 0, y: 0 }, + type: "resource", + data: { + resourceType: "focus", + amount: new Decimal(100), + maxAmount: new Decimal(100) + } + }, { position: { x: 0, y: 150 }, type: "item", @@ -145,8 +238,48 @@ export default { if (data.resourceType === "time") { return { text: formatTime(data.amount), color: "#0FF3" }; } + if (Decimal.eq(data.maxAmount, 100)) { + return { text: formatWhole(data.amount) + "%", color: "#0FF3" }; + } return { text: format(data.amount), color: "#0FF3" }; } + if (player.layers[this.layer].boards[this.id].selectedNode == null) { + return null; + } + const selectedNode = layers[this.layer].boards!.data[this.id] + .selectedNode; + if (selectedNode.type === "resource") { + const data = selectedNode.data as ResourceNodeData; + if (data.resourceType in links) { + const link = links[data.resourceType].find( + link => + link.resource === + (node.data as ResourceNodeData).resourceType + ); + if (link) { + let text; + if ( + (node.data as ResourceNodeData).resourceType === "time" + ) { + text = formatTime(link.amount); + } else if ( + Decimal.eq( + (node.data as ResourceNodeData).maxAmount, + 100 + ) + ) { + text = formatWhole(link.amount) + "%"; + } else { + text = format(link.amount); + } + let negativeLink = Decimal.lt(link.amount, 0); + if (link.linkType === LinkType.LossOnly) { + negativeLink = !negativeLink; + } + return { text, color: negativeLink ? "red" : "green" }; + } + } + } if (player.layers[this.layer].boards[this.id].selectedAction == null) { return null; } @@ -170,13 +303,7 @@ export default { return themes[player.theme].variables["--background"]; }, progressColor(node) { - const data = node.data as ResourceNodeData; - switch (data.resourceType) { - case "time": - return "#0FF3"; - default: - return "none"; - } + return "#0FF3"; }, canAccept(node, otherNode) { return otherNode.type === "item"; @@ -189,7 +316,7 @@ export default { (node.data as ResourceNodeData).amount = Decimal.add( (node.data as ResourceNodeData).amount, (otherNode.data as ItemNodeData).amount - ); + ).min((node.data as ResourceNodeData).maxAmount); } }, item: { @@ -281,6 +408,43 @@ export default { } ] } + }, + links() { + if (this.selectedAction?.links) { + if (typeof this.selectedAction!.links === "function") { + return this.selectedAction!.links(this.selectedNode); + } + return this.selectedAction!.links; + } + if (player.layers[this.layer].boards[this.id].selectedNode == null) { + return null; + } + const selectedNode = layers[this.layer].boards!.data[this.id].selectedNode; + if (selectedNode.type === "resource") { + const data = selectedNode.data as ResourceNodeData; + if (data.resourceType in links) { + return links[data.resourceType].map(link => { + const node = player.layers.main.boards.main.nodes.find( + node => + node.type === "resource" && + (node.data as ResourceNodeData).resourceType === + link.resource + ); + let negativeLink = Decimal.lt(link.amount, 0); + if (link.linkType === LinkType.LossOnly) { + negativeLink = !negativeLink; + } + return { + from: selectedNode, + to: node, + stroke: negativeLink ? "red" : "green", + "stroke-width": 4, + pulsing: true + }; + }); + } + } + return null; } } } From a7009e416e114fd899ed1082472c99a6f224edcc Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 24 Aug 2021 08:18:55 -0500 Subject: [PATCH 27/49] Implemented pinning resource amounts --- src/components/board/BoardNode.vue | 3 +- src/data/layers/main.ts | 84 +++++++++++++++++++----------- src/typings/features/board.d.ts | 3 +- src/util/proxies.ts | 2 +- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index 4dd2ed8..5936777 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -310,10 +310,9 @@ export default defineComponent({ this.hovering = false; }, performAction(e: MouseEvent, action: BoardNodeAction) { - action.onClick(this.node); // If the onClick function made this action selected, // don't propagate the event (which will deselect everything) - if (this.board.selectedAction === action) { + if (action.onClick(this.node) || this.board.selectedAction === action) { e.preventDefault(); e.stopPropagation(); } diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 21da979..1d34797 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -2,6 +2,7 @@ import { ProgressDisplay, Shape } from "@/game/enums"; import { layers } from "@/game/layers"; import player from "@/game/player"; import Decimal, { DecimalSource } from "@/lib/break_eternity"; +import { BoardNodeAction } from "@/typings/features/board"; import { RawLayer } from "@/typings/layer"; import { formatTime } from "@/util/bignum"; import { format, formatWhole } from "@/util/break_eternity"; @@ -147,6 +148,22 @@ for (const resource in links) { ); } +const pinAction = { + id: "pin", + icon: "push_pin", + fillColor(node) { + if (node.pinned) { + return themes[player.theme].variables["--bought"]; + } + return themes[player.theme].variables["--secondary-background"]; + }, + tooltip: "Always show resource", + onClick(node) { + node.pinned = !node.pinned; + return true; + } +} as BoardNodeAction; + export default { id: "main", display: Main, @@ -233,22 +250,29 @@ export default { return (node.data as ResourceNodeData).resourceType; }, label(node) { - if (player.layers[this.layer].boards[this.id].selectedNode == node.id) { - const data = node.data as ResourceNodeData; - if (data.resourceType === "time") { - return { text: formatTime(data.amount), color: "#0FF3" }; - } - if (Decimal.eq(data.maxAmount, 100)) { - return { text: formatWhole(data.amount) + "%", color: "#0FF3" }; - } - return { text: format(data.amount), color: "#0FF3" }; - } - if (player.layers[this.layer].boards[this.id].selectedNode == null) { - return null; - } const selectedNode = layers[this.layer].boards!.data[this.id] .selectedNode; - if (selectedNode.type === "resource") { + if ( + selectedNode != node && + player.layers[this.layer].boards[this.id].selectedAction != null + ) { + const action = + player.layers[this.layer].boards[this.id].selectedAction; + switch (action) { + case "reddit": + if ( + (node.data as ResourceNodeData).resourceType === "time" + ) { + return { text: "30m", color: "red", pulsing: true }; + } + break; + } + } + if ( + selectedNode != node && + selectedNode != null && + selectedNode.type === "resource" + ) { const data = selectedNode.data as ResourceNodeData; if (data.resourceType in links) { const link = links[data.resourceType].find( @@ -280,18 +304,15 @@ export default { } } } - if (player.layers[this.layer].boards[this.id].selectedAction == null) { - return null; - } - const action = player.layers[this.layer].boards[this.id].selectedAction; - switch (action) { - default: - return null; - case "reddit": - if ((node.data as ResourceNodeData).resourceType === "time") { - return { text: "30m", color: "red", pulsing: true }; - } - return null; + if (selectedNode == node || node.pinned) { + const data = node.data as ResourceNodeData; + if (data.resourceType === "time") { + return { text: formatTime(data.amount), color: "#0FF3" }; + } + if (Decimal.eq(data.maxAmount, 100)) { + return { text: formatWhole(data.amount) + "%", color: "#0FF3" }; + } + return { text: format(data.amount), color: "#0FF3" }; } }, draggable: true, @@ -317,7 +338,8 @@ export default { (node.data as ResourceNodeData).amount, (otherNode.data as ItemNodeData).amount ).min((node.data as ResourceNodeData).maxAmount); - } + }, + actions: [pinAction] }, item: { title(node) { @@ -329,7 +351,10 @@ export default { } }, label(node) { - if (player.layers[this.layer].boards[this.id].selectedNode == node.id) { + if ( + player.layers[this.layer].boards[this.id].selectedNode == node.id || + node.pinned + ) { const data = node.data as ItemNodeData; if (data.itemType === "time") { return { text: formatTime(data.amount), color: "#0FF3" }; @@ -337,7 +362,8 @@ export default { return { text: format(data.amount), color: "#0FF3" }; } }, - draggable: true + draggable: true, + actions: [pinAction] }, action: { title(node) { diff --git a/src/typings/features/board.d.ts b/src/typings/features/board.d.ts index 234965f..69d462e 100644 --- a/src/typings/features/board.d.ts +++ b/src/typings/features/board.d.ts @@ -11,6 +11,7 @@ export interface BoardNode { }; type: string; data?: State; + pinned?: boolean; } export interface BoardData { @@ -62,7 +63,7 @@ export interface BoardNodeAction { icon: string | ((node: BoardNode) => string); fillColor?: string | ((node: BoardNode) => string); tooltip: string | ((node: BoardNode) => string); - onClick: (node: BoardNode) => void; + onClick: (node: BoardNode) => boolean | undefined; links?: BoardNodeLink[] | ((node: BoardNode) => BoardNodeLink[]); } diff --git a/src/util/proxies.ts b/src/util/proxies.ts index a541eeb..52b32ea 100644 --- a/src/util/proxies.ts +++ b/src/util/proxies.ts @@ -30,7 +30,7 @@ function travel( objectProxy: Record ) { for (const key in object) { - if (object[key] == undefined || object[key].isProxy) { + if (object[key] == undefined || object[key].isProxy || isRef(object[key])) { continue; } if (isFunction(object[key])) { From d2e0ab29f28c681ecd5ae046455386eacc0ee08d Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 24 Aug 2021 19:19:55 -0500 Subject: [PATCH 28/49] Various mobile fixes --- src/components/board/Board.vue | 43 ++++++++++++++++++++++++------ src/components/board/BoardNode.vue | 6 ++--- src/components/system/Nav.vue | 4 +++ src/data/layers/main.ts | 1 + src/main.css | 1 - 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/components/board/Board.vue b/src/components/board/Board.vue index 608dd27..d01789e 100644 --- a/src/components/board/Board.vue +++ b/src/components/board/Board.vue @@ -137,14 +137,26 @@ export default defineComponent({ onInit(panzoomInstance: any) { panzoomInstance.setTransformOrigin(null); }, - mouseDown(e: MouseEvent, nodeID: number | null = null, draggable = false) { + mouseDown(e: MouseEvent | TouchEvent, nodeID: number | null = null, draggable = false) { if (this.dragging == null) { e.preventDefault(); e.stopPropagation(); + let clientX, clientY; + if ("touches" in e) { + if (e.touches.length === 1) { + clientX = e.touches[0].clientX; + clientY = e.touches[0].clientY; + } else { + return; + } + } else { + clientX = e.clientX; + clientY = e.clientY; + } this.lastMousePosition = { - x: e.clientX, - y: e.clientY + x: clientX, + y: clientY }; this.dragged = { x: 0, y: 0 }; this.hasDragged = false; @@ -158,15 +170,30 @@ export default defineComponent({ player.layers[this.layer].boards[this.id].selectedAction = null; } }, - drag(e: MouseEvent) { + drag(e: MouseEvent | TouchEvent) { const zoom = (this.getZoomLevel as () => number)(); + + let clientX, clientY; + if ("touches" in e) { + if (e.touches.length === 1) { + clientX = e.touches[0].clientX; + clientY = e.touches[0].clientY; + } else { + this.endDragging(this.dragging); + return; + } + } else { + clientX = e.clientX; + clientY = e.clientY; + } + this.dragged = { - x: this.dragged.x + (e.clientX - this.lastMousePosition.x) / zoom, - y: this.dragged.y + (e.clientY - this.lastMousePosition.y) / zoom + x: this.dragged.x + (clientX - this.lastMousePosition.x) / zoom, + y: this.dragged.y + (clientY - this.lastMousePosition.y) / zoom }; this.lastMousePosition = { - x: e.clientX, - y: e.clientY + x: clientX, + y: clientY }; if (Math.abs(this.dragged.x) > 10 || Math.abs(this.dragged.y) > 10) { diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index 5936777..3ca807d 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -295,7 +295,7 @@ export default defineComponent({ } }, methods: { - mouseDown(e: MouseEvent) { + mouseDown(e: MouseEvent | TouchEvent) { this.$emit("mouseDown", e, this.node.id, this.draggable); }, mouseUp() { @@ -309,7 +309,7 @@ export default defineComponent({ mouseLeave() { this.hovering = false; }, - performAction(e: MouseEvent, action: BoardNodeAction) { + performAction(e: MouseEvent | TouchEvent, action: BoardNodeAction) { // If the onClick function made this action selected, // don't propagate the event (which will deselect everything) if (action.onClick(this.node) || this.board.selectedAction === action) { @@ -317,7 +317,7 @@ export default defineComponent({ e.stopPropagation(); } }, - actionMouseUp(e: MouseEvent, action: BoardNodeAction) { + actionMouseUp(e: MouseEvent | TouchEvent, action: BoardNodeAction) { if (this.board.selectedAction === action) { e.preventDefault(); e.stopPropagation(); diff --git a/src/components/system/Nav.vue b/src/components/system/Nav.vue index 8e54b17..93a61b3 100644 --- a/src/components/system/Nav.vue +++ b/src/components/system/Nav.vue @@ -139,6 +139,7 @@ export default defineComponent({ width: 46px; display: flex; cursor: pointer; + flex-shrink: 0; } .overlay-nav { @@ -169,6 +170,9 @@ export default defineComponent({ .nav > .title { width: unset; + flex-shrink: 1; + overflow: hidden; + white-space: nowrap; } .nav .saves, diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 1d34797..fdac1c1 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -167,6 +167,7 @@ const pinAction = { export default { id: "main", display: Main, + minWidth: undefined, startData() { return { openNode: null, diff --git a/src/main.css b/src/main.css index e204b96..519e0e2 100644 --- a/src/main.css +++ b/src/main.css @@ -16,7 +16,6 @@ body { overflow: hidden; - min-width: 640px; transition: none; text-align: center; } From e90aac51f2826e0f1ac6899aa2e3e0cd00ded75a Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Tue, 24 Aug 2021 19:48:07 -0500 Subject: [PATCH 29/49] save before loading new save --- src/components/system/SavesManager.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/system/SavesManager.vue b/src/components/system/SavesManager.vue index bfbcb5a..93073e4 100644 --- a/src/components/system/SavesManager.vue +++ b/src/components/system/SavesManager.vue @@ -181,6 +181,7 @@ export default defineComponent({ }, openSave(id: string) { this.saves[player.id].time = player.time; + save(); loadSave(this.saves[id]); const modData = JSON.parse( decodeURIComponent(escape(atob(localStorage.getItem(modInfo.id)!))) From e642b0e42093688a65f697d2bf07160d3a2e5f5e Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Wed, 25 Aug 2021 00:04:40 -0500 Subject: [PATCH 30/49] Some refactoring of resources --- src/data/layers/main.ts | 300 ++++++++++++++++++-------------- src/typings/features/board.d.ts | 2 +- 2 files changed, 174 insertions(+), 128 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index fdac1c1..29d4506 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -2,20 +2,20 @@ import { ProgressDisplay, Shape } from "@/game/enums"; import { layers } from "@/game/layers"; import player from "@/game/player"; import Decimal, { DecimalSource } from "@/lib/break_eternity"; -import { BoardNodeAction } from "@/typings/features/board"; +import { BoardNode, BoardNodeAction } from "@/typings/features/board"; import { RawLayer } from "@/typings/layer"; import { formatTime } from "@/util/bignum"; import { format, formatWhole } from "@/util/break_eternity"; import { camelToTitle } from "@/util/common"; import { getUniqueNodeID } from "@/util/features"; -import { watch } from "vue"; +import { computed, watch } from "vue"; import themes from "../themes"; import Main from "./Main.vue"; export type ResourceNodeData = { resourceType: string; amount: DecimalSource; - maxAmount: DecimalSource; + [key: string]: any; }; export type ItemNodeData = { @@ -92,8 +92,8 @@ enum LinkType { // Links cause gain/loss of one resource to also affect other resources const links = { time: [ - { resource: "social", amount: 1 / 60, linkType: LinkType.LossOnly }, - { resource: "mental", amount: 1 / 120, linkType: LinkType.LossOnly } + { resource: "social", amount: 1 / (60 * 60), linkType: LinkType.LossOnly }, + { resource: "mental", amount: 1 / (120 * 60), linkType: LinkType.LossOnly } ] } as Record< string, @@ -107,41 +107,25 @@ const links = { for (const resource in links) { const resourceLinks = links[resource]; watch( - () => - (player.layers.main?.boards.main.nodes.find( - node => - node.type === "resource" && - (node.data as ResourceNodeData).resourceType === resource - )?.data as ResourceNodeData | null)?.amount, + () => resources[resource].amount, (amount, oldAmount) => { if (amount == null || oldAmount == null) { return; } const resourceGain = Decimal.sub(amount, oldAmount); resourceLinks.forEach(link => { - switch (link.linkType) { - case LinkType.LossOnly: - if (Decimal.gt(amount, oldAmount)) { - return; - } - break; - case LinkType.GainOnly: - if (Decimal.lt(amount, oldAmount)) { - return; - } - break; + if (link.linkType === LinkType.LossOnly && Decimal.gt(amount, oldAmount)) { + return; } - const node = player.layers.main.boards.main.nodes.find( - node => - node.type === "resource" && - (node.data as ResourceNodeData).resourceType === link.resource - ); - if (node) { - const data = node.data as ResourceNodeData; - data.amount = Decimal.add( - data.amount, + if (link.linkType === LinkType.GainOnly && Decimal.lt(amount, oldAmount)) { + return; + } + const resource = resources[link.resource]; + if (resource.amount != null) { + resource.amount = Decimal.add( + resource.amount, Decimal.times(link.amount, resourceGain) - ).clamp(0, data.maxAmount); + ); } }); } @@ -164,6 +148,53 @@ const pinAction = { } } as BoardNodeAction; +type Resource = { + readonly name: string; + readonly color: string; + readonly node: BoardNode | undefined; + amount: DecimalSource | undefined; + readonly maxAmount: DecimalSource; +}; + +const resources = { + time: createResource("time", "#3EB48933", 24 * 60 * 60), + energy: createResource("energy", "#FFA50033", 100), + social: createResource("social", "#80008033", 100), + mental: createResource("mental", "#32CD3233", 100), + focus: createResource("focus", "#0000FF33", 100) +} as Record; + +function createResource(name: string, color: string, maxAmount: DecimalSource): Resource { + const node = computed(() => + player.layers.main?.boards.main.nodes.find( + node => + node.type === "resource" && (node.data as ResourceNodeData).resourceType === name + ) + ); + const data = computed(() => node.value?.data as ResourceNodeData); + return { + name, + color, + get node() { + return node.value; + }, + get amount() { + return data.value?.amount; + }, + set amount(amount: DecimalSource) { + data.value.amount = Decimal.clamp(amount, 0, maxAmount); + }, + maxAmount + }; +} + +function getResource(node: BoardNode): Resource | undefined { + return Object.values(resources).find(resource => resource.node === node); +} + +const selectedNode = computed(() => layers.main?.boards?.data.main.selectedNode); +const selectedAction = computed(() => layers.main?.boards?.data.main.selectedAction); + export default { id: "main", display: Main, @@ -196,43 +227,40 @@ export default { type: "resource", data: { resourceType: "time", - amount: new Decimal(24 * 60 * 60), - maxAmount: new Decimal(24 * 60 * 60) + amount: new Decimal(24 * 60 * 60) } }, { - position: { x: 0, y: 0 }, + position: { x: 300, y: 0 }, type: "resource", data: { resourceType: "mental", - amount: new Decimal(100), - maxAmount: new Decimal(100) + amount: new Decimal(100) } }, { - position: { x: 0, y: 0 }, + position: { x: 150, y: 0 }, type: "resource", data: { resourceType: "social", - amount: new Decimal(100), - maxAmount: new Decimal(100) + amount: new Decimal(100) } }, { - position: { x: 0, y: 0 }, + position: { x: -150, y: 0 }, type: "resource", data: { resourceType: "focus", - amount: new Decimal(100), - maxAmount: new Decimal(100) + amount: new Decimal(0), + currentFocus: "" } }, { - position: { x: 0, y: 150 }, - type: "item", + position: { x: -300, y: 0 }, + type: "resource", data: { - itemType: "time", - amount: new Decimal(5 * 60 * 60) + resourceType: "energy", + amount: new Decimal(100) } }, { @@ -251,48 +279,52 @@ export default { return (node.data as ResourceNodeData).resourceType; }, label(node) { - const selectedNode = layers[this.layer].boards!.data[this.id] - .selectedNode; - if ( - selectedNode != node && - player.layers[this.layer].boards[this.id].selectedAction != null - ) { - const action = - player.layers[this.layer].boards[this.id].selectedAction; - switch (action) { + const resource = getResource(node)!; + if (selectedNode.value != node && selectedAction.value != null) { + if (resource && resource.name === "focus") { + const currentFocus = + (resource.node?.data as ResourceNodeData | undefined) + ?.currentFocus === selectedAction.value?.id; + return { + text: currentFocus ? "10%" : "X", + color: currentFocus ? "green" : "black", + pulsing: true + }; + } + switch (selectedAction.value.id) { case "reddit": - if ( - (node.data as ResourceNodeData).resourceType === "time" - ) { - return { text: "30m", color: "red", pulsing: true }; + switch (resource.name) { + case "time": + return { + text: "30m", + color: "red", + pulsing: true + }; + case "energy": + return { + text: "5%", + color: "green", + pulsing: true + }; } break; } } if ( - selectedNode != node && - selectedNode != null && - selectedNode.type === "resource" + selectedNode.value != node && + selectedNode.value != null && + selectedNode.value.type === "resource" ) { - const data = selectedNode.data as ResourceNodeData; - if (data.resourceType in links) { - const link = links[data.resourceType].find( - link => - link.resource === - (node.data as ResourceNodeData).resourceType + const selectedResource = getResource(selectedNode.value); + if (selectedResource && selectedResource.name in links) { + const link = links[selectedResource.name].find( + link => link.resource === resource.name ); if (link) { let text; - if ( - (node.data as ResourceNodeData).resourceType === "time" - ) { + if (resource.name === "time") { text = formatTime(link.amount); - } else if ( - Decimal.eq( - (node.data as ResourceNodeData).maxAmount, - 100 - ) - ) { + } else if (Decimal.eq(resource.maxAmount, 100)) { text = formatWhole(link.amount) + "%"; } else { text = format(link.amount); @@ -305,12 +337,12 @@ export default { } } } - if (selectedNode == node || node.pinned) { + if (selectedNode.value == node || node.pinned) { const data = node.data as ResourceNodeData; if (data.resourceType === "time") { return { text: formatTime(data.amount), color: "#0FF3" }; } - if (Decimal.eq(data.maxAmount, 100)) { + if (Decimal.eq(resource.maxAmount, 100)) { return { text: formatWhole(data.amount) + "%", color: "#0FF3" }; } return { text: format(data.amount), color: "#0FF3" }; @@ -318,27 +350,28 @@ export default { }, draggable: true, progress(node) { - const data = node.data as ResourceNodeData; - return Decimal.div(data.amount, data.maxAmount).toNumber(); + const resource = getResource(node)!; + return Decimal.div(resource.amount || 0, resource.maxAmount).toNumber(); }, fillColor() { return themes[player.theme].variables["--background"]; }, progressColor(node) { - return "#0FF3"; + return getResource(node)!.color; }, canAccept(node, otherNode) { return otherNode.type === "item"; }, onDrop(node, otherNode) { + const resource = getResource(node)!; const index = player.layers[this.layer].boards[this.id].nodes.indexOf( otherNode ); player.layers[this.layer].boards[this.id].nodes.splice(index, 1); - (node.data as ResourceNodeData).amount = Decimal.add( - (node.data as ResourceNodeData).amount, + resource.amount = Decimal.add( + resource.amount || 0, (otherNode.data as ItemNodeData).amount - ).min((node.data as ResourceNodeData).maxAmount); + ); }, actions: [pinAction] }, @@ -352,10 +385,7 @@ export default { } }, label(node) { - if ( - player.layers[this.layer].boards[this.id].selectedNode == node.id || - node.pinned - ) { + if (selectedNode.value == node || node.pinned) { const data = node.data as ItemNodeData; if (data.itemType === "time") { return { text: formatTime(data.amount), color: "#0FF3" }; @@ -393,23 +423,34 @@ export default { icon: "reddit", tooltip: "Browse Reddit", onClick(node) { - if (player.layers.main.boards.main.selectedAction === this.id) { - const timeNode = player.layers.main.boards.main.nodes.find( - node => - node.type === "resource" && - (node.data as ResourceNodeData).resourceType === - "time" - ); - if (timeNode) { - (timeNode.data as ResourceNodeData).amount = Decimal.sub( - (timeNode.data as ResourceNodeData).amount, - 30 * 60 - ); - player.layers.main.boards.main.selectedAction = null; - (node.data as ActionNodeData).log.push( - getRandomEvent(redditEvents)! + if (selectedAction.value?.id === this.id) { + const focusData = resources.focus.node + ?.data as ResourceNodeData; + if (focusData.currentFocus === "reddit") { + resources.focus.amount = Decimal.add( + resources.focus.amount || 0, + 10 ); + } else { + focusData.currentFocus = "reddit"; + resources.focus.amount = 10; } + const focusMult = Decimal.div( + resources.focus.amount, + 100 + ).add(1); + resources.time.amount = Decimal.sub( + resources.time.amount || 0, + Decimal.times(30 * 60, focusMult) + ); + resources.energy.amount = Decimal.sub( + resources.energy.amount || 0, + Decimal.times(5, focusMult) + ); + player.layers.main.boards.main.selectedAction = null; + (node.data as ActionNodeData).log.push( + getRandomEvent(redditEvents)! + ); } else { player.layers.main.boards.main.selectedAction = this.id; } @@ -417,18 +458,29 @@ export default { links(node) { return [ { - // TODO this is ridiculous and needs some utility - // function to shrink it down - from: player.layers.main.boards.main.nodes.find( - node => - node.type === "resource" && - (node.data as ResourceNodeData).resourceType === - "time" - ), + from: resources.time.node, to: node, stroke: "red", "stroke-width": 4, pulsing: true + }, + { + from: resources.energy.node, + to: node, + stroke: "green", + "stroke-width": 4, + pulsing: true + }, + { + from: resources.focus.node, + to: node, + stroke: + (resources.focus.node?.data as ResourceNodeData) + .currentFocus === selectedAction.value?.id + ? "green" + : "black", + "stroke-width": 4, + pulsing: true } ]; } @@ -443,27 +495,21 @@ export default { } return this.selectedAction!.links; } - if (player.layers[this.layer].boards[this.id].selectedNode == null) { + if (selectedNode.value == null) { return null; } - const selectedNode = layers[this.layer].boards!.data[this.id].selectedNode; - if (selectedNode.type === "resource") { - const data = selectedNode.data as ResourceNodeData; - if (data.resourceType in links) { - return links[data.resourceType].map(link => { - const node = player.layers.main.boards.main.nodes.find( - node => - node.type === "resource" && - (node.data as ResourceNodeData).resourceType === - link.resource - ); + if (selectedNode.value.type === "resource") { + const resource = getResource(selectedNode.value)!; + if (resource.name in links) { + return links[resource.name].map(link => { + const linkResource = resources[link.resource]; let negativeLink = Decimal.lt(link.amount, 0); if (link.linkType === LinkType.LossOnly) { negativeLink = !negativeLink; } return { - from: selectedNode, - to: node, + from: selectedNode.value, + to: linkResource.node, stroke: negativeLink ? "red" : "green", "stroke-width": 4, pulsing: true diff --git a/src/typings/features/board.d.ts b/src/typings/features/board.d.ts index 69d462e..bc224b6 100644 --- a/src/typings/features/board.d.ts +++ b/src/typings/features/board.d.ts @@ -65,13 +65,13 @@ export interface BoardNodeAction { tooltip: string | ((node: BoardNode) => string); onClick: (node: BoardNode) => boolean | undefined; links?: BoardNodeLink[] | ((node: BoardNode) => BoardNodeLink[]); + [key: string]: any; } export interface BoardNodeLink { from: BoardNode; to: BoardNode; stroke: string; - strokeWidth: number | string; pulsing?: boolean; [key: string]: any; } From 1ee8d2a41c5d5dcb711f7aae697a201831d186f4 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Wed, 25 Aug 2021 08:41:49 -0500 Subject: [PATCH 31/49] Fixed issue with registering things out of order --- src/data/layers/main.ts | 94 ++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 29d4506..269a4e4 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -28,6 +28,53 @@ export type ActionNodeData = { log: LogEntry[]; }; +type Resource = { + readonly name: string; + readonly color: string; + readonly node: BoardNode | undefined; + amount: DecimalSource | undefined; + readonly maxAmount: DecimalSource; +}; + +const resources = { + time: createResource("time", "#3EB48933", 24 * 60 * 60), + energy: createResource("energy", "#FFA50033", 100), + social: createResource("social", "#80008033", 100), + mental: createResource("mental", "#32CD3233", 100), + focus: createResource("focus", "#0000FF33", 100) +} as Record; + +function createResource(name: string, color: string, maxAmount: DecimalSource): Resource { + const node = computed(() => + player.layers.main?.boards.main.nodes.find( + node => + node.type === "resource" && (node.data as ResourceNodeData).resourceType === name + ) + ); + const data = computed(() => node.value?.data as ResourceNodeData); + return { + name, + color, + get node() { + return node.value; + }, + get amount() { + return data.value?.amount; + }, + set amount(amount: DecimalSource) { + data.value.amount = Decimal.clamp(amount, 0, maxAmount); + }, + maxAmount + }; +} + +function getResource(node: BoardNode): Resource | undefined { + return Object.values(resources).find(resource => resource.node === node); +} + +const selectedNode = computed(() => layers.main?.boards?.data.main.selectedNode); +const selectedAction = computed(() => layers.main?.boards?.data.main.selectedAction); + export type LogEntry = { description: string; effectDescription?: string; @@ -148,53 +195,6 @@ const pinAction = { } } as BoardNodeAction; -type Resource = { - readonly name: string; - readonly color: string; - readonly node: BoardNode | undefined; - amount: DecimalSource | undefined; - readonly maxAmount: DecimalSource; -}; - -const resources = { - time: createResource("time", "#3EB48933", 24 * 60 * 60), - energy: createResource("energy", "#FFA50033", 100), - social: createResource("social", "#80008033", 100), - mental: createResource("mental", "#32CD3233", 100), - focus: createResource("focus", "#0000FF33", 100) -} as Record; - -function createResource(name: string, color: string, maxAmount: DecimalSource): Resource { - const node = computed(() => - player.layers.main?.boards.main.nodes.find( - node => - node.type === "resource" && (node.data as ResourceNodeData).resourceType === name - ) - ); - const data = computed(() => node.value?.data as ResourceNodeData); - return { - name, - color, - get node() { - return node.value; - }, - get amount() { - return data.value?.amount; - }, - set amount(amount: DecimalSource) { - data.value.amount = Decimal.clamp(amount, 0, maxAmount); - }, - maxAmount - }; -} - -function getResource(node: BoardNode): Resource | undefined { - return Object.values(resources).find(resource => resource.node === node); -} - -const selectedNode = computed(() => layers.main?.boards?.data.main.selectedNode); -const selectedAction = computed(() => layers.main?.boards?.data.main.selectedAction); - export default { id: "main", display: Main, From ae0fbd09eb1c4eee9a90cff9e8c24332c0c1dc96 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 00:04:51 -0500 Subject: [PATCH 32/49] Refactored actions and added Bed node --- src/data/layers/main.ts | 725 +++++++++++++++++++++++-------------- src/util/break_eternity.ts | 5 +- 2 files changed, 462 insertions(+), 268 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 269a4e4..214ba73 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -2,7 +2,14 @@ import { ProgressDisplay, Shape } from "@/game/enums"; import { layers } from "@/game/layers"; import player from "@/game/player"; import Decimal, { DecimalSource } from "@/lib/break_eternity"; -import { BoardNode, BoardNodeAction } from "@/typings/features/board"; +import { + Board, + BoardNode, + BoardNodeAction, + BoardNodeLink, + NodeType +} from "@/typings/features/board"; +import { RawFeature } from "@/typings/features/feature"; import { RawLayer } from "@/typings/layer"; import { formatTime } from "@/util/bignum"; import { format, formatWhole } from "@/util/break_eternity"; @@ -12,18 +19,19 @@ import { computed, watch } from "vue"; import themes from "../themes"; import Main from "./Main.vue"; -export type ResourceNodeData = { +type ResourceNodeData = { resourceType: string; amount: DecimalSource; - [key: string]: any; + [key: string]: unknown; }; -export type ItemNodeData = { - itemType: string; +type ItemNodeData = { + resource: string; amount: DecimalSource; + display: string; }; -export type ActionNodeData = { +type ActionNodeData = { actionType: string; log: LogEntry[]; }; @@ -31,49 +39,71 @@ export type ActionNodeData = { type Resource = { readonly name: string; readonly color: string; - readonly node: BoardNode | undefined; - amount: DecimalSource | undefined; + readonly node: BoardNode; readonly maxAmount: DecimalSource; + amount: DecimalSource; }; const resources = { - time: createResource("time", "#3EB48933", 24 * 60 * 60), - energy: createResource("energy", "#FFA50033", 100), - social: createResource("social", "#80008033", 100), - mental: createResource("mental", "#32CD3233", 100), - focus: createResource("focus", "#0000FF33", 100) + time: createResource("time", "#3EB48933", 24 * 60 * 60, 24 * 60 * 60), + energy: createResource("energy", "#FFA50033", 100, 100), + social: createResource("social", "#80008033", 100, 100), + mental: createResource("mental", "#32CD3233", 100, 100), + focus: createResource("focus", "#0000FF33", 100, 0) } as Record; -function createResource(name: string, color: string, maxAmount: DecimalSource): Resource { +function createResource( + name: string, + color: string, + maxAmount: DecimalSource, + defaultAmount: DecimalSource +): Resource { const node = computed(() => player.layers.main?.boards.main.nodes.find( node => node.type === "resource" && (node.data as ResourceNodeData).resourceType === name ) ); - const data = computed(() => node.value?.data as ResourceNodeData); return { name, color, get node() { + // Should only run once, but this tricks TS into knowing node.value exists + while (node.value == null) { + player.layers.main.boards.main.nodes.push({ + id: getUniqueNodeID(layers.main.boards!.data.main), + position: { x: 0, y: 150 }, // TODO function to get nearest unoccupied space + type: "resource", + data: { + resourceType: name, + amount: defaultAmount + } + }); + } return node.value; }, get amount() { - return data.value?.amount; + return node.value ? (node.value.data as ResourceNodeData).amount : defaultAmount; }, set amount(amount: DecimalSource) { - data.value.amount = Decimal.clamp(amount, 0, maxAmount); + (this.node.data as ResourceNodeData).amount = Decimal.clamp(amount, 0, maxAmount); }, maxAmount }; } -function getResource(node: BoardNode): Resource | undefined { - return Object.values(resources).find(resource => resource.node === node); +function getResource(node: BoardNode): Resource { + const resource = Object.values(resources).find(resource => resource.node === node); + if (resource == null) { + console.error("No resource associated with node", node); + throw Error(); + } + return resource; } const selectedNode = computed(() => layers.main?.boards?.data.main.selectedNode); const selectedAction = computed(() => layers.main?.boards?.data.main.selectedAction); +const focusMult = computed(() => Decimal.div(resources.focus.amount, 100).add(1)); export type LogEntry = { description: string; @@ -85,31 +115,190 @@ export type WeightedEvent = { weight: number; }; -const redditEvents = [ - { - event: () => ({ description: "You blink and half an hour has passed before you know it." }), - weight: 1 +function createItem(resource: string, amount: DecimalSource, display?: string) { + display = display || camelToTitle(resource); + const item = { + id: getUniqueNodeID(layers.main.boards!.data.main), + position: { x: 0, y: 150 }, // TODO function to get nearest unoccupied space + type: "item", + data: { resource, amount, display } as ItemNodeData + }; + player.layers.main.boards.main.nodes.push(item); + return item; +} + +type Action = { + icon: string; + fillColor?: string; + tooltip?: string; + events: Array<{ + event: () => LogEntry; + weight: number; + }>; + baseChanges: Array<{ + resource: string; + amount: DecimalSource; + assign?: boolean; + }>; +}; + +const actions = { + reddit: { + icon: "reddit", + tooltip: "Browse Reddit", + events: [ + { + event: () => ({ + description: "You blink and half an hour has passed before you know it." + }), + weight: 1 + }, + { + event: () => { + createItem("time", 15 * 60, "Speed"); + return { + description: + "You found some funny memes and actually feel a bit refreshed.", + effectDescription: `Added Speed node` + }; + }, + weight: 0.5 + } + ], + baseChanges: [ + { resource: "time", amount: -30 * 60 }, + { resource: "energy", amount: 5 } + ] }, - { - event: () => { - const id = getUniqueNodeID(layers.main.boards!.data.main); - player.layers.main.boards.main.nodes.push({ - id, - position: { x: 0, y: 150 }, // TODO function to get nearest unoccupied space - type: "item", - data: { - itemType: "time", - amount: new Decimal(15 * 60) + sleep: { + icon: "bed", + tooltip: "Sleep", + events: [ + { + event: () => ({ description: "You have a normal evening of undisturbed sleep" }), + weight: 90 + }, + { + event: () => { + resources.energy.amount = 50; + return { + description: "You had a very restless sleep filled with nightmares :(", + effectDescription: `50% Energy` + }; + }, + weight() { + return Decimal.sub(100, resources.mental.amount || 100); } - }); - return { - description: "You found some funny memes and actually feel a bit refreshed.", - effectDescription: `Added Speed node` - }; - }, - weight: 0.5 + }, + { + event: () => { + createItem("energy", 25, "Refreshed"); + return { + description: + "You dreamt of your future and woke up feeling extra refreshed", + effectDescription: `Added Refreshed node` + }; + }, + weight() { + return Decimal.sub(resources.mental.amount || 100, 75).max(5); + } + } + ], + baseChanges: [ + { resource: "time", amount: -8 * 30 * 60 }, + { resource: "energy", amount: 100, assign: true } + ] + }, + rest: { + icon: "chair", + tooltip: "Rest", + events: [ + { + event: () => { + resources.energy.amount = Decimal.sub( + resources.energy.amount || 100, + Decimal.times(10, focusMult.value) + ); + return { description: "You rest your eyes for a bit and wake up rejuvenated" }; + }, + weight: 90 + }, + { + event: () => ({ + description: + "You close your eyes and it feels like no time has gone by before you wake up with a start, slightly less rested than you feel you should be given the time that's passed", + effectDescription: `-25% effective Energy restoration` + }), + weight: 5 + }, + { + event: () => { + resources.energy.amount = Decimal.add( + resources.energy.amount, + Decimal.times(20, focusMult.value) + ); + return { + description: + "You take an incredible power nap and wake up significantly more refreshed", + effectDescription: `+50% effectvie Energy restoration` + }; + }, + weight: 5 + } + ], + baseChanges: [ + { resource: "time", amount: -4 * 30 * 60 }, + // 30 is the lowest it can be from any event + // typically you'll get 40 though + { resource: "energy", amount: 30 } + ] } -]; +} as Record; + +const pinAction = { + id: "pin", + icon: "push_pin", + fillColor(node) { + if (node.pinned) { + return themes[player.theme].variables["--bought"]; + } + return themes[player.theme].variables["--secondary-background"]; + }, + tooltip: "Always show resource", + onClick(node) { + node.pinned = !node.pinned; + return true; + } +} as BoardNodeAction; + +const logAction = { + id: "info", + icon: "history_edu", + fillColor() { + return themes[player.theme].variables["--secondary-background"]; + }, + tooltip: "Log", + onClick(node) { + player.layers.main.openNode = node.id; + player.layers.main.showModal = true; + } +} as BoardNodeAction; + +type ActionNode = { + actions: string[]; + display: string; +}; + +const actionNodes = { + web: { + actions: ["reddit"], + display: "Web" + }, + bed: { + actions: ["sleep", "rest"], + display: "Bed" + } +} as Record; function getRandomEvent(events: WeightedEvent[]): LogEntry | null { if (events.length === 0) { @@ -179,21 +368,206 @@ for (const resource in links) { ); } -const pinAction = { - id: "pin", - icon: "push_pin", - fillColor(node) { - if (node.pinned) { - return themes[player.theme].variables["--bought"]; - } - return themes[player.theme].variables["--secondary-background"]; +const resourceNodeType = { + title(node) { + return (node.data as ResourceNodeData).resourceType; }, - tooltip: "Always show resource", - onClick(node) { - node.pinned = !node.pinned; - return true; + label(node) { + const resource = getResource(node); + if (selectedNode.value != node && selectedAction.value != null) { + if (resource.name === "focus") { + const currentFocus = + (resource.node.data as ResourceNodeData).currentFocus === + selectedAction.value?.id; + return { + text: currentFocus ? "10%" : "X", + color: currentFocus ? "green" : "black", + pulsing: true + }; + } + const action = actions[selectedAction.value.id]; + const change = action.baseChanges.find(change => change.resource === resource.name); + if (change != null) { + let text; + if (resource.name === "time") { + text = formatTime(change.amount); + } else if (Decimal.eq(resource.maxAmount, 100)) { + text = formatWhole(change.amount) + "%"; + } else { + text = format(change.amount); + } + let color; + if (change.assign) { + color = "black"; + } else { + color = Decimal.gt(change.amount, 0) ? "green" : "red"; + } + return { text, color, pulsing: true }; + } + } + + if ( + selectedNode.value != node && + selectedNode.value != null && + selectedNode.value.type === "resource" + ) { + const selectedResource = getResource(selectedNode.value); + if (selectedResource.name in links) { + const link = links[selectedResource.name].find( + link => link.resource === resource.name + ); + if (link) { + let text; + if (resource.name === "time") { + text = formatTime(link.amount); + } else if (Decimal.eq(resource.maxAmount, 100)) { + text = formatWhole(link.amount) + "%"; + } else { + text = format(link.amount); + } + let negativeLink = Decimal.lt(link.amount, 0); + if (link.linkType === LinkType.LossOnly) { + negativeLink = !negativeLink; + } + return { text, color: negativeLink ? "red" : "green" }; + } + } + } + + if (selectedNode.value == node || node.pinned) { + const data = node.data as ResourceNodeData; + if (data.resourceType === "time") { + return { text: formatTime(data.amount), color: resource.color }; + } + if (Decimal.eq(resource.maxAmount, 100)) { + return { + text: formatWhole(data.amount) + "%", + color: resource.color + }; + } + return { text: format(data.amount), color: resource.color }; + } + }, + draggable: true, + progress(node) { + const resource = getResource(node); + return Decimal.div(resource.amount, resource.maxAmount).toNumber(); + }, + fillColor() { + return themes[player.theme].variables["--background"]; + }, + progressColor(node) { + return getResource(node).color; + }, + canAccept(node, otherNode) { + return ( + otherNode.type === "item" && + (otherNode.data as ItemNodeData).resource === getResource(node).name + ); + }, + onDrop(node, otherNode) { + const resource = getResource(node); + const index = player.layers[this.layer].boards[this.id].nodes.indexOf(otherNode); + player.layers[this.layer].boards[this.id].nodes.splice(index, 1); + resource.amount = Decimal.add(resource.amount, (otherNode.data as ItemNodeData).amount); + }, + actions: [pinAction] +} as RawFeature; + +const actionNodeType = { + title(node) { + return actionNodes[(node.data as ActionNodeData).actionType].display; + }, + label(node) { + if (selectedNode.value == node && selectedAction.value != null) { + return { text: selectedAction.value.tooltip, color: "#000" }; + } + }, + fillColor: "#000", + draggable: true, + shape: Shape.Diamond, + progressColor: "#0FF3", + progressDisplay: ProgressDisplay.Outline, + actions(node) { + const actionNode = actionNodes[(node.data as ActionNodeData).actionType]; + return [ + logAction, + ...actionNode.actions.map(id => { + const action = actions[id]; + return { + id, + icon: action.icon, + tooltip: action.tooltip, + fillColor: action.fillColor, + onClick(node) { + if (selectedAction.value?.id === this.id) { + const focusData = resources.focus.node.data as ResourceNodeData; + if (focusData.currentFocus === id) { + resources.focus.amount = Decimal.add(resources.focus.amount, 10); + } else { + focusData.currentFocus = id; + resources.focus.amount = 10; + } + for (const change of action.baseChanges) { + if (change.assign) { + resources[change.resource].amount = change.amount; + } else if (change.resource === "time") { + // Time isn't affected by focus multiplier + resources.time.amount = Decimal.add( + resources.time.amount, + change.amount + ); + } else { + resources.time.amount = Decimal.add( + resources.time.amount, + Decimal.times(change.amount, focusMult.value) + ); + } + } + player.layers.main.boards.main.selectedAction = null; + const logEntry = getRandomEvent(action.events); + if (logEntry) { + (node.data as ActionNodeData).log.push(logEntry); + } + } else { + player.layers.main.boards.main.selectedAction = this.id; + } + }, + links(node) { + return [ + { + from: resources.focus.node, + to: node, + stroke: + (resources.focus.node.data as ResourceNodeData).currentFocus === + selectedAction.value?.id + ? "green" + : "black", + "stroke-width": 4, + pulsing: true + }, + ...action.baseChanges.map(change => { + let color; + if (change.assign) { + color = "black"; + } else { + color = Decimal.gt(change.amount, 0) ? "green" : "red"; + } + return { + from: resources[change.resource].node, + to: node, + stroke: color, + "stroke-width": 4, + pulsing: true + } as BoardNodeLink; + }) + ]; + } + } as BoardNodeAction; + }) + ]; } -} as BoardNodeAction; +} as RawFeature; export default { id: "main", @@ -228,7 +602,7 @@ export default { data: { resourceType: "time", amount: new Decimal(24 * 60 * 60) - } + } as ResourceNodeData }, { position: { x: 300, y: 0 }, @@ -236,7 +610,7 @@ export default { data: { resourceType: "mental", amount: new Decimal(100) - } + } as ResourceNodeData }, { position: { x: 150, y: 0 }, @@ -244,7 +618,7 @@ export default { data: { resourceType: "social", amount: new Decimal(100) - } + } as ResourceNodeData }, { position: { x: -150, y: 0 }, @@ -253,7 +627,7 @@ export default { resourceType: "focus", amount: new Decimal(0), currentFocus: "" - } + } as ResourceNodeData }, { position: { x: -300, y: 0 }, @@ -261,7 +635,7 @@ export default { data: { resourceType: "energy", amount: new Decimal(100) - } + } as ResourceNodeData }, { position: { x: -150, y: 150 }, @@ -269,237 +643,54 @@ export default { data: { actionType: "web", log: [] - } + } as ActionNodeData + }, + { + position: { x: 150, y: 150 }, + type: "action", + data: { + actionType: "bed", + log: [] + } as ActionNodeData } ]; }, types: { - resource: { - title(node) { - return (node.data as ResourceNodeData).resourceType; - }, - label(node) { - const resource = getResource(node)!; - if (selectedNode.value != node && selectedAction.value != null) { - if (resource && resource.name === "focus") { - const currentFocus = - (resource.node?.data as ResourceNodeData | undefined) - ?.currentFocus === selectedAction.value?.id; - return { - text: currentFocus ? "10%" : "X", - color: currentFocus ? "green" : "black", - pulsing: true - }; - } - switch (selectedAction.value.id) { - case "reddit": - switch (resource.name) { - case "time": - return { - text: "30m", - color: "red", - pulsing: true - }; - case "energy": - return { - text: "5%", - color: "green", - pulsing: true - }; - } - break; - } - } - if ( - selectedNode.value != node && - selectedNode.value != null && - selectedNode.value.type === "resource" - ) { - const selectedResource = getResource(selectedNode.value); - if (selectedResource && selectedResource.name in links) { - const link = links[selectedResource.name].find( - link => link.resource === resource.name - ); - if (link) { - let text; - if (resource.name === "time") { - text = formatTime(link.amount); - } else if (Decimal.eq(resource.maxAmount, 100)) { - text = formatWhole(link.amount) + "%"; - } else { - text = format(link.amount); - } - let negativeLink = Decimal.lt(link.amount, 0); - if (link.linkType === LinkType.LossOnly) { - negativeLink = !negativeLink; - } - return { text, color: negativeLink ? "red" : "green" }; - } - } - } - if (selectedNode.value == node || node.pinned) { - const data = node.data as ResourceNodeData; - if (data.resourceType === "time") { - return { text: formatTime(data.amount), color: "#0FF3" }; - } - if (Decimal.eq(resource.maxAmount, 100)) { - return { text: formatWhole(data.amount) + "%", color: "#0FF3" }; - } - return { text: format(data.amount), color: "#0FF3" }; - } - }, - draggable: true, - progress(node) { - const resource = getResource(node)!; - return Decimal.div(resource.amount || 0, resource.maxAmount).toNumber(); - }, - fillColor() { - return themes[player.theme].variables["--background"]; - }, - progressColor(node) { - return getResource(node)!.color; - }, - canAccept(node, otherNode) { - return otherNode.type === "item"; - }, - onDrop(node, otherNode) { - const resource = getResource(node)!; - const index = player.layers[this.layer].boards[this.id].nodes.indexOf( - otherNode - ); - player.layers[this.layer].boards[this.id].nodes.splice(index, 1); - resource.amount = Decimal.add( - resource.amount || 0, - (otherNode.data as ItemNodeData).amount - ); - }, - actions: [pinAction] - }, + resource: resourceNodeType, + action: actionNodeType, item: { title(node) { - switch ((node.data as ItemNodeData).itemType) { - default: - return null; - case "time": - return "speed"; - } + return (node.data as ItemNodeData).display; }, label(node) { if (selectedNode.value == node || node.pinned) { const data = node.data as ItemNodeData; - if (data.itemType === "time") { - return { text: formatTime(data.amount), color: "#0FF3" }; + const resource = resources[data.resource]; + let text; + if (data.resource === "time") { + text = formatTime(data.amount); + } else if (Decimal.eq(100, resource.maxAmount)) { + text = format(data.amount) + "%"; } - return { text: format(data.amount), color: "#0FF3" }; + return { text, color: resource.color }; } }, draggable: true, actions: [pinAction] - }, - action: { - title(node) { - return camelToTitle((node.data as ActionNodeData).actionType); - }, - fillColor: "#000", - draggable: true, - shape: Shape.Diamond, - progressColor: "#0FF3", - progressDisplay: ProgressDisplay.Outline, - actions: [ - { - id: "info", - icon: "history_edu", - fillColor() { - return themes[player.theme].variables["--secondary-background"]; - }, - tooltip: "Log", - onClick(node) { - player.layers.main.openNode = node.id; - player.layers.main.showModal = true; - } - }, - { - id: "reddit", - icon: "reddit", - tooltip: "Browse Reddit", - onClick(node) { - if (selectedAction.value?.id === this.id) { - const focusData = resources.focus.node - ?.data as ResourceNodeData; - if (focusData.currentFocus === "reddit") { - resources.focus.amount = Decimal.add( - resources.focus.amount || 0, - 10 - ); - } else { - focusData.currentFocus = "reddit"; - resources.focus.amount = 10; - } - const focusMult = Decimal.div( - resources.focus.amount, - 100 - ).add(1); - resources.time.amount = Decimal.sub( - resources.time.amount || 0, - Decimal.times(30 * 60, focusMult) - ); - resources.energy.amount = Decimal.sub( - resources.energy.amount || 0, - Decimal.times(5, focusMult) - ); - player.layers.main.boards.main.selectedAction = null; - (node.data as ActionNodeData).log.push( - getRandomEvent(redditEvents)! - ); - } else { - player.layers.main.boards.main.selectedAction = this.id; - } - }, - links(node) { - return [ - { - from: resources.time.node, - to: node, - stroke: "red", - "stroke-width": 4, - pulsing: true - }, - { - from: resources.energy.node, - to: node, - stroke: "green", - "stroke-width": 4, - pulsing: true - }, - { - from: resources.focus.node, - to: node, - stroke: - (resources.focus.node?.data as ResourceNodeData) - .currentFocus === selectedAction.value?.id - ? "green" - : "black", - "stroke-width": 4, - pulsing: true - } - ]; - } - } - ] } }, - links() { - if (this.selectedAction?.links) { - if (typeof this.selectedAction!.links === "function") { - return this.selectedAction!.links(this.selectedNode); + links(this: Board) { + if (this.selectedNode && this.selectedAction?.links) { + if (typeof this.selectedAction.links === "function") { + return this.selectedAction.links(this.selectedNode); } - return this.selectedAction!.links; + return this.selectedAction.links; } if (selectedNode.value == null) { return null; } if (selectedNode.value.type === "resource") { - const resource = getResource(selectedNode.value)!; + const resource = getResource(selectedNode.value); if (resource.name in links) { return links[resource.name].map(link => { const linkResource = resources[link.resource]; diff --git a/src/util/break_eternity.ts b/src/util/break_eternity.ts index 003d807..57ef17a 100644 --- a/src/util/break_eternity.ts +++ b/src/util/break_eternity.ts @@ -115,6 +115,9 @@ export function formatWhole(num: DecimalSource): string { } export function formatTime(seconds: DecimalSource): string { + if (Decimal.lt(seconds, 0)) { + return "-" + formatTime(Decimal.neg(seconds)); + } if (Decimal.gt(seconds, 2 ** 51)) { // integer precision limit return format(Decimal.div(seconds, 31536000)) + "y"; @@ -130,7 +133,7 @@ export function formatTime(seconds: DecimalSource): string { "h " + formatWhole(Math.floor(seconds / 60) % 60) + "m " + - format(seconds % 60) + + formatWhole(seconds % 60) + "s" ); } else if (seconds < 31536000) { From af57840dc6fd3ec2c5b37a24a3f9eff6dce87522 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 00:13:42 -0500 Subject: [PATCH 33/49] Added animation to nodes appearing/disappearing --- src/components/board/BoardNode.vue | 180 +++++++++++++++-------------- 1 file changed, 91 insertions(+), 89 deletions(-) diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index 3ca807d..2bc3395 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -44,100 +44,97 @@ - - + + + + - + - - - - - + + + + + - + - - - + + + - {{ title }} + {{ title }} + + From 5c23976ec7ae6614493288f669da4492b869fdb0 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 00:29:27 -0500 Subject: [PATCH 35/49] Changed "assign" color to white --- src/data/layers/main.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 214ba73..46620b9 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -381,7 +381,7 @@ const resourceNodeType = { selectedAction.value?.id; return { text: currentFocus ? "10%" : "X", - color: currentFocus ? "green" : "black", + color: currentFocus ? "green" : "white", pulsing: true }; } @@ -398,7 +398,7 @@ const resourceNodeType = { } let color; if (change.assign) { - color = "black"; + color = "white"; } else { color = Decimal.gt(change.amount, 0) ? "green" : "red"; } @@ -542,14 +542,14 @@ const actionNodeType = { (resources.focus.node.data as ResourceNodeData).currentFocus === selectedAction.value?.id ? "green" - : "black", + : "white", "stroke-width": 4, pulsing: true }, ...action.baseChanges.map(change => { let color; if (change.assign) { - color = "black"; + color = "white"; } else { color = Decimal.gt(change.amount, 0) ? "green" : "red"; } From b1d2bab36ffd11a6b9bc8bd3dac9cf632a3ffd15 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 00:44:38 -0500 Subject: [PATCH 36/49] Fixed labels not fading out properly --- src/components/board/BoardNode.vue | 36 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index e1baf43..b644b37 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -11,7 +11,7 @@ v-for="(action, index) in actions" :key="action.id" class="action" - :class="{ selected: selectedAction === action }" + :class="{ selected: selectedAction?.id === action.id }" :transform=" `translate( ${(-size - 30) * @@ -34,7 +34,7 @@ : fillColor " r="20" - :stroke-width="selectedAction === action ? 4 : 0" + :stroke-width="selectedAction?.id === action.id ? 4 : 0" :stroke="outlineColor" /> {{ @@ -88,8 +88,7 @@ :width="size * sqrtTwo + 16" :height="size * sqrtTwo + 16" :transform=" - `translate(${-(size * sqrtTwo + 16) / 2}, ${-(size * sqrtTwo + 16) / - 2})` + `translate(${-(size * sqrtTwo + 16) / 2}, ${-(size * sqrtTwo + 16) / 2})` " :fill="backgroundColor" :stroke="receivingNode ? '#0F0' : '#0F03'" @@ -110,8 +109,10 @@ :width="Math.max(size * sqrtTwo * progress - 2, 0)" :height="Math.max(size * sqrtTwo * progress - 2, 0)" :transform=" - `translate(${-Math.max(size * sqrtTwo * progress - 2, 0) / - 2}, ${-Math.max(size * sqrtTwo * progress - 2, 0) / 2})` + `translate(${-Math.max(size * sqrtTwo * progress - 2, 0) / 2}, ${-Math.max( + size * sqrtTwo * progress - 2, + 0 + ) / 2})` " :fill="progressColor" /> @@ -136,22 +137,23 @@ - {{ label.text }} + + {{ label.text }} + + Tap again to confirm @@ -308,13 +310,13 @@ export default defineComponent({ performAction(e: MouseEvent | TouchEvent, action: BoardNodeAction) { // If the onClick function made this action selected, // don't propagate the event (which will deselect everything) - if (action.onClick(this.node) || this.board.selectedAction === action) { + if (action.onClick(this.node) || this.board.selectedAction?.id === action.id) { e.preventDefault(); e.stopPropagation(); } }, actionMouseUp(e: MouseEvent | TouchEvent, action: BoardNodeAction) { - if (this.board.selectedAction === action) { + if (this.board.selectedAction?.id === action.id) { e.preventDefault(); e.stopPropagation(); } From 7890c1c298fed9624c24eebb01507c00ad376455 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 00:52:23 -0500 Subject: [PATCH 37/49] Made resource colors non-transparent --- src/data/layers/main.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index 46620b9..a55b03e 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -45,11 +45,11 @@ type Resource = { }; const resources = { - time: createResource("time", "#3EB48933", 24 * 60 * 60, 24 * 60 * 60), - energy: createResource("energy", "#FFA50033", 100, 100), - social: createResource("social", "#80008033", 100, 100), - mental: createResource("mental", "#32CD3233", 100, 100), - focus: createResource("focus", "#0000FF33", 100, 0) + time: createResource("time", "#3EB489", 24 * 60 * 60, 24 * 60 * 60), + energy: createResource("energy", "#FFA500", 100, 100), + social: createResource("social", "#800080", 100, 100), + mental: createResource("mental", "#32CD32", 100, 100), + focus: createResource("focus", "#0000FF", 100, 0) } as Record; function createResource( @@ -486,7 +486,7 @@ const actionNodeType = { fillColor: "#000", draggable: true, shape: Shape.Diamond, - progressColor: "#0FF3", + progressColor: "#000", progressDisplay: ProgressDisplay.Outline, actions(node) { const actionNode = actionNodes[(node.data as ActionNodeData).actionType]; From 0e4cf7ebbce49a92f3d3f2ba8ab164ec03327c14 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 00:57:33 -0500 Subject: [PATCH 38/49] Moved links into resources objects --- src/data/layers/main.ts | 62 +++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/data/layers/main.ts b/src/data/layers/main.ts index a55b03e..a47fb49 100644 --- a/src/data/layers/main.ts +++ b/src/data/layers/main.ts @@ -36,16 +36,33 @@ type ActionNodeData = { log: LogEntry[]; }; +enum LinkType { + LossOnly, + GainOnly, + Both +} + +// Links cause gain/loss of one resource to also affect other resources +type ResourceLink = { + resource: string; + amount: DecimalSource; + linkType: LinkType; +}; + type Resource = { readonly name: string; readonly color: string; readonly node: BoardNode; + readonly links?: ResourceLink[]; readonly maxAmount: DecimalSource; amount: DecimalSource; }; const resources = { - time: createResource("time", "#3EB489", 24 * 60 * 60, 24 * 60 * 60), + time: createResource("time", "#3EB489", 24 * 60 * 60, 24 * 60 * 60, [ + { resource: "social", amount: 1 / (60 * 60), linkType: LinkType.LossOnly }, + { resource: "mental", amount: 1 / (120 * 60), linkType: LinkType.LossOnly } + ]), energy: createResource("energy", "#FFA500", 100, 100), social: createResource("social", "#800080", 100, 100), mental: createResource("mental", "#32CD32", 100, 100), @@ -56,7 +73,8 @@ function createResource( name: string, color: string, maxAmount: DecimalSource, - defaultAmount: DecimalSource + defaultAmount: DecimalSource, + links?: ResourceLink[] ): Resource { const node = computed(() => player.layers.main?.boards.main.nodes.find( @@ -67,6 +85,7 @@ function createResource( return { name, color, + links, get node() { // Should only run once, but this tricks TS into knowing node.value exists while (node.value == null) { @@ -319,37 +338,16 @@ function getRandomEvent(events: WeightedEvent[]): LogEntry | null { return null; } -enum LinkType { - LossOnly, - GainOnly, - Both -} - -// Links cause gain/loss of one resource to also affect other resources -const links = { - time: [ - { resource: "social", amount: 1 / (60 * 60), linkType: LinkType.LossOnly }, - { resource: "mental", amount: 1 / (120 * 60), linkType: LinkType.LossOnly } - ] -} as Record< - string, - { - resource: string; - amount: DecimalSource; - linkType: LinkType; - }[] ->; - -for (const resource in links) { - const resourceLinks = links[resource]; +for (const id in resources) { + const resource = resources[id]; watch( - () => resources[resource].amount, + () => resource.amount, (amount, oldAmount) => { if (amount == null || oldAmount == null) { return; } const resourceGain = Decimal.sub(amount, oldAmount); - resourceLinks.forEach(link => { + resource.links?.forEach(link => { if (link.linkType === LinkType.LossOnly && Decimal.gt(amount, oldAmount)) { return; } @@ -412,10 +410,8 @@ const resourceNodeType = { selectedNode.value.type === "resource" ) { const selectedResource = getResource(selectedNode.value); - if (selectedResource.name in links) { - const link = links[selectedResource.name].find( - link => link.resource === resource.name - ); + if (selectedResource.links) { + const link = selectedResource.links.find(link => link.resource === resource.name); if (link) { let text; if (resource.name === "time") { @@ -691,8 +687,8 @@ export default { } if (selectedNode.value.type === "resource") { const resource = getResource(selectedNode.value); - if (resource.name in links) { - return links[resource.name].map(link => { + if (resource.links) { + return resource.links.map(link => { const linkResource = resources[link.resource]; let negativeLink = Decimal.lt(link.amount, 0); if (link.linkType === LinkType.LossOnly) { From 116e6a47ec2f847e9027afd1c5bcecf8f63ecd16 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 18:15:05 -0500 Subject: [PATCH 39/49] Added nordic theme --- src/data/themes.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/data/themes.ts b/src/data/themes.ts index 35b8eaa..0e38c30 100644 --- a/src/data/themes.ts +++ b/src/data/themes.ts @@ -23,6 +23,7 @@ const defaultTheme: Theme = { export enum Themes { Classic = "classic", Paper = "paper", + Nordic = "nordic", Aqua = "aqua" } @@ -44,6 +45,27 @@ export default { stackedInfoboxes: true, floatingTabs: false } as Theme, + // Based on https://www.nordtheme.com + nordic: { + ...defaultTheme, + variables: { + ...defaultTheme.variables, + "--color": "#D8DEE9", + "--points": "#E5E9F0", + "--background": "#2E3440", + "--secondary-background": "#3B4252", + "--locked": "#3B4252", + "--bought": "#8FBCBB", + "--link": "#88C0D0", + "--separator": "#3B4252", + "--border-radius": "4px", + "--danger": "#D08770", + "--modal-border": "solid 2px #3B4252", + "--feature-margin": "5px" + }, + stackedInfoboxes: true, + floatingTabs: false + } as Theme, aqua: { ...defaultTheme, variables: { From f516a3a09282c504a2c9ea9cef4515e4959aa5b4 Mon Sep 17 00:00:00 2001 From: thepaperpilot Date: Thu, 26 Aug 2021 22:01:56 -0500 Subject: [PATCH 40/49] Implemented force sleep and rest actions --- src/components/board/BoardNode.vue | 15 +- src/data/layers/main.ts | 260 +++++++++++++++++++++-------- 2 files changed, 207 insertions(+), 68 deletions(-) diff --git a/src/components/board/BoardNode.vue b/src/components/board/BoardNode.vue index b644b37..ac2d12e 100644 --- a/src/components/board/BoardNode.vue +++ b/src/components/board/BoardNode.vue @@ -1,6 +1,7 @@