1
0
Fork 0
mirror of https://github.com/Acamaeda/The-Modding-Tree.git synced 2024-11-25 01:41:45 +00:00

1.2: This changes everything!

This commit is contained in:
Acamaeda 2020-10-03 15:45:47 -04:00
parent 7929873a11
commit eca8970c38
15 changed files with 389 additions and 401 deletions

View file

@ -1,8 +1,11 @@
# The-Modding-Tree # The-Modding-Tree
The main way to add content is through creating layers. You can either add a layer directly in the layers object in layers.js, or declare it separately and then do "`addLayer(layername, layerdata)`" (good for breaking things up into smaller files). The existing layers are just examples and can be freely deleted. sampleLayers.js has even more features and comments in it. You can use those as references and a base for your own layers. The main way to add content is through creating layers. You can either add a layer directly in the layers object in layersSupportjs,
or declare it in another file and then do "`addLayer(layername, layerdata)`"
(good for breaking things up into smaller files). The existing layers are just examples and can be freely deleted.
You can use those as references and a base for your own layers.
**You will also need to add layer nodes to the tree in the HTML, look for where it says "Modify the tree in the table below!"** While you're there, you can also edit the modInfo at the top to change the name for your mod. **You will also need to add layer nodes to the tree in the HTML, look for where it says "Modify the tree in the table below!"** While you're there, you can also edit the modInfo at the top to change the name for your mod and some other settings. A unique modId will prevent your mod's saves from conflicting with other mods.
Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to. Most of the time, you won't need to dive deep into the code to create things, but you still can if you really want to.

View file

@ -1,6 +1,8 @@
# Basic layer breakdown # Basic layer breakdown
This is a very minimal layer with minimal features. Most things will require additional features: This is a very minimal layer with minimal features. Most things will require additional features.
If you're curious about "() =>", it's a weird notation that lets you use either a value or function in the same slot,
and treats it like a function. If you're using an actual function there, you can replace it with the normal notation.
```js ```js
p: { p: {
@ -10,16 +12,15 @@ This is a very minimal layer with minimal features. Most things will require add
// If you add non-standard Decimal variables, look at convertToDecimal // If you add non-standard Decimal variables, look at convertToDecimal
}}, }},
color: "#FE0102", // The color for this layer, which affects many elements color:() => "#FE0102", // The color for this layer, which affects many elements
resource: "prestige points", // The name of this layer's main prestige resource resource: "prestige points", // The name of this layer's main prestige resource
row: 0, // The row this layer is on (0 is the first row) row: 0, // The row this layer is on (0 is the first row)
baseResource: "points", // The name of the resource your prestige gain is based on baseResource: "points", // The name of the resource your prestige gain is based on
baseAmount() {return player.points}, // A function to return the current value of that resource baseAmount() {return player.points}, // A function to return the current value of that resource
requires() {return new Decimal(200)}, // A function returning the amount of the base needed to requires:() => new Decimal(200)}, // The amount of the base needed to gain 1 of the prestige currency.
// gain 1 of the prestige currency. Also the amount required // Also the amount required to unlock the layer.
// to unlock the layer.
type: "normal", // Determines the formula used for calculating prestige currency. type: "normal", // Determines the formula used for calculating prestige currency.
exponent: 0.5, // "normal" prestige gain is (currency^exponent) exponent: 0.5, // "normal" prestige gain is (currency^exponent)

View file

@ -13,7 +13,7 @@ Buyables should be formatted like this:
Having this function makes a respec button appear Having this function makes a respec button appear
respecText: **optional**, text that appears on the respec button respecText: **optional**, text that appears on the respec button
11: { 11: {
desc: "Blah", desc:() => "Blah",
etc etc
} }
etc etc
@ -23,6 +23,7 @@ Buyables should be formatted like this:
Features: Features:
- title: **optional**, displayed at the top in a larger font - title: **optional**, displayed at the top in a larger font
It can also be a function that returns updating text.
- cost(x): cost for buying xth buyable, can be an object if there are multiple currencies - cost(x): cost for buying xth buyable, can be an object if there are multiple currencies
@ -30,7 +31,7 @@ Features:
for having x of this buyable. Can return a value or an object containing multiple values. for having x of this buyable. Can return a value or an object containing multiple values.
- display(): A function returning everything that should be displayed on the rebuyable after the title, likely - display(): A function returning everything that should be displayed on the rebuyable after the title, likely
including the description, amount bought, cost, and current effect including the description, amount bought, cost, and current effect.
- unl(): A function returning a bool to determine if the buyable is visible or not. - unl(): A function returning a bool to determine if the buyable is visible or not.
@ -39,3 +40,7 @@ Features:
- buy(): A function that implements buying one of the buyable. - buy(): A function that implements buying one of the buyable.
- buyMax(): **optional**, A function that implements buying as many of the buyable as possible. - buyMax(): **optional**, A function that implements buying as many of the buyable as possible.
- layer: **Assigned automagically**. It's the same value as the name of this layer, so you can do player[this.layer].points or similar
- id: **Assigned automagically**. It's the id for this buyable.

View file

@ -7,7 +7,7 @@ Challenges are stored in the following format:
rows: # of rows rows: # of rows
cols: # of columns cols: # of columns
11: { 11: {
name: "Ouch", name:() => "Ouch",
etc etc
} }
etc etc
@ -20,19 +20,22 @@ or has completed the challenge, respectively. These are useful for implementing
Each challenge should have an id where the first digit is the row and the second digit is the column. Each challenge should have an id where the first digit is the row and the second digit is the column.
Individual upgrades can have these features: Individual upgrades can have these features:
- name: Name of the challenge - name: Name of the challenge, can be a string or a function
- desc: A description of what makes the challenge a challenge. *You will need to implement these elsewhere* - desc: A description of what makes the challenge a challenge. *You will need to implement these elsewhere*
It can also be a function that returns updating text.
- reward: A description of the reward's effect. *You will also have to implement the effect where it is applied.* - reward: A description of the reward's effect. *You will also have to implement the effect where it is applied.*
It can also be a function that returns updating text.
- effect(): **optional**, A function that calculates and returns the current values of any bonuses from the reward. - effect(): **optional**, A function that calculates and returns the current values of any bonuses from the reward.
Can return a value or an object containing multiple values. Can return a value or an object containing multiple values.
- effectDisp(effects): **optional**, A function that returns a display of the current effects of the reward with - effectDisplay(effects): **optional**, A function that returns a display of the current effects of the reward with
formatting. Default behavior is to just display the a number appropriately formatted. formatting. Default behavior is to just display the a number appropriately formatted.
- goal: A Decimal for the cost of the upgrade. By default, the goal is in basic Points. - goal: A Decimal for the cost of the upgrade. By default, the goal is in basic Points.
The goal can also be a function if its value changes.
- unl(): A function returning a bool to determine if the challenge is visible or not. - unl(): A function returning a bool to determine if the challenge is visible or not.
@ -48,3 +51,6 @@ By default, challenges use basic Points for the goal. You can change that using
If it's part of a layer, omit. If it's part of a layer, omit.
- layer: **Assigned automagically**. It's the same value as the name of this layer, so you can do player[this.layer].points or similar
- id: **Assigned automagically**. It's the id for this challenge.

View file

@ -19,16 +19,17 @@ which applies its style to the component.
These are the existing components, but you can create more in v.js: These are the existing components, but you can create more in v.js:
- display-text: Displays some text. The argument is a function which returns the text to display. - display-text: Displays some text. The argument is the text to display. It can also be a function that returns updating text.
- raw-html: Displays some HTML. The argument is a function which returns the HTML. It doesn't work with many vue things. - raw-html: Displays some HTML. The argument is the HTML as a string, or a function that returns updating HTML.
It doesn't work with many vue things.
- blank: An empty newline - blank: An empty newline
- main-display: The text that displays the main currency for the layer and its effects. - main-display: The text that displays the main currency for the layer and its effects.
- prestige-button: The argument is a function that returns what the prestige button should say before the amount of - prestige-button: The argument is a string that the prestige button should say before the amount of
currency you will gain. currency you will gain. It can also be a function that returns updating text.
- upgrades, milestones, challs: Display the upgrades, milestones, and challenges for a layer, as appropriate. - upgrades, milestones, challs: Display the upgrades, milestones, and challenges for a layer, as appropriate.
@ -36,3 +37,7 @@ These are the existing components, but you can create more in v.js:
boxes in pixels. boxes in pixels.
- toggle: A toggle button that toggles a bool value. The data is a pair that identifies what bool to toggle, [layer, id] - toggle: A toggle button that toggles a bool value. The data is a pair that identifies what bool to toggle, [layer, id]
Tip: use readData on things you're displaying! If the data is a function, it will return the result of calling it.
Otherwise, it will return the data itself. This lets you use dynamic values, while keeping constant values convenient.

