Make layers lazy instantiate

This commit is contained in:
thepaperpilot 2022-01-27 22:47:26 -06:00
parent 90e49e196f
commit 067ba6ce90
8 changed files with 929 additions and 909 deletions

View file

@ -118,6 +118,7 @@ export type LayerTreeNode<T extends LayerTreeNodeOptions> = Replace<
append: ProcessedComputable<boolean>; append: ProcessedComputable<boolean>;
} }
>; >;
export type GenericLayerTreeNode = LayerTreeNode<LayerTreeNodeOptions>;
export function createLayerTreeNode<T extends LayerTreeNodeOptions>(options: T): LayerTreeNode<T> { export function createLayerTreeNode<T extends LayerTreeNodeOptions>(options: T): LayerTreeNode<T> {
processComputable(options as T, "append"); processComputable(options as T, "append");

View file

@ -1,5 +1,5 @@
import Tooltip from "@/components/system/Tooltip.vue"; import Tooltip from "@/components/system/Tooltip.vue";
import { points as mainPoints } from "@/data/mod"; import { main } from "@/data/mod";
import { createAchievement } from "@/features/achievement"; import { createAchievement } from "@/features/achievement";
import { createGrid } from "@/features/grid"; import { createGrid } from "@/features/grid";
import { createResource } from "@/features/resource"; import { createResource } from "@/features/resource";
@ -8,21 +8,22 @@ import { createLayer } from "@/game/layers";
import { DecimalSource } from "@/lib/break_eternity"; import { DecimalSource } from "@/lib/break_eternity";
import Decimal from "@/util/bignum"; import Decimal from "@/util/bignum";
import { render, renderRow } from "@/util/vue"; import { render, renderRow } from "@/util/vue";
import { points as fPoints } from "./f"; import f from "./f";
const id = "a"; const layer = createLayer(() => {
const color = "yellow"; const id = "a";
const name = "Achievements"; const color = "yellow";
const points = createResource<DecimalSource>(0, "achievement power"); const name = "Achievements";
const points = createResource<DecimalSource>(0, "achievement power");
export const treeNode = createTreeNode({ const treeNode = createTreeNode({
tooltip: "Achievements", tooltip: "Achievements",
onClick() { onClick() {
// TODO open this layer as a modal // TODO open this layer as a modal
} }
}); });
const ach1 = createAchievement({ const ach1 = createAchievement({
image: "https://unsoftcapped2.github.io/The-Modding-Tree-2/discord.png", image: "https://unsoftcapped2.github.io/The-Modding-Tree-2/discord.png",
display: "Get me!", display: "Get me!",
tooltip() { tooltip() {
@ -32,8 +33,8 @@ const ach1 = createAchievement({
return "How did this happen?"; return "How did this happen?";
}, },
shouldEarn: true shouldEarn: true
}); });
const ach2 = createAchievement({ const ach2 = createAchievement({
display: "Impossible!", display: "Impossible!",
tooltip() { tooltip() {
if (this.earned.value) { if (this.earned.value) {
@ -42,21 +43,21 @@ const ach2 = createAchievement({
return "Mwahahaha!"; return "Mwahahaha!";
}, },
style: { color: "#04e050" } style: { color: "#04e050" }
}); });
const ach3 = createAchievement({ const ach3 = createAchievement({
display: "EIEIO", display: "EIEIO",
tooltip: tooltip:
"Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).", "Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).",
shouldEarn: function () { shouldEarn: function () {
return Decimal.gte(fPoints.value, 1); return Decimal.gte(f.value.points.value, 1);
}, },
onComplete() { onComplete() {
console.log("Bork bork bork!"); console.log("Bork bork bork!");
} }
}); });
const achievements = [ach1, ach2, ach3]; const achievements = [ach1, ach2, ach3];
const grid = createGrid({ const grid = createGrid({
rows: 2, rows: 2,
cols: 2, cols: 2,
getStartState(id) { getStartState(id) {
@ -86,22 +87,22 @@ const grid = createGrid({
getDisplay(id) { getDisplay(id) {
return String(id); return String(id);
}, },
getCanClick() { getCanClick(): boolean {
return Decimal.eq(mainPoints.value, 10); return Decimal.eq(main.value.points.value, 10);
}, },
onClick(id, state) { onClick(id, state) {
this.cells[id].state = Number(state) + 1; this.cells[id].state = Number(state) + 1;
} }
}); });
const display = ( const display = (
<template> <template>
{renderRow(achievements)} {renderRow(achievements)}
{render(grid)} {render(grid)}
</template> </template>
); );
const layer = createLayer({ return {
id, id,
color, color,
name, name,
@ -110,6 +111,7 @@ const layer = createLayer({
grid, grid,
treeNode, treeNode,
display display
};
}); });
export default layer; export default layer;

View file

@ -9,13 +9,13 @@ import Spacer from "@/components/system/Spacer.vue";
import Sticky from "@/components/system/Sticky.vue"; import Sticky from "@/components/system/Sticky.vue";
import VerticalRule from "@/components/system/VerticalRule.vue"; import VerticalRule from "@/components/system/VerticalRule.vue";
import { createLayerTreeNode, createResetButton } from "@/data/common"; import { createLayerTreeNode, createResetButton } from "@/data/common";
import { points as mainPoints, tree as mainTree } from "@/data/mod"; import { main } from "@/data/mod";
import { createBar, Direction } from "@/features/bar"; import { createBar, Direction } from "@/features/bar";
import { createBuyable } from "@/features/buyable"; import { createBuyable } from "@/features/buyable";
import { createChallenge } from "@/features/challenge"; import { createChallenge } from "@/features/challenge";
import { createClickable } from "@/features/clickable"; import { createClickable } from "@/features/clickable";
import { createCumulativeConversion, createExponentialScaling } from "@/features/conversion"; import { createCumulativeConversion, createExponentialScaling } from "@/features/conversion";
import { persistent, showIf } from "@/features/feature"; import { CoercableComponent, persistent, showIf } from "@/features/feature";
import { createHotkey } from "@/features/hotkey"; import { createHotkey } from "@/features/hotkey";
import { createInfobox } from "@/features/infobox"; import { createInfobox } from "@/features/infobox";
import { createMilestone } from "@/features/milestone"; import { createMilestone } from "@/features/milestone";
@ -23,38 +23,37 @@ import { createReset } from "@/features/reset";
import { addSoftcap, createResource, displayResource, trackBest } from "@/features/resource"; import { addSoftcap, createResource, displayResource, trackBest } from "@/features/resource";
import { createTab } from "@/features/tab"; import { createTab } from "@/features/tab";
import { createTabButton, createTabFamily } from "@/features/tabFamily"; import { createTabButton, createTabFamily } from "@/features/tabFamily";
import { createTree, createTreeNode } from "@/features/tree"; import { createTree, createTreeNode, GenericTreeNode, TreeBranch } from "@/features/tree";
import { createUpgrade } from "@/features/upgrade"; import { createUpgrade } from "@/features/upgrade";
import { createLayer, getLayer } from "@/game/layers"; import { createLayer, getLayer } from "@/game/layers";
import { DecimalSource } from "@/lib/break_eternity"; import { DecimalSource } from "@/lib/break_eternity";
import Decimal, { format, formatWhole } from "@/util/bignum"; import Decimal, { format, formatWhole } from "@/util/bignum";
import { render, renderCol, renderRow } from "@/util/vue"; import { render, renderCol, renderRow } from "@/util/vue";
import { computed } from "vue"; import { computed, Ref } from "vue";
import { boop, tab as fTab, treeNode as fNode } from "./f"; import f from "./f";
const c = getLayer("c"); const layer = createLayer(() => {
const id = "c";
const color = "#4BDC13";
const name = "Candies";
const points = addSoftcap(createResource<DecimalSource>(0, "lollipops"), 1e100, 0.5);
const best = trackBest(points);
const beep = persistent<boolean>(false);
const thingy = persistent<string>("pointy");
const otherThingy = persistent<number>(10);
const spentOnBuyables = persistent(new Decimal(10));
const id = "c"; const waffleBoost = computed(() => Decimal.pow(points.value, 0.2));
const color = "#4BDC13"; const icecreamCap = computed(() => Decimal.times(points.value, 10));
const name = "Candies";
const points = addSoftcap(createResource<DecimalSource>(0, "lollipops"), 1e100, 0.5);
const best = trackBest(points);
const beep = persistent<boolean>(false);
const thingy = persistent<string>("pointy");
export const otherThingy = persistent<number>(10);
const spentOnBuyables = persistent(new Decimal(10));
const waffleBoost = computed(() => Decimal.pow(points.value, 0.2)); const coolInfo = createInfobox({
const icecreamCap = computed(() => Decimal.times(points.value, 10));
const coolInfo = createInfobox({
title: "Lore", title: "Lore",
titleStyle: { color: "#FE0000" }, titleStyle: { color: "#FE0000" },
display: "DEEP LORE!", display: "DEEP LORE!",
bodyStyle: { backgroundColor: "#0000EE" } bodyStyle: { backgroundColor: "#0000EE" }
}); });
const lollipopMilestone3 = createMilestone({ const lollipopMilestone3 = createMilestone({
shouldEarn() { shouldEarn() {
return Decimal.gte(best.value, 3); return Decimal.gte(best.value, 3);
}, },
@ -62,8 +61,8 @@ const lollipopMilestone3 = createMilestone({
requirement: "3 Lollipops", requirement: "3 Lollipops",
effectDisplay: "Unlock the next milestone" effectDisplay: "Unlock the next milestone"
} }
}); });
const lollipopMilestone4 = createMilestone({ const lollipopMilestone4 = createMilestone({
visibility() { visibility() {
return showIf(lollipopMilestone3.earned.value); return showIf(lollipopMilestone3.earned.value);
}, },
@ -77,7 +76,7 @@ const lollipopMilestone4 = createMilestone({
return ( return (
<div style="display: flex; justify-content: center"> <div style="display: flex; justify-content: center">
<Toggle title="beep" v-model={beep} /> <Toggle title="beep" v-model={beep} />
<Toggle title="boop" v-model={boop} /> <Toggle title="boop" v-model={f.value.boop as Ref<boolean>} />
</div> </div>
); );
} }
@ -88,10 +87,10 @@ const lollipopMilestone4 = createMilestone({
} }
return {}; return {};
} }
}); });
const lollipopMilestones = [lollipopMilestone3, lollipopMilestone4]; const lollipopMilestones = [lollipopMilestone3, lollipopMilestone4];
const funChallenge = createChallenge({ const funChallenge = createChallenge({
title: "Fun", title: "Fun",
completionLimit: 3, completionLimit: 3,
display: { display: {
@ -108,7 +107,7 @@ const funChallenge = createChallenge({
return showIf(Decimal.gt(best.value, 0)); return showIf(Decimal.gt(best.value, 0));
}, },
goal: 20, goal: 20,
resource: () => mainPoints, resource: main.value.points,
onComplete() { onComplete() {
console.log("hiii"); console.log("hiii");
}, },
@ -121,16 +120,16 @@ const funChallenge = createChallenge({
style: { style: {
height: "200px" height: "200px"
} }
}); });
const funEffect = computed(() => Decimal.add(points.value, 1).tetrate(0.02)); const funEffect = computed(() => Decimal.add(points.value, 1).tetrate(0.02));
export const generatorUpgrade = createUpgrade({ const generatorUpgrade = createUpgrade({
title: "Generator of Genericness", title: "Generator of Genericness",
display: "Gain 1 point every second", display: "Gain 1 point every second",
cost: 1, cost: 1,
resource: points resource: points
}); });
export const lollipopMultiplierUpgrade = createUpgrade({ const lollipopMultiplierUpgrade = createUpgrade({
display: () => display: () =>
`Point generation is faster based on your unspent Lollipops<br>Currently: ${format( `Point generation is faster based on your unspent Lollipops<br>Currently: ${format(
lollipopMultiplierEffect.value lollipopMultiplierEffect.value
@ -138,23 +137,24 @@ export const lollipopMultiplierUpgrade = createUpgrade({
cost: 1, cost: 1,
resource: points, resource: points,
visibility: () => showIf(generatorUpgrade.bought.value) visibility: () => showIf(generatorUpgrade.bought.value)
}); });
export const lollipopMultiplierEffect = computed(() => { const lollipopMultiplierEffect = computed(() => {
let ret = Decimal.add(points.value, 1).pow(0.5); let ret = Decimal.add(points.value, 1).pow(0.5);
if (ret.gte("1e20000000")) ret = ret.sqrt().times("1e10000000"); if (ret.gte("1e20000000")) ret = ret.sqrt().times("1e10000000");
return ret; return ret;
}); });
export const unlockIlluminatiUpgrade = createUpgrade({ const unlockIlluminatiUpgrade = createUpgrade({
visibility() { visibility() {
return showIf(lollipopMultiplierUpgrade.bought.value); return showIf(lollipopMultiplierUpgrade.bought.value);
}, },
canPurchase() { canPurchase() {
return Decimal.lt(mainPoints.value, 7); return Decimal.lt(main.value.points.value, 7);
}, },
onPurchase() { onPurchase() {
mainPoints.value = Decimal.add(mainPoints.value, 7); main.value.points.value = Decimal.add(main.value.points.value, 7);
}, },
display: "Only buyable with less than 7 points, and gives you 7 more. Unlocks a secret subtab.", display:
"Only buyable with less than 7 points, and gives you 7 more. Unlocks a secret subtab.",
style() { style() {
if (this.bought) { if (this.bought) {
return { backgroundColor: "#1111dd" }; return { backgroundColor: "#1111dd" };
@ -164,10 +164,10 @@ export const unlockIlluminatiUpgrade = createUpgrade({
} }
return {}; return {};
} }
}); });
const upgrades = [generatorUpgrade, lollipopMultiplierUpgrade, unlockIlluminatiUpgrade]; const upgrades = [generatorUpgrade, lollipopMultiplierUpgrade, unlockIlluminatiUpgrade];
const exhancers = createBuyable({ const exhancers = createBuyable({
resource: points, resource: points,
cost() { cost() {
let x = new Decimal(this.amount.value); let x = new Decimal(this.amount.value);
@ -190,21 +190,21 @@ const exhancers = createBuyable({
}, },
style: { height: "222px" }, style: { height: "222px" },
purchaseLimit: 4 purchaseLimit: 4
}); });
const exhancersFirstEffect = computed(() => { const exhancersFirstEffect = computed(() => {
if (Decimal.gte(exhancers.amount.value, 0)) { if (Decimal.gte(exhancers.amount.value, 0)) {
return Decimal.pow(25, Decimal.pow(exhancers.amount.value, 1.1)); return Decimal.pow(25, Decimal.pow(exhancers.amount.value, 1.1));
} }
return Decimal.pow(1 / 25, Decimal.times(exhancers.amount.value, -1).pow(1.1)); return Decimal.pow(1 / 25, Decimal.times(exhancers.amount.value, -1).pow(1.1));
}); });
const exhancersSecondEffect = computed(() => { const exhancersSecondEffect = computed(() => {
if (Decimal.gte(exhancers.amount.value, 0)) { if (Decimal.gte(exhancers.amount.value, 0)) {
return Decimal.pow(25, Decimal.pow(exhancers.amount.value, 1.1)); return Decimal.pow(25, Decimal.pow(exhancers.amount.value, 1.1));
} }
return Decimal.pow(1 / 25, Decimal.times(exhancers.amount.value, -1).pow(1.1)); return Decimal.pow(1 / 25, Decimal.times(exhancers.amount.value, -1).pow(1.1));
}); });
const confirmRespec = persistent<boolean>(false); const confirmRespec = persistent<boolean>(false);
const respecBuyables = createClickable({ const respecBuyables = createClickable({
small: true, small: true,
display: "Respec Thingies", display: "Respec Thingies",
onClick() { onClick() {
@ -216,10 +216,10 @@ const respecBuyables = createClickable({
} }
points.value = Decimal.add(points.value, spentOnBuyables.value); points.value = Decimal.add(points.value, spentOnBuyables.value);
mainTree.reset(treeNode); main.value.tree.reset(treeNode);
} }
}); });
const sellExhancer = createClickable({ const sellExhancer = createClickable({
small: true, small: true,
display: "Sell One", display: "Sell One",
onClick() { onClick() {
@ -229,8 +229,8 @@ const sellExhancer = createClickable({
exhancers.amount.value = Decimal.sub(exhancers.amount.value, 1); exhancers.amount.value = Decimal.sub(exhancers.amount.value, 1);
points.value = Decimal.add(points.value, exhancers.cost.value); points.value = Decimal.add(points.value, exhancers.cost.value);
} }
}); });
const buyablesDisplay = ( const buyablesDisplay = (
<Column> <Column>
<Row> <Row>
<Toggle title="Confirm" v-model={confirmRespec} /> <Toggle title="Confirm" v-model={confirmRespec} />
@ -239,9 +239,9 @@ const buyablesDisplay = (
{render(exhancers)} {render(exhancers)}
{render(sellExhancer)} {render(sellExhancer)}
</Column> </Column>
); );
const longBoi = createBar({ const longBoi = createBar({
fillStyle: { backgroundColor: "#FFFFFF" }, fillStyle: { backgroundColor: "#FFFFFF" },
baseStyle: { backgroundColor: "#696969" }, baseStyle: { backgroundColor: "#696969" },
textStyle: { color: "#04e050" }, textStyle: { color: "#04e050" },
@ -249,13 +249,13 @@ const longBoi = createBar({
width: 300, width: 300,
height: 30, height: 30,
progress() { progress() {
return Decimal.add(mainPoints.value, 1).log(10).div(10).toNumber(); return Decimal.add(main.value.points.value, 1).log(10).div(10).toNumber();
}, },
display() { display() {
return format(mainPoints.value) + " / 1e10 points"; return format(main.value.points.value) + " / 1e10 points";
} }
}); });
const tallBoi = createBar({ const tallBoi = createBar({
fillStyle: { backgroundColor: "#4BEC13" }, fillStyle: { backgroundColor: "#4BEC13" },
baseStyle: { backgroundColor: "#000000" }, baseStyle: { backgroundColor: "#000000" },
textStyle: { textShadow: "0px 0px 2px #000000" }, textStyle: { textShadow: "0px 0px 2px #000000" },
@ -264,13 +264,13 @@ const tallBoi = createBar({
width: 50, width: 50,
height: 200, height: 200,
progress() { progress() {
return Decimal.div(mainPoints.value, 100); return Decimal.div(main.value.points.value, 100);
}, },
display() { display() {
return formatWhole(Decimal.div(mainPoints.value, 1).min(100)) + "%"; return formatWhole(Decimal.div(main.value.points.value, 1).min(100)) + "%";
} }
}); });
const flatBoi = createBar({ const flatBoi = createBar({
fillStyle: { backgroundColor: "#FE0102" }, fillStyle: { backgroundColor: "#FE0102" },
baseStyle: { backgroundColor: "#222222" }, baseStyle: { backgroundColor: "#222222" },
textStyle: { textShadow: "0px 0px 2px #000000" }, textStyle: { textShadow: "0px 0px 2px #000000" },
@ -280,20 +280,20 @@ const flatBoi = createBar({
progress() { progress() {
return Decimal.div(points.value, 50); return Decimal.div(points.value, 50);
} }
}); });
const conversion = createCumulativeConversion({ const conversion = createCumulativeConversion({
scaling: createExponentialScaling(10, 5, 0.5), scaling: createExponentialScaling(10, 5, 0.5),
baseResource: mainPoints, baseResource: main.value.points,
gainResource: points, gainResource: points,
roundUpCost: true roundUpCost: true
}); });
const reset = createReset({ const reset = createReset({
thingsToReset: () => [c()] thingsToReset: () => [getLayer("c")]
}); });
const hotkeys = [ const hotkeys = [
createHotkey({ createHotkey({
key: "c", key: "c",
description: "reset for lollipops or whatever", description: "reset for lollipops or whatever",
@ -310,9 +310,9 @@ const hotkeys = [
respecBuyables.onClick(); respecBuyables.onClick();
} }
}) })
]; ];
export const treeNode = createLayerTreeNode({ const treeNode = createLayerTreeNode({
layerID: id, layerID: id,
color, color,
reset, reset,
@ -320,7 +320,9 @@ export const treeNode = createLayerTreeNode({
tooltip() { tooltip() {
let tooltip = displayResource(points); let tooltip = displayResource(points);
if (Decimal.gt(exhancers.amount.value, 0)) { if (Decimal.gt(exhancers.amount.value, 0)) {
tooltip += `<br><i><br><br><br>${formatWhole(exhancers.amount.value)} Exhancers</i>`; tooltip += `<br><i><br><br><br>${formatWhole(
exhancers.amount.value
)} Exhancers</i>`;
} }
return tooltip; return tooltip;
}, },
@ -328,19 +330,19 @@ export const treeNode = createLayerTreeNode({
color: "#3325CC", color: "#3325CC",
textDecoration: "underline" textDecoration: "underline"
} }
}); });
const resetButton = createResetButton({ const resetButton = createResetButton({
conversion, conversion,
tree: mainTree, tree: main.value.tree,
treeNode, treeNode,
style: { style: {
color: "#AA66AA" color: "#AA66AA"
}, },
resetDescription: "Melt your points into " resetDescription: "Melt your points into "
}); });
export const g = createTreeNode({ const g = createTreeNode({
display: "TH", display: "TH",
color: "#6d3678", color: "#6d3678",
canClick() { canClick() {
@ -357,30 +359,31 @@ export const g = createTreeNode({
} }
return ""; return "";
} }
}); });
export const h = createTreeNode({ const h = createTreeNode({
id: "h", id: "h",
tooltip() { tooltip() {
return `Restore your points to ${format(otherThingy.value)}`; return `Restore your points to ${format(otherThingy.value)}`;
}, },
canClick() { canClick() {
return Decimal.lt(mainPoints.value, otherThingy.value); return Decimal.lt(main.value.points.value, otherThingy.value);
}, },
onClick() { onClick() {
mainPoints.value = otherThingy.value; main.value.points.value = otherThingy.value;
} }
}); });
export const spook = createTreeNode({}); const spook = createTreeNode({});
const tree = createTree({ const tree = createTree({
nodes() { nodes(): GenericTreeNode[][] {
return [ return [
[fNode, treeNode], [f.value.treeNode, treeNode],
[g, spook, h] [g, spook, h]
]; ];
}, },
branches: () => [ branches(): TreeBranch[] {
return [
{ {
startNode: fNode, startNode: f.value.treeNode,
endNode: treeNode, endNode: treeNode,
style: { style: {
strokeWidth: "25px", strokeWidth: "25px",
@ -390,10 +393,11 @@ const tree = createTree({
}, },
{ startNode: treeNode, endNode: g }, { startNode: treeNode, endNode: g },
{ startNode: g, endNode: h } { startNode: g, endNode: h }
] ];
}); }
});
const illuminatiTabs = createTabFamily({ const illuminatiTabs = createTabFamily({
tabs: { tabs: {
first: createTabButton({ first: createTabButton({
tab: ( tab: (
@ -405,7 +409,7 @@ const illuminatiTabs = createTabFamily({
display: "first" display: "first"
}), }),
second: createTabButton({ second: createTabButton({
tab: () => fTab, tab: f.value.display as CoercableComponent,
display: "second" display: "second"
}) })
}, },
@ -417,9 +421,9 @@ const illuminatiTabs = createTabFamily({
border: "solid white", border: "solid white",
margin: "auto" margin: "auto"
} }
}); });
const tabs = createTabFamily({ const tabs = createTabFamily({
tabs: { tabs: {
mainTab: createTabButton({ mainTab: createTabButton({
tab: createTab({ tab: createTab({
@ -442,7 +446,7 @@ const tabs = createTabFamily({
<div>Name your points!</div> <div>Name your points!</div>
<Text v-model={thingy} /> <Text v-model={thingy} />
<Sticky style="color: red; font-size: 32px; font-family: Comic Sans MS;"> <Sticky style="color: red; font-size: 32px; font-family: Comic Sans MS;">
I have {displayResource(mainPoints)}! I have {displayResource(main.value.points)}!
</Sticky> </Sticky>
<hr /> <hr />
{renderCol(lollipopMilestones)} {renderCol(lollipopMilestones)}
@ -553,9 +557,9 @@ const tabs = createTabFamily({
display: "illuminati" display: "illuminati"
}) })
} }
}); });
const layer = createLayer({ return {
id, id,
color, color,
name, name,
@ -600,6 +604,7 @@ const layer = createLayer({
resetButton, resetButton,
minWidth: 800, minWidth: 800,
display: render(tabs) display: render(tabs)
};
}); });
export default layer; export default layer;

View file

@ -1,6 +1,6 @@
import MainDisplay from "@/components/features/MainDisplay.vue"; import MainDisplay from "@/components/features/MainDisplay.vue";
import { createLayerTreeNode, createResetButton } from "@/data/common"; import { createLayerTreeNode, createResetButton } from "@/data/common";
import { points as mainPoints, tree as mainTree } from "@/data/mod"; import { main } from "@/data/mod";
import { createClickable } from "@/features/clickable"; import { createClickable } from "@/features/clickable";
import { createExponentialScaling, createIndependentConversion } from "@/features/conversion"; import { createExponentialScaling, createIndependentConversion } from "@/features/conversion";
import { persistent } from "@/features/feature"; import { persistent } from "@/features/feature";
@ -10,25 +10,24 @@ import { createResource, displayResource } from "@/features/resource";
import { createLayer, getLayer } from "@/game/layers"; import { createLayer, getLayer } from "@/game/layers";
import Decimal, { DecimalSource, formatWhole } from "@/util/bignum"; import Decimal, { DecimalSource, formatWhole } from "@/util/bignum";
import { render } from "@/util/vue"; import { render } from "@/util/vue";
import { otherThingy } from "./c"; import c from "./c";
const f = getLayer("f"); const layer = createLayer(() => {
const id = "f";
const color = "#FE0102";
const name = "Farms";
const points = createResource<DecimalSource>(0, "farm points");
const boop = persistent<boolean>(false);
const id = "f"; const coolInfo = createInfobox({
const color = "#FE0102";
const name = "Farms";
export const points = createResource<DecimalSource>(0, "farm points");
export const boop = persistent<boolean>(false);
const coolInfo = createInfobox({
title: "Lore", title: "Lore",
titleStyle: { color: "#FE0000" }, titleStyle: { color: "#FE0000" },
display: "DEEP LORE!", display: "DEEP LORE!",
bodyStyle: { backgroundColor: "#0000EE" } bodyStyle: { backgroundColor: "#0000EE" }
}); });
const clickableState = persistent<string>("Start"); const clickableState = persistent<string>("Start");
const clickable = createClickable({ const clickable = createClickable({
display: { display: {
title: "Clicky clicky!", title: "Clicky clicky!",
description() { description() {
@ -76,9 +75,9 @@ const clickable = createClickable({
return {}; return {};
} }
} }
}); });
const resetClickable = createClickable({ const resetClickable = createClickable({
onClick() { onClick() {
if (clickableState.value == "Borkened...") { if (clickableState.value == "Borkened...") {
clickableState.value = "Start"; clickableState.value = "Start";
@ -87,20 +86,20 @@ const resetClickable = createClickable({
display() { display() {
return clickableState.value == "Borkened..." ? "Fix the clickable!" : "Does nothing"; return clickableState.value == "Borkened..." ? "Fix the clickable!" : "Does nothing";
} }
}); });
const reset = createReset({ const reset = createReset({
thingsToReset: () => [f()] thingsToReset: () => [getLayer("f")]
}); });
const conversion = createIndependentConversion({ const conversion = createIndependentConversion({
scaling: createExponentialScaling(10, 3, 0.5), scaling: createExponentialScaling(10, 3, 0.5),
baseResource: mainPoints, baseResource: main.value.points,
gainResource: points, gainResource: points,
modifyGainAmount: gain => Decimal.times(gain, otherThingy.value) modifyGainAmount: gain => Decimal.times(gain, c.value.otherThingy.value)
}); });
export const treeNode = createLayerTreeNode({ const treeNode = createLayerTreeNode({
layerID: id, layerID: id,
color, color,
reset, reset,
@ -109,41 +108,41 @@ export const treeNode = createLayerTreeNode({
return `${displayResource(points)} ${points.displayName}`; return `${displayResource(points)} ${points.displayName}`;
} }
return `This weird farmer dinosaur will only see you if you have at least 10 points. You only have ${displayResource( return `This weird farmer dinosaur will only see you if you have at least 10 points. You only have ${displayResource(
mainPoints main.value.points
)}`; )}`;
}, },
canClick() { canClick() {
return Decimal.gte(mainPoints.value, 10); return Decimal.gte(main.value.points.value, 10);
} }
}); });
const resetButton = createResetButton({ const resetButton = createResetButton({
conversion, conversion,
tree: mainTree, tree: main.value.tree,
treeNode, treeNode,
display() { display() {
if (this.conversion.buyMax) { if (this.conversion.buyMax) {
return ( return (
<span> <span>
Hi! I'm a <u>weird dinosaur</u> and I'll give you{" "} Hi! I'm a <u>weird dinosaur</u> and I'll give you{" "}
<b>{formatWhole(this.conversion.currentGain.value)}</b> Farm Points in exchange <b>{formatWhole(this.conversion.currentGain.value)}</b> Farm Points in
for all of your points and lollipops! (You'll get another one at{" "} exchange for all of your points and lollipops! (You'll get another one at{" "}
{formatWhole(this.conversion.nextAt.value)} points) {formatWhole(this.conversion.nextAt.value)} points)
</span> </span>
); );
} else { } else {
return ( return (
<span> <span>
Hi! I'm a <u>weird dinosaur</u> and I'll give you a Farm Point in exchange for Hi! I'm a <u>weird dinosaur</u> and I'll give you a Farm Point in exchange
all of your points and lollipops! (At least{" "} for all of your points and lollipops! (At least{" "}
{formatWhole(this.conversion.nextAt.value)} points) {formatWhole(this.conversion.nextAt.value)} points)
</span> </span>
); );
} }
} }
}); });
export const tab = (): JSX.Element => ( const tab = (): JSX.Element => (
<template> <template>
{render(coolInfo)} {render(coolInfo)}
<MainDisplay resource={points} color={color} /> <MainDisplay resource={points} color={color} />
@ -156,9 +155,9 @@ export const tab = (): JSX.Element => (
</div> </div>
{render(clickable)} {render(clickable)}
</template> </template>
); );
const layer = createLayer({ return {
id, id,
color, color,
name, name,
@ -173,6 +172,7 @@ const layer = createLayer({
treeNode, treeNode,
resetButton, resetButton,
display: tab display: tab
};
}); });
export default layer; export default layer;

View file

@ -10,50 +10,49 @@ import Decimal, { format, formatSmall, formatTime } from "@/util/bignum";
import { render } from "@/util/vue"; import { render } from "@/util/vue";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import a from "./layers/aca/a"; import a from "./layers/aca/a";
import c, { import c from "./layers/aca/c";
generatorUpgrade,
lollipopMultiplierEffect,
lollipopMultiplierUpgrade
} from "./layers/aca/c";
import f from "./layers/aca/f"; import f from "./layers/aca/f";
export const points = createResource<DecimalSource>(0); export const main = createLayer(() => {
const best = trackBest(points); const points = createResource<DecimalSource>(0);
const total = trackTotal(points); const best = trackBest(points);
const oomps = trackOOMPS(points); const total = trackTotal(points);
const showModal = ref(false); const oomps = trackOOMPS(points);
const showModal = ref(false);
const pointGain = computed(() => { const pointGain = computed(() => {
if (!generatorUpgrade.bought) return new Decimal(0); if (!c.value.generatorUpgrade.bought) return new Decimal(0);
let gain = new Decimal(3.19); let gain = new Decimal(3.19);
if (lollipopMultiplierUpgrade.bought) gain = gain.times(lollipopMultiplierEffect.value); if (c.value.lollipopMultiplierUpgrade.bought)
gain = gain.times(c.value.lollipopMultiplierEffect.value);
return gain; return gain;
}); });
globalBus.on("update", diff => { globalBus.on("update", diff => {
points.value = Decimal.add(points.value, Decimal.times(pointGain.value, diff)); points.value = Decimal.add(points.value, Decimal.times(pointGain.value, diff));
}); });
// Note: Casting as generic tree to avoid recursive type definitions // Note: Casting as generic tree to avoid recursive type definitions
export const tree = createTree({ const tree = createTree({
nodes: () => [[c.treeNode], [f.treeNode, c.spook]], nodes: [[c.value.treeNode], [f.value.treeNode, c.value.spook]],
leftSideNodes: [a.treeNode, c.h], leftSideNodes: [a.value.treeNode, c.value.h],
branches: [ branches: [
{ {
startNode: f.treeNode, startNode: f.value.treeNode,
endNode: c.treeNode, endNode: c.value.treeNode,
stroke: "blue", stroke: "blue",
"stroke-width": "25px", "stroke-width": "25px",
style: { style: {
filter: "blur(5px)" filter: "blur(5px)"
} }
}, },
{ startNode: c.treeNode, endNode: c.g } { startNode: c.value.treeNode, endNode: c.value.g }
] ]
}) as GenericTree; }) as GenericTree;
// Note: layers don't _need_ a reference to everything, but I'd recommend it over trying to remember // Note: layers don't _need_ a reference to everything,
// what does and doesn't need to be included. Officially all you need are anything with persistency // but I'd recommend it over trying to remember what does and doesn't need to be included.
export const main = createLayer({ // Officially all you need are anything with persistency or that you want to access elsewhere
return {
id: "main", id: "main",
name: "Tree", name: "Tree",
links: tree.links, links: tree.links,
@ -95,12 +94,13 @@ export const main = createLayer({
total, total,
oomps, oomps,
tree tree
};
}); });
export const getInitialLayers = ( export const getInitialLayers = (
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
player: Partial<PlayerData> player: Partial<PlayerData>
): Array<GenericLayer> => [main, f, c, a]; ): Array<GenericLayer> => [main.value, f.value, c.value, a.value];
export const hasWon = computed(() => { export const hasWon = computed(() => {
return false; return false;

View file

@ -37,7 +37,7 @@ type BuyableDisplay =
export interface BuyableOptions { export interface BuyableOptions {
visibility?: Computable<Visibility>; visibility?: Computable<Visibility>;
cost?: Computable<DecimalSource>; cost?: Computable<DecimalSource>;
resource?: Computable<Resource>; resource?: Resource;
canPurchase?: Computable<boolean>; canPurchase?: Computable<boolean>;
purchaseLimit?: Computable<DecimalSource>; purchaseLimit?: Computable<DecimalSource>;
classes?: Computable<Record<string, boolean>>; classes?: Computable<Record<string, boolean>>;

View file

@ -34,7 +34,7 @@ export interface ChallengeOptions {
canComplete?: Computable<boolean | DecimalSource>; canComplete?: Computable<boolean | DecimalSource>;
completionLimit?: Computable<DecimalSource>; completionLimit?: Computable<DecimalSource>;
mark?: Computable<boolean | string>; mark?: Computable<boolean | string>;
resource?: Computable<Resource>; resource?: Resource;
goal?: Computable<DecimalSource>; goal?: Computable<DecimalSource>;
classes?: Computable<Record<string, boolean>>; classes?: Computable<Record<string, boolean>>;
style?: Computable<StyleValue>; style?: Computable<StyleValue>;
@ -72,7 +72,6 @@ export type Challenge<T extends ChallengeOptions> = Replace<
canComplete: GetComputableTypeWithDefault<T["canComplete"], Ref<boolean>>; canComplete: GetComputableTypeWithDefault<T["canComplete"], Ref<boolean>>;
completionLimit: GetComputableTypeWithDefault<T["completionLimit"], 1>; completionLimit: GetComputableTypeWithDefault<T["completionLimit"], 1>;
mark: GetComputableTypeWithDefault<T["mark"], Ref<boolean>>; mark: GetComputableTypeWithDefault<T["mark"], Ref<boolean>>;
resource: GetComputableType<T["resource"]>;
goal: GetComputableType<T["goal"]>; goal: GetComputableType<T["goal"]>;
classes: GetComputableType<T["classes"]>; classes: GetComputableType<T["classes"]>;
style: GetComputableType<T["style"]>; style: GetComputableType<T["style"]>;
@ -160,7 +159,7 @@ export function createChallenge<T extends ChallengeOptions>(
if (!proxy.active.value || proxy.resource == null || proxy.goal == null) { if (!proxy.active.value || proxy.resource == null || proxy.goal == null) {
return false; return false;
} }
return Decimal.gte(unref<Resource>(proxy.resource).value, unref(proxy.goal)); return Decimal.gte(proxy.resource.value, unref(proxy.goal));
}); });
} }
if (challenge.mark == null) { if (challenge.mark == null) {
@ -174,7 +173,6 @@ export function createChallenge<T extends ChallengeOptions>(
processComputable(challenge as T, "completionLimit"); processComputable(challenge as T, "completionLimit");
setDefault(challenge, "completionLimit", 1); setDefault(challenge, "completionLimit", 1);
processComputable(challenge as T, "mark"); processComputable(challenge as T, "mark");
processComputable(challenge as T, "resource");
processComputable(challenge as T, "goal"); processComputable(challenge as T, "goal");
processComputable(challenge as T, "classes"); processComputable(challenge as T, "classes");
processComputable(challenge as T, "style"); processComputable(challenge as T, "style");

View file

@ -17,6 +17,7 @@ import {
} from "@/util/computed"; } from "@/util/computed";
import { createProxy } from "@/util/proxies"; import { createProxy } from "@/util/proxies";
import { createNanoEvents, Emitter } from "nanoevents"; import { createNanoEvents, Emitter } from "nanoevents";
import { customRef, Ref } from "vue";
import { globalBus } from "./events"; import { globalBus } from "./events";
import player from "./player"; import player from "./player";
@ -81,27 +82,40 @@ export type GenericLayer = Replace<
} }
>; >;
export function createLayer<T extends LayerOptions>(options: T): Layer<T> { export function createLayer<T extends LayerOptions>(optionsFunc: () => T): Ref<Layer<T>> {
const layer: T & Partial<BaseLayer> = options; let layer: Layer<T> | null = null;
const emitter = (layer.emitter = createNanoEvents<LayerEvents>()); return customRef(track => {
layer.on = emitter.on.bind(emitter); return {
layer.emit = emitter.emit.bind(emitter); get() {
if (layer == undefined) {
const partialLayer = optionsFunc() as T & Partial<BaseLayer>;
const emitter = (partialLayer.emitter = createNanoEvents<LayerEvents>());
partialLayer.on = emitter.on.bind(emitter);
partialLayer.emit = emitter.emit.bind(emitter);
layer.minimized = persistent(false); partialLayer.minimized = persistent(false);
processComputable(layer as T, "color"); processComputable(partialLayer as T, "color");
processComputable(layer as T, "display"); processComputable(partialLayer as T, "display");
processComputable(layer as T, "name"); processComputable(partialLayer as T, "name");
setDefault(layer, "name", options.id); setDefault(partialLayer, "name", partialLayer.id);
processComputable(layer as T, "minWidth"); processComputable(partialLayer as T, "minWidth");
setDefault(layer, "minWidth", 600); setDefault(partialLayer, "minWidth", 600);
processComputable(layer as T, "minimizable"); processComputable(partialLayer as T, "minimizable");
setDefault(layer, "minimizable", true); setDefault(partialLayer, "minimizable", true);
processComputable(layer as T, "links"); processComputable(partialLayer as T, "links");
const proxy = createProxy(layer as unknown as Layer<T>); layer = createProxy(partialLayer as unknown as Layer<T>);
return proxy; }
track();
return layer;
},
set() {
console.error("Layers are read-only!");
}
};
});
} }
export function addLayer( export function addLayer(
@ -127,8 +141,8 @@ export function addLayer(
globalBus.emit("addLayer", layer, player.layers[layer.id]); globalBus.emit("addLayer", layer, player.layers[layer.id]);
} }
export function getLayer<T extends GenericLayer>(layerID: string): () => T { export function getLayer<T extends GenericLayer>(layerID: string): T {
return () => layers[layerID] as T; return layers[layerID] as T;
} }
export function removeLayer(layer: GenericLayer): void { export function removeLayer(layer: GenericLayer): void {