View file

@ -10,6 +10,9 @@ Key:
# Layer Definition features # Layer Definition features
- layer: **Assigned automagically**. It's the same value as the name of this layer, so you can do player[this.layer].points or similar
to access the save value. It makes copying code to new layers easier. It is also assigned to all upgrades and buyables and such.
- startData(): A function to return the default save data for this layer. Add any variables you have to it. - startData(): A function to return the default save data for this layer. Add any variables you have to it.
Any nonstandard Decimal variables need to be added to convertToDecimal as well. Any nonstandard Decimal variables need to be added to convertToDecimal as well.
Standard values: Standard values:
@ -32,7 +35,8 @@ Key:
Can return a value or an object containing multiple values. Can return a value or an object containing multiple values.
*You will also have to implement the effect where it is applied.* *You will also have to implement the effect where it is applied.*
- effectDescription(): **optional**, A function that returns a description of this effect - effectDescription: **optional**, A function that returns a description of this effect.
If the text stays constant, it can just be a string.
- layerShown(): A function returning a bool which determines if this layer's node should be visible on the tree. - layerShown(): A function returning a bool which determines if this layer's node should be visible on the tree.
@ -46,6 +50,7 @@ Key:
``` ```
- style: A CSS object containing any CSS that should affect this layer's whole tab. - style: A CSS object containing any CSS that should affect this layer's whole tab.
Can also be a function returning a dynamic CSS object.
- tabFormat: Use this if you want to add extra things to your tab or change the layout. - tabFormat: Use this if you want to add extra things to your tab or change the layout.
@ -72,9 +77,9 @@ Key:
- baseAmount(): A function that gets the current value of the base resource. - baseAmount(): A function that gets the current value of the base resource.
- requires(): A function returning the amount of the base needed to gain 1 of the prestige currency. - requires: A Decimal, the amount of the base needed to gain 1 of the prestige currency.
Also the amount required to unlock the layer. Also the amount required to unlock the layer.
You might make the value increase if another layer was unlocked first (based on "order"). You can instead make this a function, to make it harder if another layer was unlocked first (based on "order").
- type: Determines which prestige formula you use. - type: Determines which prestige formula you use.
"normal": The amount of currency you gain is independent of its current amount (like Prestige). "normal": The amount of currency you gain is independent of its current amount (like Prestige).

View file

@ -5,7 +5,7 @@ Milestones should be formatted like this:
```js ```js
milestones: { milestones: {
0: { 0: {
requirementDesc: "123 waffles", requirementDesc:() => "123 waffles",
} }
etc etc
} }
@ -16,8 +16,10 @@ You can use inChall(layer, id) and hasChall(layer, id) to determine if the playe
Milestone features: Milestone features:
- requirementDesc: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total". - requirementDesc: A string describing the requirement for unlocking this milestone. Suggestion: Use a "total".
It can also be a function that returns updating text.
- effectDesc: A string describing the reward for having the milestone. *You will have to implement the reward elsewhere.* - effectDesc: A string describing the reward for having the milestone. *You will have to implement the reward elsewhere.*
It can also be a function that returns updating text.
- done(): A function returning a boolean to determine if the milestone has been fulfilled. - done(): A function returning a boolean to determine if the milestone has been fulfilled.
@ -26,3 +28,7 @@ Milestone features:
It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer It is defined as an array of paired items, one pair per toggle. The first is the internal name of the layer
the value being toggled is stored in, and the second is the internal name of the variable to toggle. the value being toggled is stored in, and the second is the internal name of the variable to toggle.
(e.g. [["b", "auto"], ["g", "auto"]) (e.g. [["b", "auto"], ["g", "auto"])
- layer: **Assigned automagically**. It's the same value as the name of this layer, so you can do player[this.layer].points or similar
- id: **Assigned automagically**. It's the id for this milestone.

View file

@ -7,7 +7,7 @@ Upgrades are stored in the following format:
rows: # of rows rows: # of rows
cols: # of columns cols: # of columns
11: { 11: {
desc: "Blah", desc:() => "Blah",
etc etc
} }
etc etc
@ -20,12 +20,16 @@ Hint: Basic point gain is calculated in game.js's "getPointGain".
Each upgrade should have an id where the first digit is the row and the second digit is the column. Each upgrade should have an id where the first digit is the row and the second digit is the column.
Individual upgrades can have these features: Individual upgrades can have these features:
- title: **optional**, displayed at the top in a larger font
It can also be a function that returns updating text.
- desc: A description of the upgrade's effect. *You will also have to implement the effect where it is applied.* - desc: A description of the upgrade's effect. *You will also have to implement the effect where it is applied.*
It can also be a function that returns updating text.
- effect(): **optional**, A function that calculates and returns the current values of any bonuses from the upgrade. - effect(): **optional**, A function that calculates and returns the current values of any bonuses from the upgrade.
Can return a value or an object containing multiple values. Can return a value or an object containing multiple values.
- effectDisp(effects): **optional**, A function that returns a display of the current effects of the upgrade with - effectDisplay(effects): **optional**, A function that returns a display of the current effects of the upgrade with
formatting. Default behavior is to just display the a number appropriately formatted. formatting. Default behavior is to just display the a number appropriately formatted.
- cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer. - cost: A Decimal for the cost of the upgrade. By default, upgrades cost the main prestige currency for the layer.
@ -41,4 +45,6 @@ By default, upgrades use the main prestige currency for the layer. You can inclu
- currencyLayer: **optional**, the internal name of the layer that currency is stored in. - currencyLayer: **optional**, the internal name of the layer that currency is stored in.
If it's not in a layer (like Points), omit. If it's not in a layer (like Points), omit.
- layer: **Assigned automagically**. It's the same value as the name of this layer, so you can do player[this.layer].points or similar
- id: **Assigned automagically**. It's the id for this upgrade.

View file

@ -13,6 +13,7 @@
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script type="text/javascript" src="js/break_eternity.js"></script> <script type="text/javascript" src="js/break_eternity.js"></script>
<script type="text/javascript" src="js/layerSupport.js"></script>
<script type="text/javascript" src="js/layers.js"></script> <script type="text/javascript" src="js/layers.js"></script>
<script type="text/javascript" src="js/temp.js"></script> <script type="text/javascript" src="js/temp.js"></script>
<script type="text/javascript" src="js/saves.js"></script> <script type="text/javascript" src="js/saves.js"></script>
@ -44,7 +45,14 @@
<div v-if="player.tab=='changelog'" class="col right"> <div v-if="player.tab=='changelog'" class="col right">
<button class="back" onclick="showTab('tree')"></button><br> <button class="back" onclick="showTab('tree')"></button><br>
<h3>v1.2: This Changes Everything!</h3>
<ul>
<li>Many layer features can now be static values or functions. (This made some notations change, which will break things)</li>
<li>You can now use the "this" keyword, to make code easier to transfer when making new layers. Also added "this.layer", which is the current layer's name, and works on existing subfeatures (e.g. individual upgrades) as well! Subfeatures also have "this.id".</li>
<li>Fixed a big save issue. If you use a unique mod id, your save will never conflict with other mods.</li>
<li>Added a configurable offline time limit in modinfo at the top of index.html. (default 1 hour)</li>
<li>Added a few minor features, and updated the docs with new information.</li>
</ul><br>
<h3>v1.1.1</h3> <h3>v1.1.1</h3>
<ul> <ul>
<li>You can define hotkeys in layer config.</li> <li>You can define hotkeys in layer config.</li>
@ -140,7 +148,7 @@
<canvas id="treeCanvas" class="canvas"></canvas> <canvas id="treeCanvas" class="canvas"></canvas>
</div> </div>
<div v-for="layer in LAYERS"> <div v-for="layer in LAYERS">
<div v-if="player.tab==layer" v-bind:class="'col right'" v-bind:style="layers[layer].style ? layers[layer].style : {}"> <div v-if="player.tab==layer" v-bind:class="'col right'" v-bind:style="tmp.style[layer] ? tmp.style[layer] : {}">
<button class="back" onclick="showTab('tree')"></button><br><br><br> <button class="back" onclick="showTab('tree')"></button><br><br><br>
<div v-if="!layers[layer].tabFormat"> <div v-if="!layers[layer].tabFormat">
<main-display :layer="layer"></main-display> <main-display :layer="layer"></main-display>

View file

@ -5,8 +5,8 @@ var NaNalert = false;
var gameEnded = false; var gameEnded = false;
let VERSION = { let VERSION = {
num: "1.1.1", num: "1.2",
name: "Enhanced Edition" name: "This changes everything!"
} }
function startPlayerBase() { function startPlayerBase() {
@ -293,7 +293,7 @@ function getNextAt(layer) {
} }
function nodeShown(layer) { function nodeShown(layer) {
if (layers[layer].layerShown()) return true if (tmp.layerShown[layer]) return true
switch(layer) { switch(layer) {
case "idk": case "idk":
return player.l.unl return player.l.unl
@ -405,7 +405,7 @@ function respecBuyables(layer) {
function canAffordUpg(layer, id) { function canAffordUpg(layer, id) {
upg = layers[layer].upgrades[id] upg = layers[layer].upgrades[id]
cost = upg.cost cost = tmp.upgrades[layer][id].cost
return canAffordPurchase(layer, upg, cost) return canAffordPurchase(layer, upg, cost)
} }
@ -421,7 +421,6 @@ function hasChall(layer, id){
return (player[layer].challs.includes(id)) return (player[layer].challs.includes(id))
} }
function canAffordPurchase(layer, thing, cost) { function canAffordPurchase(layer, thing, cost) {
if (thing.currencyInternalName){ if (thing.currencyInternalName){
let name = thing.currencyInternalName let name = thing.currencyInternalName
@ -443,22 +442,23 @@ function buyUpg(layer, id) {
if (!layers[layer].upgrades[id].unl()) return if (!layers[layer].upgrades[id].unl()) return
if (player[layer].upgrades.includes(id)) return if (player[layer].upgrades.includes(id)) return
upg = layers[layer].upgrades[id] upg = layers[layer].upgrades[id]
cost = tmp.upgrades[layer][id].cost
if (upg.currencyInternalName){ if (upg.currencyInternalName){
let name = upg.currencyInternalName let name = upg.currencyInternalName
if (upg.currencyLayer){ if (upg.currencyLayer){
let lr = upg.currencyLayer let lr = upg.currencyLayer
if (player[lr][name].lt(upg.cost)) return if (player[lr][name].lt(cost)) return
player[lr][name] = player[lr][name].sub(upg.cost) player[lr][name] = player[lr][name].sub(cost)
} }
else { else {
if (player[name].lt(upg.cost)) return if (player[name].lt(cost)) return
player[name] = player[name].sub(upg.cost) player[name] = player[name].sub(cost)
} }
} }
else { else {
if (player[layer].points.lt(upg.cost)) return if (player[layer].points.lt(cost)) return
player[layer].points = player[layer].points.sub(upg.cost) player[layer].points = player[layer].points.sub(cost)
} }
player[layer].upgrades.push(id); player[layer].upgrades.push(id);
if (upg.onPurchase != undefined) if (upg.onPurchase != undefined)
@ -467,8 +467,8 @@ function buyUpg(layer, id) {
function buyBuyable(layer, id) { function buyBuyable(layer, id) {
if (!player[layer].unl) return if (!player[layer].unl) return
if (!layers[layer].buyables[id].unl()) return if (!tmp.buyables[layer][id].unl) return
if (!layers[layer].buyables[id].canAfford()) return if (!tmp.buyables[layer][id].canAfford) return
layers[layer].buyables[id].buy() layers[layer].buyables[id].buy()
} }
@ -517,7 +517,7 @@ function canCompleteChall(layer, x)
let name = chall.currencyInternalName let name = chall.currencyInternalName
if (chall.currencyLayer){ if (chall.currencyLayer){
let lr = chall.currencyLayer let lr = chall.currencyLayer
return !(player[lr][name].lt(chall.goal)) return !(player[lr][name].lt(readData(chall.goal)))
} }
else { else {
return !(player[name].lt(chall.cost)) return !(player[name].lt(chall.cost))
@ -719,21 +719,6 @@ function switchTheme() {
resizeCanvas() resizeCanvas()
} }
function updateHotkeys()
{
hotkeys = {};
for (layer in layers){
hk = layers[layer].hotkeys
if (hk){
for (id in hk){
hotkeys[hk[id].key] = hk[id]
hotkeys[hk[id].key].layer = layer
}
}
}
}
updateHotkeys()
document.onkeydown = function(e) { document.onkeydown = function(e) {
if (player===undefined) return; if (player===undefined) return;
if (gameEnded&&!player.keepGoing) return; if (gameEnded&&!player.keepGoing) return;

85
js/layerSupport.js Normal file
View file

@ -0,0 +1,85 @@
var layers = {}
function layerShown(layer){
return layers[layer].layerShown();
}
var LAYERS = Object.keys(layers);
var hotkeys = {};
function updateHotkeys()
{
hotkeys = {};
for (layer in layers){
hk = layers[layer].hotkeys
if (hk){
for (id in hk){
hotkeys[hk[id].key] = hk[id]
hotkeys[hk[id].key].layer = layer
}
}
}
}
var ROW_LAYERS = {}
function updateLayers(){
LAYERS = Object.keys(layers);
ROW_LAYERS = {}
for (layer in layers){
layers[layer].layer = layer
if (layers[layer].upgrades){
for (thing in layers[layer].upgrades){
if (!isNaN(thing)){
layers[layer].upgrades[thing].id = thing
layers[layer].upgrades[thing].layer = layer
}
}
}
if (layers[layer].milestones){
for (thing in layers[layer].milestones){
if (!isNaN(thing)){
layers[layer].milestones[thing].id = thing
layers[layer].milestones[thing].layer = layer
}
}
}
if (layers[layer].challs){
for (thing in layers[layer].challs){
if (!isNaN(thing)){
layers[layer].challs[thing].id = thing
layers[layer].challs[thing].layer = layer
}
}
}
if (layers[layer].buyables){
layers[layer].buyables.layer = layer
for (thing in layers[layer].buyables){
if (!isNaN(thing)){
layers[layer].buyables[thing].id = thing
layers[layer].buyables[thing].layer = layer
}
}
}
row = layers[layer].row
if(!ROW_LAYERS[row]) ROW_LAYERS[row] = {}
ROW_LAYERS[row][layer]=layer;
}
updateHotkeys()
}
function addLayer(layerName, layerData){ // Call this to add layers from a different file!
layers[layerName] = layerData
updateLayers()
}
// If data is a function, return the result of calling it. Otherwise, return the data.
function readData(data, args=null){
if (!!(data && data.constructor && data.call && data.apply))
return data(args);
else
return data;
}

View file

@ -1,5 +1,5 @@
var layers = { addLayer("c", {
c: { layer: "c", // This is assigned automatically, both to the layer and all upgrades, etc. Shown here so you know about it
startData() { return { startData() { return {
unl: true, unl: true,
points: new Decimal(0), points: new Decimal(0),
@ -8,75 +8,98 @@ var layers = {
buyables: {}, // You don't actually have to initialize this one buyables: {}, // You don't actually have to initialize this one
beep: false, beep: false,
}}, }},
color: "#4BEC13", color:() => "#4BEC13",
requires() {return new Decimal(10)}, // Can be a function that takes requirement increases into account requires:() => new Decimal(10), // Can be a function that takes requirement increases into account
resource: "lollipops", // Name of prestige currency resource: "lollipops", // Name of prestige currency
baseResource: "candies", // Name of resource prestige is based on baseResource: "candies", // Name of resource prestige is based on
baseAmount() {return player.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 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 exponent: 0.5, // Prestige currency exponent
base: 5, // Only needed for static layers, base of the formula (b^(x^exp)) base: 5, // Only needed for static layers, base of the formula (b^(x^exp))
resCeil: false, // True if the resource needs to be rounded up resCeil: false, // True if the cost needs to be rounded up (use when baseResource is static?)
canBuyMax() {}, // Only needed for static layers canBuyMax() {}, // Only needed for static layers with buy max
gainMult() { gainMult() { // Calculate the multiplier for main currency from bonuses
mult = new Decimal(1) mult = new Decimal(1)
if (player.c.upgrades.includes(21)) mult = mult.times(2) if (player[this.layer].upgrades.includes(21)) mult = mult.times(2)
if (player.c.upgrades.includes(23)) mult = mult.times(LAYER_UPGS.c[23].currently()) if (player[this.layer].upgrades.includes(23)) mult = mult.times(this.upgrades[23].currently())
return mult return mult
}, },
gainExp() { gainExp() { // Calculate the exponent on main currency from bonuses
return new Decimal(1) return new Decimal(1)
}, },
row: 0, 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 effect() {
waffleBoost: (true == false ? 0 : Decimal.pow(player.c.points, 0.2)), 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
icecreamCap: (player.c.points * 10) waffleBoost: (true == false ? 0 : Decimal.pow(player[this.layer].points, 0.2)),
icecreamCap: (player[this.layer].points * 10)
}}, }},
effectDescription() { effectDescription() { // Optional text to describe the effects
eff = layers.c.effect(); eff = this.effect;
return "which are boosting waffles by "+format(eff.waffleBoost)+" and increasing the Ice Cream cap by "+format(eff.icecreamCap) return "which are boosting waffles by "+format(eff.waffleBoost)+" and increasing the Ice Cream cap by "+format(eff.icecreamCap)
}, },
milestones: { milestones: {
0: {requirementDesc: "3 Lollipops", 0: {requirementDesc:() => "3 Lollipops",
done() {return player.c.best.gte(3)}, done() {return player[this.layer].best.gte(3)}, // Used to determine when to give the milestone
effectDesc: "Makes this green", effectDesc:() => "Makes this green",
}, },
1: {requirementDesc: "4 Lollipops", 1: {requirementDesc:() => "4 Lollipops",
done() {return player.c.best.gte(4)}, done() {return player[this.layer].best.gte(4)},
effectDesc: "You can toggle beep and boop (which do nothing)", effectDesc:() => "You can toggle beep and boop (which do nothing)",
toggles: [ toggles: [
["c", "beep"], // Each toggle is defined by a layer and the data toggled for that layer [this.layer, "beep"], // Each toggle is defined by a layer and the data toggled for that layer
["f", "boop"]], ["f", "boop"]],
} }
}, },
challs: {
rows: 1,
cols: 1,
11: {
name:() => "Fun",
desc:() => "Makes the game 0% harder",
unl() { return player[this.layer].best.gt(0) },
goal:() => new Decimal("20"),
currencyDisplayName: "lollipops", // Use if using a nonstandard currency
currencyInternalName: "points", // Use if using a nonstandard currency
currencyLayer: this.layer, // Leave empty if not in a layer
effect() {
let ret = player[this.layer].points.add(1).tetrate(0.02)
return ret;
},
effectDisplay(x) { return format(x)+"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.
reward:() => "Says hi",
onComplete() {console.log("hiii")} // Called when you complete the challenge
},
},
upgrades: { upgrades: {
rows: 1, rows: 1,
cols: 3, cols: 3,
11: { 11: {
desc: "Gain 1 Candy every second.", title:() => "Generator of Genericness",
cost: new Decimal(1), desc:() => "Gain 1 Point every second.",
unl() { return player.c.unl }, cost:() => new Decimal(1),
unl() { return player[this.layer].unl }, // The upgrade is only visible when this is true
}, },
12: { 12: {
desc: "Candy generation is faster based on your unspent Lollipops.", desc:() => "Candy generation is faster based on your unspent Lollipops.",
cost: new Decimal(1), cost:() => new Decimal(1),
unl() { return player.c.upgrades.includes(11) }, unl() { return player[this.layer].upgrades.includes(11) },
effect() { effect() { // Calculate bonuses from the upgrade. Can return a single value or an object with multiple values
let ret = player.c.points.add(1).pow(player.c.upgrades.includes(24)?1.1:(player.c.upgrades.includes(14)?0.75:0.5)) let ret = player[this.layer].points.add(1).pow(player[this.layer].upgrades.includes(24)?1.1:(player[this.layer].upgrades.includes(14)?0.75:0.5))
if (ret.gte("1e20000000")) ret = ret.sqrt().times("1e10000000") if (ret.gte("1e20000000")) ret = ret.sqrt().times("1e10000000")
return ret; return ret;
}, },
effDisp(fx) { return format(fx)+"x" }, effectDisplay(fx) { return format(fx)+"x" }, // Add formatting to the effect
}, },
13: { 13: {
desc: "Make this layer act like you bought it first.", desc:() => "Make this layer act like you bought it first.",
cost: new Decimal(69), cost:() => new Decimal(69),
currencyDisplayName: "candies", // Use if using a nonstandard currency currencyDisplayName: "candies", // Use if using a nonstandard currency
currencyInternalName: "points", // Use if using a nonstandard currency currencyInternalName: "points", // Use if using a nonstandard currency
currencyLayer: "", // Leave empty if not in a layer "e.g. points" currencyLayer: "", // Leave empty if not in a layer "e.g. points"
unl() { return player.c.upgrades.includes(12) }, unl() { return player[this.layer].upgrades.includes(12) },
onPurchase() { onPurchase() { // This function triggers when the upgrade is purchased
player.c.order = 0 player[this.layer].order = 0
} }
}, },
}, },
@ -84,13 +107,13 @@ var layers = {
rows: 1, rows: 1,
cols: 1, cols: 1,
respec() { // Optional, reset things and give back your currency. Having this function makes a respec button appear respec() { // Optional, reset things and give back your currency. Having this function makes a respec button appear
player.c.points = player.c.points.add(player.c.spentOnBuyables) // A built-in thing to keep track of this but only keeps a single value player[this.layer].points = player[this.layer].points.add(player[this.layer].spentOnBuyables) // A built-in thing to keep track of this but only keeps a single value
resetBuyables("c") resetBuyables(this.layer)
doReset("c", true) // Force a reset doReset(this.layer, true) // Force a reset
}, },
respecText: "Respec Thingies", // Text on Respec button, optional respecText:() => "Respec Thingies", // Text on Respec button, optional
11: { 11: {
title: "Exhancers", // Optional, displayed at the top in a larger font title:() => "Exhancers", // Optional, displayed at the top in a larger font
cost(x) { // cost for buying xth buyable, can be an object if there are multiple currencies cost(x) { // cost for buying xth buyable, can be an object if there are multiple currencies
if (x.gte(25)) x = x.pow(2).div(25) if (x.gte(25)) x = x.pow(2).div(25)
let cost = Decimal.pow(2, x.pow(1.5)) let cost = Decimal.pow(2, x.pow(1.5))
@ -105,41 +128,46 @@ var layers = {
else eff.second = x.times(-1).pow(0.8).times(-1) else eff.second = x.times(-1).pow(0.8).times(-1)
return eff; return eff;
}, },
display (){ display() { // Everything else displayed in the buyable button after the title
let data = tmp.buyables.c["11"] let data = tmp.buyables[this.layer]["11"]
return "Cost: " + format(data.cost) + " lollipops\n\ return "Cost: " + format(data.cost) + " lollipops\n\
Amount: " + player.c.buyables["11"] + "\n\ Amount: " + player[this.layer].buyables["11"] + "\n\
Adds + " + format(data.effects.first) + " things and multiplies stuff by " + format(data.effects.second) Adds + " + format(data.effect.first) + " things and multiplies stuff by " + format(data.effect.second)
}, },
unl() { return player.c.unl }, unl() { return player[this.layer].unl },
canAfford() {return player.c.points.gte(tmp.buyables.c[11].cost)}, canAfford() {
return player[this.layer].points.gte(tmp.buyables["c"][11].cost)},
buy() { buy() {
cost = tmp.buyables.c[11].cost cost = tmp.buyables[this.layer][11].cost
player.c.points = player.c.points.sub(cost) player[this.layer].points = player[this.layer].points.sub(cost)
player.c.buyables[11] = player.c.buyables[11].add(1) player[this.layer].buyables[11] = player[this.layer].buyables[11].add(1)
player.c.spentOnBuyables = player.c.spentOnBuyables.add(cost) // This is a built-in system that you can use for respeccing but it only works with a single Decimal value player[this.layer].spentOnBuyables = player[this.layer].spentOnBuyables.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 buyMax() {}, // You'll have to handle this yourself if you want
}, },
}, },
doReset(layer){ doReset(resettingLayer){ // 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[layer].row > layers["c"].row) fullLayerReset('c') // This is actually the default behavior if(layers[resettingLayer].row > this.row) fullLayerReset(this.layer) // This is actually the default behavior
}, },
convertToDecimal() { convertToDecimal() {
// Convert any layer-specific values (besides points, total, and best) to Decimal // Convert any layer-specific Decimal values (besides points, total, and best) from String to Decimal (used when loading save)
}, },
layerShown() {return true}, // Condition for when layer appears layerShown() {return true}, // Condition for when layer appears on the tree
update(diff) { update(diff) {
if (player.c.upgrades.includes(11)) player.points = player.points.add(tmp.pointGen.times(diff)).max(0) if (player[this.layer].upgrades.includes(11)) player.points = player.points.add(tmp.pointGen.times(diff)).max(0)
}, // Do any gameloop things (e.g. resource generation) inherent to this layer }, // Do any gameloop things (e.g. resource generation) inherent to this layer
automate() { automate() {
}, // Do any automation inherent to this layer if appropriate }, // Do any automation inherent to this layer if appropriate
updateTemp() { updateTemp() {
}, // Do any necessary temp updating }, // Do any necessary temp updating, not that important usually
resetsNothing() {return false}, resetsNothing() {return false},
onPrestige(gain) {
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: [ hotkeys: [
{key: "c", desc: "C: reset for lollipops or whatever", onPress(){if (player.c.unl) doReset("c")}}, {key: this.layer, desc: "C: reset for lollipops or whatever", onPress(){if (player[this.layer].unl) doReset(this.layer)}},
{key: "ctrl+c", desc: "Ctrl+c: respec things", onPress(){if (player.c.unl) respecBuyables("c")}}, {key: "ctrl+" + this.layer, desc: "Ctrl+c: respec things", onPress(){if (player[this.layer].unl) respecBuyables(this.layer)}},
], ],
incr_order: [], // Array of layer names to have their order increased when this one is first unlocked incr_order: [], // Array of layer names to have their order increased when this one is first unlocked
@ -151,20 +179,20 @@ var layers = {
function() {return 'I have ' + format(player.points) + ' pointy points!'}, function() {return 'I have ' + format(player.points) + ' pointy points!'},
{"color": "red", "font-size": "32px", "font-family": "Comic Sans MS"}], {"color": "red", "font-size": "32px", "font-family": "Comic Sans MS"}],
["buyables", "150px"], ["buyables", "150px"],
["toggle", ["c", "beep"]], ["toggle", [this.layer, "beep"]],
"milestones", "upgrades"], "milestones", "upgrades", "challs"],
style: { style() {return {
'background-color': 'blue' 'background-color': 'blue'
}, }},
}, })
f: { addLayer("f", {
startData() { return { startData() { return {
unl: false, unl: false,
points: new Decimal(0), points: new Decimal(0),
boop: false, boop: false,
}}, }},
color: "#FE0102", color:() => "#FE0102",
requires() {return new Decimal(200)}, requires() {return new Decimal(200)},
resource: "farm points", resource: "farm points",
baseResource: "candies", baseResource: "candies",
@ -181,35 +209,6 @@ var layers = {
layerShown() {return true}, layerShown() {return true},
branches: [["c", 1]] // Each pair corresponds to a line added to the tree when this node is unlocked. The letter is the other end of the line, and the number affects the color, 1 is default branches: [["c", 1]] // Each pair corresponds to a line added to the tree when this node is unlocked. The letter is the other end of the line, and the number affects the color, 1 is default
}, },
} )
function layerShown(layer){
return layers[layer].layerShown();
}
var LAYERS = Object.keys(layers);
var hotkeys = {};
var ROW_LAYERS = {}
for (layer in layers){
row = layers[layer].row
if(!ROW_LAYERS[row]) ROW_LAYERS[row] = {}
ROW_LAYERS[row][layer]=layer;
}
function addLayer(layerName, layerData){ // Call this to add layers from a different file!
layers[layerName] = layerData
LAYERS = Object.keys(layers);
ROW_LAYERS = {}
for (layer in layers){
row = layers[layer].row
if(!ROW_LAYERS[row]) ROW_LAYERS[row] = {}
ROW_LAYERS[row][layer]=layer;
}
updateHotkeys()
}

View file

@ -1,6 +1,6 @@
function updateTemp() { function updateTemp() {
if (!tmp.challActive) {tmp.challActive = {}} if (!tmp.challActive) {tmp.challActive = {}}
if (!tmp.challs) tmp.challs = {}
for (layer in layers) { for (layer in layers) {
if(layers[layer].challs !== undefined){ if(layers[layer].challs !== undefined){
tmp.challActive[layer] = {} tmp.challActive[layer] = {}
@ -8,6 +8,19 @@ function updateTemp() {
} }
} }
if (!tmp.upgrades) tmp.upgrades = {}
for (layer in layers) {
if(layers[layer].upgrades !== undefined){
updateUpgradeTemp(layer)
}
}
if (!tmp.milestones) tmp.milestones = {}
for (layer in layers) {
if(layers[layer].milestones !== undefined){
updateMilestoneTemp(layer)
}
}
if (!tmp.layerEffs) tmp.layerEffs = {} if (!tmp.layerEffs) tmp.layerEffs = {}
for (layer in layers) if (layers[layer].effect) tmp.layerEffs[layer] = layers[layer].effect() for (layer in layers) if (layers[layer].effect) tmp.layerEffs[layer] = layers[layer].effect()
@ -17,12 +30,8 @@ function updateTemp() {
if (!tmp.buyables) tmp.buyables = {} if (!tmp.buyables) tmp.buyables = {}
for (layer in layers) if (layers[layer].buyables) { for (layer in layers) if (layers[layer].buyables) {
if (!tmp.buyables[layer]) tmp.buyables[layer] = {} if(layers[layer].buyables !== undefined){
for (id in player[layer].buyables){ updateBuyableTemp(layer)
if (!tmp.buyables[layer][id]) tmp.buyables[layer][id] = {}
tmp.buyables[layer][id]
tmp.buyables[layer][id].cost = layers[layer].buyables[id].cost(player[layer].buyables[id])
tmp.buyables[layer][id].effects = layers[layer].buyables[id].effect(player[layer].buyables[id])
} }
} }
@ -31,13 +40,23 @@ function updateTemp() {
if (!tmp.resetGain) tmp.resetGain = {} if (!tmp.resetGain) tmp.resetGain = {}
if (!tmp.nextAt) tmp.nextAt = {} if (!tmp.nextAt) tmp.nextAt = {}
if (!tmp.layerAmt) tmp.layerAmt = {} if (!tmp.layerAmt) tmp.layerAmt = {}
if (!tmp.layerColor) tmp.layerColor = {}
if (!tmp.layerShown) tmp.layerShown = {}
if (!tmp.effectDescription) tmp.effectDescription = {}
if (!tmp.style) tmp.style = {}
for (layer in layers) { for (layer in layers) {
if (layers[layer].color) tmp.layerColor[layer] = layers[layer].color()
if (layers[layer].style) tmp.style[layer] = layers[layer].style()
tmp.layerShown[layer] = layers[layer].layerShown()
tmp.layerAmt[layer] = layers[layer].baseAmount() tmp.layerAmt[layer] = layers[layer].baseAmount()
tmp.gainMults[layer] = layers[layer].gainMult() tmp.gainMults[layer] = layers[layer].gainMult()
tmp.gainExp[layer] = layers[layer].gainExp() tmp.gainExp[layer] = layers[layer].gainExp()
tmp.resetGain[layer] = getResetGain(layer) tmp.resetGain[layer] = getResetGain(layer)
tmp.nextAt[layer] = getNextAt(layer) tmp.nextAt[layer] = getNextAt(layer)
if (layers[layer].effectDescription) tmp.effectDescription[layer] = layers[layer].effectDescription()
} }
tmp.pointGen = getPointGen() tmp.pointGen = getPointGen()
@ -49,6 +68,7 @@ function updateTemp() {
function updateChallTemp(layer) { function updateChallTemp(layer) {
if (player[layer] === undefined) return if (player[layer] === undefined) return
if (!tmp.challs[layer]) tmp.challs[layer] = {}
let data = tmp.challActive[layer] let data = tmp.challActive[layer]
let data2 = layers[layer].challs let data2 = layers[layer].challs
@ -56,8 +76,72 @@ function updateChallTemp(layer) {
for (let row = 1; row <= data2.rows; row++) { for (let row = 1; row <= data2.rows; row++) {
for (let col = 1; col <= data2.cols; col++) { for (let col = 1; col <= data2.cols; col++) {
let id = row * 10 + col let id = row * 10 + col
tmp.challs[layer][id] = {}
tmp.challs[layer][id].unl = data2[id].unl()
if(data2[id].name) tmp.challs[layer][id].name = data2[id].name()
if(data2[id].desc) tmp.challs[layer][id].desc = data2[id].desc()
if(data2[id].reward) tmp.challs[layer][id].reward = data2[id].reward()
if(data2[id].effect) tmp.challs[layer][id].effect = data2[id].effect()
if(data2[id].effectDisplay) tmp.challs[layer][id].effectDisplay = data2[id].effectDisplay(tmp.challs[layer][id].effect)
tmp.challs[layer][id].goal = data2[id].goal()
if (customActive ? data2.active(id) : player[layer].active == id) data[id] = 1 if (customActive ? data2.active(id) : player[layer].active == id) data[id] = 1
else delete data[id] else delete data[id]
} }
} }
} }
function updateUpgradeTemp(layer) {
if (player[layer] === undefined) return
if (!tmp.upgrades[layer]) tmp.upgrades[layer] = {}
let data2 = layers[layer].upgrades
for (let row = 1; row <= data2.rows; row++) {
for (let col = 1; col <= data2.cols; col++) {
let id = row * 10 + col
tmp.upgrades[layer][id] = {}
tmp.upgrades[layer][id].unl = data2[id].unl()
if(data2[id].title) tmp.upgrades[layer][id].title = data2[id].title()
if(data2[id].effect) tmp.upgrades[layer][id].effect = data2[id].effect()
if(data2[id].effectDisplay) tmp.upgrades[layer][id].effectDisplay = data2[id].effectDisplay(tmp.upgrades[layer][id].effect)
if(data2[id].desc) tmp.upgrades[layer][id].desc = data2[id].desc()
tmp.upgrades[layer][id].cost = data2[id].cost()
}
}
}
function updateMilestoneTemp(layer) {
if (player[layer] === undefined) return
if (!tmp.milestones[layer]) tmp.milestones[layer] = {}
let data2 = layers[layer].milestones
for (id in data2) {
tmp.milestones[layer][id] = {}
tmp.milestones[layer][id].done = data2[id].done()
if(data2[id].requirementDesc) tmp.milestones[layer][id].requirementDesc = data2[id].requirementDesc()
if(data2[id].effectDesc) tmp.milestones[layer][id].effectDesc = data2[id].effectDesc()
}
}
function updateBuyableTemp(layer) {
if (player[layer] === undefined) return
if (!tmp.buyables[layer]) tmp.buyables[layer] = {}
let data2 = layers[layer].buyables
if(data2.respecText) tmp.buyables[layer].respecText = data2.respecText()
for (let row = 1; row <= data2.rows; row++) {
for (let col = 1; col <= data2.cols; col++) {
let id = row * 10 + col
let amt = player[layer].buyables[id]
tmp.buyables[layer][id] = {}
tmp.buyables[layer][id].unl = data2[id].unl()
if(data2[id].effect) tmp.buyables[layer][id].effect = data2[id].effect(amt)
tmp.buyables[layer][id].cost = data2[id].cost(amt)
tmp.buyables[layer][id].canAfford = data2[id].canAfford()
if(data2[id].title) tmp.buyables[layer][id].title = data2[id].title()
if(data2[id].display) tmp.buyables[layer][id].display = data2[id].display()
}
}
}

53
js/v.js
View file

@ -16,12 +16,12 @@ function loadVue() {
v-bind:class="{ v-bind:class="{
treeNode: true, treeNode: true,
[layer]: true, [layer]: true,
hidden: !layers[layer].layerShown(), hidden: !tmp.layerShown[layer],
locked: !player[layer].unl && !tmp.layerAmt[layer].gte(tmp.layerReqs[layer]), locked: player[layer].unl && !tmp.layerAmt[layer].gte(tmp.layerReqs[layer]),
can: layerUnl(layer), can: layerUnl(layer),
}" }"
v-bind:style="{ v-bind:style="{
'background-color': layers[layer].color, 'background-color': tmp.layerColor[layer],
}"> }">
{{abb}} {{abb}}
</button> </button>
@ -34,13 +34,13 @@ function loadVue() {
<div v-if="layers[layer].challs" class="upgTable"> <div v-if="layers[layer].challs" class="upgTable">
<div v-for="row in layers[layer].challs.rows" class="upgRow"> <div v-for="row in layers[layer].challs.rows" class="upgRow">
<div v-for="col in layers[layer].challs.cols"> <div v-for="col in layers[layer].challs.cols">
<div v-if="layers[layer].challs[row*10+col].unl()" v-bind:class="{hChall: true, done: player[layer].challs.includes(row*10+col), canComplete: tmp.challActive[layer][row*10+col]&&!player[layer].challs.includes(row*10+col)&&canCompleteChall(layer, row*10+col)}"> <div v-if="tmp.challs[layer][row*10+col].unl" v-bind:class="{hChall: true, done: player[layer].challs.includes(row*10+col), canComplete: tmp.challActive[layer][row*10+col]&&!player[layer].challs.includes(row*10+col)&&canCompleteChall(layer, row*10+col)}">
<br><h3>{{layers[layer].challs[row*10+col].name}}</h3><br><br> <br><h3>{{tmp.challs[layer][row*10+col].name}}</h3><br><br>
<button v-bind:class="{ longUpg: true, can: true, [layer]: true }" v-bind:style="{'background-color': layers[layer].color}" v-on:click="startChall(layer, row*10+col)">{{player[layer].active==(row*10+col)?(canCompleteChall(layer, row*10+col)?"Finish":"Exit Early"):(player[layer].challs.includes(row*10+col)?"Completed":"Start")}}</button><br><br> <button v-bind:class="{ longUpg: true, can: true, [layer]: true }" v-bind:style="{'background-color': tmp.layerColor[layer]}" v-on:click="startChall(layer, row*10+col)">{{player[layer].active==(row*10+col)?(canCompleteChall(layer, row*10+col)?"Finish":"Exit Early"):(player[layer].challs.includes(row*10+col)?"Completed":"Start")}}</button><br><br>
{{layers[layer].challs[row*10+col].desc}}<br> {{tmp.challs[layer][row*10+col].desc}}<br>
Goal: {{format(layers[layer].challs[row*10+col].goal)}} {{layers[layer].challs[row*10+col].currencyDisplayName ? layers[layer].challs[row*10+col].currencyDisplayName : "points"}}<br> Goal: {{format(tmp.challs[layer][row*10+col].goal)}} {{layers[layer].challs[row*10+col].currencyDisplayName ? layers[layer].challs[row*10+col].currencyDisplayName : "points"}}<br>
Reward: {{layers[layer].challs[row*10+col].reward}}<br> Reward: {{tmp.challs[layer][row*10+col].reward}}<br>
<span v-if="layers[layer].challs[row*10+col].effDisp!==undefined">Currently: {{(layers[layer].challs[row*10+col].effDisp) ? (layers[layer].challs[row*10+col].effDisp(layers[layer].challs[row*10+col].effect())) : format(layers[layer].challs[row*10+col].effect())}}</span> <span v-if="tmp.challs[layer][row*10+col].effect!==undefined">Currently: {{(tmp.challs[layer][row*10+col].effectDisplay) ? (tmp.challs[layer][row*10+col].effectDisplay) : format(tmp.challs[layer][row*10+col].effect)}}</span>
</div> </div>
</div> </div>
</div> </div>
@ -54,7 +54,11 @@ function loadVue() {
<div v-if="layers[layer].upgrades" class="upgTable"> <div v-if="layers[layer].upgrades" class="upgTable">
<div v-for="row in layers[layer].upgrades.rows" class="upgRow"> <div v-for="row in layers[layer].upgrades.rows" class="upgRow">
<div v-for="col in layers[layer].upgrades.cols" class="upgAlign"> <div v-for="col in layers[layer].upgrades.cols" class="upgAlign">
<button v-if="layers[layer].upgrades[row*10+col].unl()" v-on:click="buyUpg(layer, row*10+col)" v-bind:class="{ [layer]: true, upg: true, bought: player[layer].upgrades.includes(row*10+col), locked: (!(canAffordUpg(layer, row*10+col))&&!player[layer].upgrades.includes(row*10+col)), can: (canAffordUpg(layer, row*10+col)&&!player[layer].upgrades.includes(row*10+col))}" v-bind:style="{'background-color': layers[layer].color}">{{ layers[layer].upgrades[row*10+col].desc }}<span v-if="layers[layer].upgrades[row*10+col].effect"><br>Currently: {{(layers[layer].upgrades[row*10+col].effDisp) ? (layers[layer].upgrades[row*10+col].effDisp(layers[layer].upgrades[row*10+col].effect())) : format(layers[layer].upgrades[row*10+col].effect())}}</span><br><br>Cost: {{ formatWhole(layers[layer].upgrades[row*10+col].cost) }} {{(layers[layer].upgrades[row*10+col].currencyDisplayName ? layers[layer].upgrades[row*10+col].currencyDisplayName : layers[layer].resource)}}</button> <button v-if="tmp.upgrades[layer][row*10+col].unl" v-on:click="buyUpg(layer, row*10+col)" v-bind:class="{ [layer]: true, upg: true, bought: player[layer].upgrades.includes(row*10+col), locked: (!(canAffordUpg(layer, row*10+col))&&!player[layer].upgrades.includes(row*10+col)), can: (canAffordUpg(layer, row*10+col)&&!player[layer].upgrades.includes(row*10+col))}" v-bind:style="{'background-color': tmp.layerColor[layer]}">
<span v-if= "tmp.upgrades[layer][row*10+col].title"><h3>{{tmp.upgrades[layer][row*10+col].title}}</h3><br></span>
{{ tmp.upgrades[layer][row*10+col].desc }}
<span v-if="tmp.upgrades[layer][row*10+col].effect"><br>Currently: {{(tmp.upgrades[layer][row*10+col].effectDisplay) ? (tmp.upgrades[layer][row*10+col].effectDisplay) : format(tmp.upgrades[layer][row*10+col].effect)}}</span>
<br><br>Cost: {{ formatWhole(tmp.upgrades[layer][row*10+col].cost) }} {{(layers[layer].upgrades[row*10+col].currencyDisplayName ? layers[layer].upgrades[row*10+col].currencyDisplayName : layers[layer].resource)}}</button>
</div> </div>
</div> </div>
<br> <br>
@ -68,7 +72,7 @@ function loadVue() {
<div v-if="layers[layer].milestones"> <div v-if="layers[layer].milestones">
<table> <table>
<tr v-for="id in Object.keys(layers[layer].milestones)"> <tr v-for="id in Object.keys(layers[layer].milestones)">
<td v-if="milestoneShown(layer, id)" v-bind:class="{milestone: !player[layer].milestones.includes(id), milestoneDone: player[layer].milestones.includes(id)}"><h3>{{layers[layer].milestones[id].requirementDesc}}</h3><br>{{layers[layer].milestones[id].effectDesc}}<br><span v-if="(layers[layer].milestones[id].toggles)&&(player[layer].milestones.includes(id))" v-for="toggle in layers[layer].milestones[id].toggles"><toggle :layer= "layer" :data= "toggle"></toggle>&nbsp;</span></td></tr> <td v-if="milestoneShown(layer, id)" v-bind:class="{milestone: !player[layer].milestones.includes(id), milestoneDone: player[layer].milestones.includes(id)}"><h3>{{tmp.milestones[layer][id].requirementDesc}}</h3><br>{{tmp.milestones[layer][id].effectDesc}}<br><span v-if="(layers[layer].milestones[id].toggles)&&(player[layer].milestones.includes(id))" v-for="toggle in layers[layer].milestones[id].toggles"><toggle :layer= "layer" :data= "toggle"></toggle>&nbsp;</span></td></tr>
</tr> </tr>
</table> </table>
<br> <br>
@ -79,7 +83,7 @@ function loadVue() {
Vue.component('toggle', { Vue.component('toggle', {
props: ['layer', 'data'], props: ['layer', 'data'],
template: ` template: `
<button class="smallUpg can" v-bind:style="{'background-color': layers[data[0]].color}" v-on:click="toggleAuto(data)">{{player[data[0]][data[1]]?"ON":"OFF"}}</button> <button class="smallUpg can" v-bind:style="{'background-color': tmp.layerColor[layer])}" v-on:click="toggleAuto(data)">{{player[data[0]][data[1]]?"ON":"OFF"}}</button>
` `
}) })
@ -88,8 +92,8 @@ function loadVue() {
props: ['layer', 'data'], props: ['layer', 'data'],
template: ` template: `
<span> <span>
<button v-if="layers[layer].type=='normal'" v-bind:class="{ [layer]: true, reset: true, locked: tmp.layerAmt[layer].lt(tmp.layerReqs[layer]), can: tmp.layerAmt[layer].gte(tmp.layerReqs[layer]) }" v-bind:style="{'background-color': layers[layer].color}" v-on:click="doReset(layer)"><span v-if="player[layer].points.lt(1e3)">{{data ? data() : "Reset for "}}</span>+<b>{{formatWhole(tmp.resetGain[layer])}}</b> {{layers[layer].resource}}<span v-if="tmp.resetGain[layer].lt(100) && player[layer].points.lt(1e3)"><br><br>Next at {{ (layers[layer].resCeil ? formatWhole(tmp.nextAt[layer]) : format(tmp.nextAt[layer])) }} {{ layers[layer].baseResource }}</span></button> <button v-if="layers[layer].type=='normal'" v-bind:class="{ [layer]: true, reset: true, locked: tmp.layerAmt[layer].lt(tmp.layerReqs[layer]), can: tmp.layerAmt[layer].gte(tmp.layerReqs[layer]) }" v-bind:style="{'background-color': tmp.layerColor[layer]}" v-on:click="doReset(layer)"><span v-if="player[layer].points.lt(1e3)">{{data ? data() : "Reset for "}}</span>+<b>{{formatWhole(tmp.resetGain[layer])}}</b> {{layers[layer].resource}}<span v-if="tmp.resetGain[layer].lt(100) && player[layer].points.lt(1e3)"><br><br>Next at {{ (layers[layer].resCeil ? formatWhole(tmp.nextAt[layer]) : format(tmp.nextAt[layer])) }} {{ layers[layer].baseResource }}</span></button>
<button v-if="layers[layer].type=='static'" v-bind:class="{ [layer]: true, reset: true, locked: tmp.layerAmt[layer].lt(tmp.nextAt[layer]), can: tmp.layerAmt[layer].gte(tmp.nextAt[layer]) }" v-bind:style="{'background-color': layers[layer].color}" v-on:click="doReset(layer)"><span v-if="player[layer].points.lt(10)">{{data ? data() : "Reset for "}}</span>+<b>{{formatWhole(tmp.resetGain[layer])}}</b> {{layers[layer].resource}}<br><br><span v-if="player[layer].points.lt(10)">Req: {{formatWhole(tmp.layerAmt[layer])}} / </span>{{(layers[layer].resCeil ? formatWhole(tmp.nextAt[layer]) : format(tmp.nextAt[layer]))}} {{ layers[layer].baseResource }}</button> <button v-if="layers[layer].type=='static'" v-bind:class="{ [layer]: true, reset: true, locked: tmp.layerAmt[layer].lt(tmp.nextAt[layer]), can: tmp.layerAmt[layer].gte(tmp.nextAt[layer]) }" v-bind:style="{'background-color': tmp.layerColor[layer]}" v-on:click="doReset(layer)"><span v-if="player[layer].points.lt(10)">{{data ? data() : "Reset for "}}</span>+<b>{{formatWhole(tmp.resetGain[layer])}}</b> {{layers[layer].resource}}<br><br><span v-if="player[layer].points.lt(10)">Req: {{formatWhole(tmp.layerAmt[layer])}} / </span>{{(layers[layer].resCeil ? formatWhole(tmp.nextAt[layer]) : format(tmp.nextAt[layer]))}} {{ layers[layer].baseResource }}</button>
</span> </span>
` `
}) })
@ -98,7 +102,7 @@ function loadVue() {
Vue.component('main-display', { Vue.component('main-display', {
props: ['layer'], props: ['layer'],
template: ` template: `
<div><span v-if="player[layer].points.lt('1e1000')">You have </span><h2 v-bind:style="{'color': layers[layer].color, 'text-shadow': '0px 0px 10px' + layers[layer].color}">{{formatWhole(player[layer].points)}}</h2> {{layers[layer].resource}}<span v-if="layers[layer].effectDescription">, {{layers[layer].effectDescription()}}</span><br><br></span> <div><span v-if="player[layer].points.lt('1e1000')">You have </span><h2 v-bind:style="{'color': tmp.layerColor[layer], 'text-shadow': '0px 0px 10px' + tmp.layerColor[layer]}">{{formatWhole(player[layer].points)}}</h2> {{layers[layer].resource}}<span v-if="layers[layer].effectDescription">, {{tmp.effectDescription[layer]}}</span><br><br></span>
` `
}) })
@ -107,7 +111,7 @@ function loadVue() {
props: ['layer', 'data'], props: ['layer', 'data'],
template: ` template: `
<div v-if="layers[layer].buyables" class="upgTable"> <div v-if="layers[layer].buyables" class="upgTable">
<button v-if="layers[layer].buyables.respec" v-on:click="respecBuyables(layer)" v-bind:class="{ longUpg: true, can: player[layer].unl, locked: !player[layer].unl }">{{layers[layer].buyables.respecText ? layers[layer].buyables.respecText : "Respec"}}</button><br> <button v-if="layers[layer].buyables.respec" v-on:click="respecBuyables(layer)" v-bind:class="{ longUpg: true, can: player[layer].unl, locked: !player[layer].unl }">{{layers[layer].buyables.respecText ? tmp.buyables[layer].respecText : "Respec"}}</button><br>
<div v-for="row in layers[layer].buyables.rows" class="upgRow"> <div v-for="row in layers[layer].buyables.rows" class="upgRow">
<div v-for="col in layers[layer].buyables.cols" class="upgAlign" v-bind:style="{'margin-left': '7px', 'margin-right': '7px', 'height': (data ? data : '200px'),}"> <div v-for="col in layers[layer].buyables.cols" class="upgAlign" v-bind:style="{'margin-left': '7px', 'margin-right': '7px', 'height': (data ? data : '200px'),}">
<buyable :layer = "layer" :data = "row*10+col" :size = "data"></buyable> <buyable :layer = "layer" :data = "row*10+col" :size = "data"></buyable>
@ -124,12 +128,12 @@ function loadVue() {
template: ` template: `
<div v-if="layers[layer].buyables"> <div v-if="layers[layer].buyables">
<button <button
v-if="layers[layer].buyables[data].unl()" v-if="tmp.buyables[layer][data].unl"
v-bind:class="{ upg: true, can: layers[layer].buyables[data].canAfford(), locked: !layers[layer].buyables[data].canAfford()}" v-bind:class="{ upg: true, can: tmp.buyables[layer][data].canAfford, locked: !tmp.buyables[layer][data].canAfford}"
v-bind:style="{'background-color': layers[layer].color, 'height': (size ? size : '200px'), 'width': (size ? size : '200px')}" v-bind:style="{'background-color': tmp.layerColor[layer], 'height': (size ? size : '200px'), 'width': (size ? size : '200px')}"
v-on:click="buyBuyable(layer, data)"> v-on:click="buyBuyable(layer, data)">
<span v-if= "layers[layer].buyables[data].title"><h2>{{layers[layer].buyables[data].title}}</h2><br></span> <span v-if= "layers[layer].buyables[data].title"><h2>{{tmp.buyables[layer][data].title}}</h2><br></span>
<span v-bind:style="{'white-space': 'pre-line'}">{{layers[layer].buyables[data].display()}}</span> <span v-bind:style="{'white-space': 'pre-line'}">{{tmp.buyables[layer][data].display}}</span>
</button> </button>
</div> </div>
` `
@ -139,7 +143,7 @@ function loadVue() {
Vue.component('display-text', { Vue.component('display-text', {
props: ['layer', 'data'], props: ['layer', 'data'],
template: ` template: `
<span>{{data()}}</span> <span>{{readData(data)}}</span>
` `
}) })
@ -147,7 +151,7 @@ function loadVue() {
Vue.component('raw-html', { Vue.component('raw-html', {
props: ['layer', 'data'], props: ['layer', 'data'],
template: ` template: `
<span v-html="data()"></span> <span v-html="readData(data)"></span>
` `
}) })
@ -164,7 +168,6 @@ function loadVue() {
data: { data: {
player, player,
tmp, tmp,
layers,
Decimal, Decimal,
format, format,
formatWhole, formatWhole,

View file

@ -1,213 +0,0 @@
var layers = {
c: {
startData() { return {
unl: true,
points: new Decimal(0),
best: new Decimal(0),
total: new Decimal(0),
order: 0, // Used for tracking other relevant layers unlocked before this one
beep:false,
}},
color: "#4BEC13",
requires() {return new Decimal(10)}, // Can be a function that takes requirement increases into account
resource: "lollipops", // Name of prestige currency
baseResource: "candies", // Name of resource prestige is based on
baseAmount() {return player.points},
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))
resCeil: false, // True if the resource needs to be rounded up
canBuyMax() {}, // Only needed for static layers
gainMult() {
mult = new Decimal(1)
if (player.c.upgrades.includes(21)) mult = mult.times(2)
if (player.c.upgrades.includes(23)) mult = mult.times(LAYER_UPGS.c[23].currently())
return mult
},
gainExp() {
return new Decimal(1)
},
row: 0,
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: (true == false ? 0 : Decimal.pow(player.c.points, 0.2)),
icecreamCap: (player.c.points * 10)
}},
effectDescription() {
eff = layers.c.effect();
return "which are boosting waffles by "+format(eff.waffleBoost)+" and increasing the Ice Cream cap by "+format(eff.icecreamCap)
},
doReset(layer){
if(layers[layer].row > layers["c"].row) fullLayerReset('c') // This is actually the default behavior
},
upgrades: {
rows: 1,
cols: 3,
11: {
desc: "Gain 1 Candy every second.",
cost: new Decimal(1),
unl() { return player.c.unl },
},
12: {
desc: "Candy generation is faster based on your unspent Lollipops.",
cost: new Decimal(1),
unl() { return player.c.upgrades.includes(11) },
effect() {
let ret = player.c.points.add(1).pow(player.c.upgrades.includes(24)?1.1:(player.c.upgrades.includes(14)?0.75:0.5))
if (ret.gte("1e20000000")) ret = ret.sqrt().times("1e10000000")
return ret;
},
effDisp(fx) { return format(fx)+"x" },
},
13: {
desc: "Make this layer act like you bought it first.",
cost: new Decimal(69),
currencyDisplayName: "candies", // Use if using a nonstandard currency
currencyInternalName: "points", // Use if using a nonstandard currency
currencyLayer: "", // Leave empty if not in a layer "e.g. points"
unl() { return player.c.upgrades.includes(12) },
onPurchase() {
player.c.order = 0
}
},
},
milestones: {
0: {requirementDesc: "3 Lollipops",
done() {return player.c.best.gte(3)},
effectDesc: "Makes this green",
},
1: {requirementDesc: "4 Lollipops",
done() {return player.c.best.gte(4)},
effectDesc: "You can toggle beep and boop (which do nothing)",
toggles: [
["c", "beep"], // Each toggle is defined by a layer and the data toggled for that layer
["f", "boop"]
],
}
},
challs: {
rows: 1,
cols: 1,
11: {
name: "Fun",
desc: "Makes the game 0% harder",
unl() { return player.c.best.gt(0) },
goal: new Decimal("20"),
currencyDisplayName: "lollipops", // Use if using a nonstandard currency
currencyInternalName: "points", // Use if using a nonstandard currency
currencyLayer: "c", // Leave empty if not in a layer
effect() {
let ret = player.c.points.add(1).tetrate(0.02)
return ret;
},
effDisp(x) { return format(x)+"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.
reward: "Says hi",
onComplete() {console.log("hiii")} // Called when you complete the challenge
},
},
buyables: {
rows: 1,
cols: 1,
respec() { // Optional, reset things and give back your currency. Having this function makes a respec button appear
player.c.points = player.c.points.add(player.c.spentOnBuyables) // A built-in thing to keep track of this but only keeps a single value
resetBuyables("c")
doReset("c", true) // Force a reset
},
respecText: "Respec Thingies", // Text on Respec button, optional
11: {
title: "Exhancers", // Optional, displayed at the top in a larger font
cost(x) { // cost for buying xth buyable, can be an object if there are multiple currencies
if (x.gte(25)) x = x.pow(2).div(25)
let cost = Decimal.pow(2, x.pow(1.5))
return cost.floor()
},
effect(x) { // Effects of owning x of the items, x is a decimal
let eff = {}
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 (){
let data = tmp.buyables.c["11"]
return "Cost: " + format(data.cost) + " lollipops\n\
Amount: " + player.c.buyables["11"] + "\n\
Adds + " + format(data.effects.first) + " things and multiplies stuff by " + format(data.effects.second)
},
unl() { return player.c.unl },
canAfford() {return player.c.points.gte(tmp.buyables.c[11].cost)},
buy() {
cost = tmp.buyables.c[11].cost
player.c.points = player.c.points.sub(cost)
player.c.buyables[11] = player.c.buyables[11].add(1)
player.c.spentOnBuyables = player.c.spentOnBuyables.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
},
},
convertToDecimal() {
// Convert any layer-specific values (besides points, total, and best) to Decimal after loading
},
layerShown() {return true}, // Condition for when layer appears
update(diff) {
if (player.c.upgrades.includes(11)) player.points = player.points.add(tmp.pointGen.times(diff)).max(0)
}, // Do any gameloop things (e.g. resource generation) inherent to this layer
automate() {}, // Do any automation inherent to this layer if appropriate
updateTemp() {}, // Do any necessary temp updating
resetsNothing() {return false},
onPrestige(gain) {
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", desc: "C: reset for lollipops or whatever", onPress(){if (player.c.unl) doReset("c")}},
{key: "ctrl+c", desc: "Ctrl+c: respec things", onPress(){if (player.c.unl) respecBuyables("c")}},
],
incr_order: [], // Array of layer names to have their order increased when this one is first unlocked
branches: [], // Each pair corresponds to a line added to the tree when this node is unlocked. The letter is the other end of the line, and the number affects the color, 1 is default
// Optional, lets you format the tab yourself by listing components. You can create more in v.js.
tabFormat: ["main-display",
["prestige-button", function(){return "Melt your points into "}],
["raw-html", function() {return "<button onclick='console.log(`yeet`)'>'HI'</button>"}],
["display-text",
function() {return 'I have ' + format(player.points) + ' pointy points!'},
{"color": "red", "font-size": "32px", "font-family": "Comic Sans MS"}],
"blank",
["toggle", ["c", "beep"]],
"milestones", "blank", "blank", "upgrades"] ,
style: {
'background-color': 'blue'
},
},
f: { // This layer contains a more minimal set of things, besides a branch and "boop"
startData() { return {
unl: false,
points: new Decimal(0),
boop: false,
}},
color: "#FE0102",
requires() {return new Decimal(200)},
resource: "stuff",
baseResource: "points",
baseAmount() {return player.points},
type: "normal",
exponent: 0.5,
gainMult() {
return new Decimal(1)
},
gainExp() {
return new Decimal(1)
},
row: 1,
layerShown() {return true}, // Condition for when layer appears
branches: [["c", 1]] // Each pair corresponds to a line added to the tree when this node is unlocked. The letter is the other end of the line, and the number affects the color, 1 is default
},
}
function layerShown(layer){
return layers[layer].layerShown();
}
const LAYERS = Object.keys(layers);