This commit is contained in:
Acamaeda 2020-10-16 11:39:39 -04:00
parent 956f13370d
commit a3d65b72a7
12 changed files with 89 additions and 33 deletions

View file

@ -1,5 +1,13 @@
# The Modding Tree changelog: # The Modding Tree changelog:
### v2.0.3 - 10/16/20
- Fixed hotkeys not displaying in info.
- Fixed the game supressing all external hotkeys.
- You can use more things as currencies for upgrade costs and challenge goals using currencyLocation.
- Added maxTickLength, which can be used to prevent offline time or tab-switching from breaking time-limit based mechanics.
- Made buyable respec buttons, and clickable "master" buttons their own components, and gave them a hide/show feature.
### v2.0.2 - 10/15/20 ### v2.0.2 - 10/15/20
- Branches are now dynamic (they can be functions). - Branches are now dynamic (they can be functions).
- Fixed a crash related to offline time. - Fixed a crash related to offline time.

View file

@ -33,11 +33,9 @@ Individual achievement can have these features:
- done(): A function returning a boolean to determine if the achievement should be awarded. - done(): A function returning a boolean to determine if the achievement should be awarded.
- goalTooltip: Appears when the achievement is hovered over and locked. This is to display the goal (or a hint). - tooltip: Default tooltip for the achievement, appears when it is hovered over. Should convey the goal and any reward for
It can also be a function that returns updating text. Can use basic HTML. completing the achievement. It can also be a function that returns updating text. Can use basic HTML.
- doneTooltip: Appears when the achievement is hovered over and completed. This can display what the player achieved (the goal),
and the rewards, if any. It can also be a function that returns updating text. Can use basic HTML.
- effect(): **optional**, A function that calculates and returns the current values of any bonuses from the achievement. - effect(): **optional**, A function that calculates and returns the current values of any bonuses from the achievement.
Can return a value or an object containing multiple values. Can return a value or an object containing multiple values.
@ -52,4 +50,12 @@ Individual achievement can have these 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 - 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 "key" which the achievement was stored under, for convenient access. - id: **Assigned automagically**. It's the "key" which the achievement was stored under, for convenient access.
The achievement in the example's id is 11. The achievement in the example's id is 11.
- goalTooltip: **optional, depracated** Appears when the achievement is hovered over and locked, overrides the basic tooltip.
This is to display the goal (or a hint). It can also be a function that returns updating text. Can use basic HTML.
- doneTooltip: **optional, depracated** Appears when the achievement is hovered over and completed, overrides the basic tooltip.
This can display what the player achieved (the goal), and the rewards, if any.
It can also be a function that returns updating text. Can use basic HTML.

View file

@ -13,9 +13,10 @@ Buyables should be formatted like this:
buyables: { buyables: {
rows: # of rows rows: # of rows
cols: # of columns cols: # of columns
respec() {}, **optional**, implement it to reset things and give back your currency. respec() {}, //**optional**, implement it to reset things and give back your currency.
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
showRespecButton(){} //**optional**, a function determining whether or not to show the button. Defaults to true if absent.
11: { 11: {
display() {return "Blah"}, display() {return "Blah"},
etc etc

View file

@ -53,7 +53,9 @@ By default, challenges use basic Points for the goal. You can change that using
- currencyDisplayName: **optional**, the name to display for the currency for the goal - currencyDisplayName: **optional**, the name to display for the currency for the goal
- currencyInternalName: **optional**, the internal name for that currency - currencyInternalName: **optional**, the internal name for that currency
- 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 part of a layer, omit. If it's not in a layer, omit. If it's not stored directly in a layer, instead use the next feature.
- currencyLocation: **optional**, if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way.
This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)
- completionLimit: **optional**, the amount of times you can complete this challenge. Default is 1 completion. - completionLimit: **optional**, the amount of times you can complete this challenge. Default is 1 completion.

View file

@ -19,6 +19,7 @@ Clickables should be formatted like this:
masterButtonPress() // **optional** If this is present, an additional button will appear above the clickables. masterButtonPress() // **optional** If this is present, an additional button will appear above the clickables.
// pressing it will call the function. // pressing it will call the function.
masterButtonText: "Press me!" // **optional** text to display on the Master Button masterButtonText: "Press me!" // **optional** text to display on the Master Button
showMasterButton(){} //**optional**, a function determining whether or not to show the button. Defaults to true if absent.
11: { 11: {
display() {return "Blah"}, display() {return "Blah"},
etc etc

View file

@ -31,6 +31,11 @@ These are the existing components, but you can create more in v.js:
If it's a single value (e.g. "20px"), that determines the height. If it's a single value (e.g. "20px"), that determines the height.
If you have a pair of arguments, the first is width and the second is height. If you have a pair of arguments, the first is width and the second is height.
- row: Display a list of components horizontally. The argument is an array of components in the tab layout format.
- column: Display a list of components vertically. The argument is an array of components in the tab layout format.
This is useful to display columns within a row.
- 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 string that 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
@ -50,7 +55,4 @@ These are the existing components, but you can create more in v.js:
- 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]
- row: Display a list of components horizontally. The argument is an array of components in the tab layout format. - respec-button, master-button: The respec and master buttons for buyables and clickables, respectively.
- column: Display a list of components vertically. The argument is an array of components in the tab layout format.
This is useful to display columns within a row.

View file

@ -43,11 +43,13 @@ Individual upgrades can have these features:
- onPurchase() - **optional**, this function will be called when the upgrade is purchased. - onPurchase() - **optional**, this function will be called when the upgrade is purchased.
Good for upgrades like "makes this layer act like it was unlocked first". Good for upgrades like "makes this layer act like it was unlocked first".
By default, upgrades use the main prestige currency for the layer. You can include these to change them: By default, upgrades use the main prestige currency for the layer. You can include these to change them (but it needs to be a Decimal):
- currencyDisplayName: **optional**, the name to display for the currency for the upgrade - currencyDisplayName: **optional**, the name to display for the currency for the upgrade
- currencyInternalName: **optional**, the internal name for that currency - currencyInternalName: **optional**, the internal name for that currency
- 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. If it's not stored directly in a layer, instead use the next feature.
- currencyLocation: **optional**, if your currency is stored in something inside a layer (e.g. a buyable's amount), you can access it this way.
This is a function returning the object in "player" that contains the value (like player[this.layer].buyables)
- style: **Optional**, Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes, - style: **Optional**, Applies CSS to this upgrade, in the form of an object where the keys are CSS attributes,
and the values are the values for those attributes (both as strings) and the values are the values for those attributes (both as strings)

View file

@ -63,7 +63,7 @@
<br><br> <br><br>
Time Played: {{ formatTime(player.timePlayed) }}<br><br> Time Played: {{ formatTime(player.timePlayed) }}<br><br>
<h3>Hotkeys</h3><br> <h3>Hotkeys</h3><br>
<span v-for="key in hotkeys" v-if="player[key.layer].unl"><br>{{key.description}}</span> <span v-for="key in hotkeys" v-if="player[key.layer].unlocked"><br>{{key.description}}</span>
</div> </div>
<div v-if="player.tab=='options'" class="col right"> <div v-if="player.tab=='options'" class="col right">
<button class="back" onclick="showTab('tree')"></button><br> <button class="back" onclick="showTab('tree')"></button><br>

View file

@ -37,7 +37,10 @@ function getPointGen() {
return gain return gain
} }
// You can change this if you have things that can be messed up by long tick lengths
function maxTickLength() {
return(3600000) // Default is 1 hour which is just arbitrarily large
}
function getResetGain(layer, useType = null) { function getResetGain(layer, useType = null) {
let type = useType let type = useType
@ -256,11 +259,14 @@ function canCompleteChallenge(layer, x)
{ {
if (x != player[layer].activeChallenge) return if (x != player[layer].activeChallenge) return
let challenge = layers[layer].challenges[x] let challenge = tmp[layer].challenges[x]
if (challenge.currencyInternalName){ if (challenge.currencyInternalName){
let name = challenge.currencyInternalName let name = challenge.currencyInternalName
if (challenge.currencyLayer){ if (challenge.currencyLocation){
return !(challenge.currencyLocation[name].lt(challenge.goal))
}
else if (challenge.currencyLayer){
let lr = challenge.currencyLayer let lr = challenge.currencyLayer
return !(player[lr][name].lt(readData(challenge.goal))) return !(player[lr][name].lt(readData(challenge.goal)))
} }
@ -306,6 +312,10 @@ function gameLoop(diff) {
} }
if (player.devSpeed) diff *= player.devSpeed if (player.devSpeed) diff *= player.devSpeed
let limit = maxTickLength()
if(diff > limit)
diff = limit
addTime(diff) addTime(diff)
player.points = player.points.add(tmp.pointGen.times(diff)).max(0) player.points = player.points.add(tmp.pointGen.times(diff)).max(0)
for (layer in layers){ for (layer in layers){

View file

@ -107,7 +107,7 @@ addLayer("c", {
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" currencyLocation: "", // The object in player data that the currency is contained in
unlocked() { return (hasUpgrade(this.layer, 12))}, unlocked() { return (hasUpgrade(this.layer, 12))},
onPurchase() { // This function triggers when the upgrade is purchased onPurchase() { // This function triggers when the upgrade is purchased
player[this.layer].unlockOrder = 0 player[this.layer].unlockOrder = 0
@ -126,6 +126,10 @@ addLayer("c", {
22: { 22: {
title: "This upgrade doesn't exist", title: "This upgrade doesn't exist",
description: "Or does it?.", description: "Or does it?.",
currencyLocation() {return player[this.layer].buyables}, // The object in player data that the currency is contained in
currencyDisplayName: "exhancers", // Use if using a nonstandard currency
currencyInternalName: 11, // Use if using a nonstandard currency
cost: new Decimal(3), cost: new Decimal(3),
unlocked() { return player[this.layer].unlocked }, // The upgrade is only visible when this is true unlocked() { return player[this.layer].unlocked }, // The upgrade is only visible when this is true
}, },
@ -133,6 +137,7 @@ addLayer("c", {
buyables: { buyables: {
rows: 1, rows: 1,
cols: 12, cols: 12,
showRespec: true,
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[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 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(this.layer) resetBuyables(this.layer)
@ -186,8 +191,8 @@ addLayer("c", {
}, // 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. }, // 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", description: "C: reset for lollipops or whatever", onPress(){if (player[this.layer].unlocked) doReset(this.layer)}}, {key: "c", description: "C: reset for lollipops or whatever", onPress(){if (canReset(this.layer)) doReset(this.layer)}},
{key: "ctrl+c" + this.layer, description: "Ctrl+c: respec things", onPress(){if (player[this.layer].unlocked) respecBuyables(this.layer)}}, {key: "ctrl+c", description: "Ctrl+c: respec things", onPress(){if (player[this.layer].unlocked) respecBuyables(this.layer)}},
], ],
increaseUnlockOrder: [], // Array of layer names to have their order increased when this one is first unlocked increaseUnlockOrder: [], // Array of layer names to have their order increased when this one is first unlocked
@ -485,8 +490,7 @@ addLayer("a", {
13: { 13: {
name: "EIEIO", name: "EIEIO",
done() {return player.f.points.gte(1)}, done() {return player.f.points.gte(1)},
goalTooltip: "Get a farm point.", // Shows when achievement is not completed tooltip: "Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).", // Showed when the achievement is completed
doneTooltip: "Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).", // Showed when the achievement is completed
onComplete() {console.log("Bork bork bork!")} onComplete() {console.log("Bork bork bork!")}
}, },
}, },

View file

@ -356,7 +356,7 @@ function respecBuyables(layer) {
} }
function canAffordUpgrade(layer, id) { function canAffordUpgrade(layer, id) {
let upg = layers[layer].upgrades[id] let upg = tmp[layer].upgrades[id]
let cost = tmp[layer].upgrades[id].cost let cost = tmp[layer].upgrades[id].cost
return canAffordPurchase(layer, upg, cost) return canAffordPurchase(layer, upg, cost)
} }
@ -414,9 +414,13 @@ function achievementEffect(layer, 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
if (thing.currencyLayer){ if (thing.currencyLocation){
return !(thing.currencyLocation[name].lt(cost))
}
else if (thing.currencyLayer){
let lr = thing.currencyLayer let lr = thing.currencyLayer
return !(player[lr][name].lt(cost)) return !(player[lr][name].lt(cost))
} }
@ -433,12 +437,16 @@ function buyUpg(layer, id) {
if (!player[layer].unlocked) return if (!player[layer].unlocked) return
if (!layers[layer].upgrades[id].unlocked) return if (!layers[layer].upgrades[id].unlocked) return
if (player[layer].upgrades.includes(id)) return if (player[layer].upgrades.includes(id)) return
let upg = layers[layer].upgrades[id] let upg = tmp[layer].upgrades[id]
let cost = tmp[layer].upgrades[id].cost let cost = tmp[layer].upgrades[id].cost
if (upg.currencyInternalName){ if (upg.currencyInternalName){
let name = upg.currencyInternalName let name = upg.currencyInternalName
if (upg.currencyLayer){ if (upg.currencyLocation){
if (upg.currencyLocation[name].lt(cost)) return
upg.currencyLocation[name] = upg.currencyLocation[name].sub(cost)
}
else if (upg.currencyLayer){
let lr = upg.currencyLayer let lr = upg.currencyLayer
if (player[lr][name].lt(cost)) return if (player[lr][name].lt(cost)) return
player[lr][name] = player[lr][name].sub(cost) player[lr][name] = player[lr][name].sub(cost)
@ -589,7 +597,7 @@ document.onkeydown = function(e) {
let key = e.key let key = e.key
if (ctrlDown) key = "ctrl+" + key if (ctrlDown) key = "ctrl+" + key
if (onFocused) return if (onFocused) return
if (ctrlDown && key != "-" && key != "_" && key != "+" && key != "=" && key != "r" && key != "R" && key != "F5") e.preventDefault() if (ctrlDown && hotkeys[key]) e.preventDefault()
if(hotkeys[key]){ if(hotkeys[key]){
if (player[hotkeys[key].layer].unlocked) if (player[hotkeys[key].layer].unlocked)
hotkeys[key].onPress() hotkeys[key].onPress()

20
js/v.js
View file

@ -199,7 +199,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="tmp[layer].buyables.respec" v-on:click="respecBuyables(layer)" v-bind:class="{ longUpg: true, can: player[layer].unlocked, locked: !player[layer].unlocked }">{{tmp[layer].buyables.respecText ? tmp[layer].buyables.respecText : "Respec"}}</button><br> <respec-button v-if="tmp[layer].buyables.respec && !(layers[layer].buyables.showRespec !== undefined && tmp[layer].buyables.showRespec == false)" :layer = "layer" v-bind:style="[{'margin-bottom': '12px'}, tmp[layer].componentStyles['respec-button']]"></respec-button>
<div v-for="row in tmp[layer].buyables.rows" class="upgRow"> <div v-for="row in tmp[layer].buyables.rows" class="upgRow">
<div v-for="col in tmp[layer].buyables.cols"><div v-if="layers[layer].buyables[row*10+col]!== undefined && tmp[layer].buyables[row*10+col].unlocked" class="upgAlign" v-bind:style="{'margin-left': '7px', 'margin-right': '7px', 'height': (data ? data : 'inherit'),}"> <div v-for="col in tmp[layer].buyables.cols"><div v-if="layers[layer].buyables[row*10+col]!== undefined && tmp[layer].buyables[row*10+col].unlocked" class="upgAlign" v-bind:style="{'margin-left': '7px', 'margin-right': '7px', 'height': (data ? data : 'inherit'),}">
<buyable :layer = "layer" :data = "row*10+col" :size = "data" v-bind:style="tmp[layer].componentStyles.buyable"></buyable> <buyable :layer = "layer" :data = "row*10+col" :size = "data" v-bind:style="tmp[layer].componentStyles.buyable"></buyable>
@ -225,13 +225,19 @@ function loadVue() {
` `
}) })
Vue.component('respec-button', {
props: ['layer', 'data'],
template: `
<button v-if="layers[layer].buyables && tmp[layer].buyables.respec && !(layers[layer].buyables.showRespec !== undefined && tmp[layer].buyables.showRespec == false)" v-on:click="respecBuyables(layer)" v-bind:class="{ longUpg: true, can: player[layer].unlocked, locked: !player[layer].unlocked }">{{tmp[layer].buyables.respecText ? tmp[layer].buyables.respecText : "Respec"}}</button><br>
`
})
// data = button size, in px // data = button size, in px
Vue.component('clickables', { Vue.component('clickables', {
props: ['layer', 'data'], props: ['layer', 'data'],
template: ` template: `
<div v-if="layers[layer].clickables" class="upgTable"> <div v-if="layers[layer].clickables" class="upgTable">
<button v-if="tmp[layer].clickables.masterButtonPress" v-on:click="layers[layer].clickables.masterButtonPress()" v-bind:class="{ longUpg: true, can: player[layer].unlocked, locked: !player[layer].unlocked }">{{tmp[layer].clickables.masterButtonText ? tmp[layer].clickables.masterButtonText : "Click me!"}}</button><br> <master-button v-if="tmp[layer].clickables.masterButtonPress && !(layers[layer].clickables.showMasterButton !== undefined && tmp[layer].clickables.showMasterButton == false)" :layer = "layer" v-bind:style="[{'margin-bottom': '12px'}, tmp[layer].componentStyles['master-button']]"></master-button>
<div v-for="row in tmp[layer].clickables.rows" class="upgRow"> <div v-for="row in tmp[layer].clickables.rows" class="upgRow">
<div v-for="col in tmp[layer].clickables.cols"><div v-if="layers[layer].clickables[row*10+col]!== undefined && tmp[layer].clickables[row*10+col].unlocked" class="upgAlign" v-bind:style="{'margin-left': '7px', 'margin-right': '7px', 'height': (data ? data : 'inherit'),}"> <div v-for="col in tmp[layer].clickables.cols"><div v-if="layers[layer].clickables[row*10+col]!== undefined && tmp[layer].clickables[row*10+col].unlocked" class="upgAlign" v-bind:style="{'margin-left': '7px', 'margin-right': '7px', 'height': (data ? data : 'inherit'),}">
<clickable :layer = "layer" :data = "row*10+col" :size = "data" v-bind:style="tmp[layer].componentStyles.clickable"></clickable> <clickable :layer = "layer" :data = "row*10+col" :size = "data" v-bind:style="tmp[layer].componentStyles.clickable"></clickable>
@ -257,6 +263,12 @@ function loadVue() {
` `
}) })
Vue.component('master-button', {
props: ['layer', 'data'],
template: `
<button v-if="tmp[layer].clickables && tmp[layer].clickables.masterButtonPress && !(layers[layer].clickables.showMasterButton !== undefined && tmp[layer].clickables.showMasterButton == false)" v-on:click="layers[layer].clickables.masterButtonPress()" v-bind:class="{ longUpg: true, can: player[layer].unlocked, locked: !player[layer].unlocked }">{{tmp[layer].clickables.masterButtonText ? tmp[layer].clickables.masterButtonText : "Click me!"}}</button><br>
`
})
// data = button size, in px // data = button size, in px
Vue.component('microtabs', { Vue.component('microtabs', {
@ -311,8 +323,8 @@ function loadVue() {
template: ` template: `
<div v-if="layers[layer].achievements && layers[layer].achievements[data]!== undefined && tmp[layer].achievements[data].unlocked" v-bind:class="{ [layer]: true, achievement: true, locked: !hasAchievement(layer, data), bought: hasAchievement(layer, data)}" <div v-if="layers[layer].achievements && layers[layer].achievements[data]!== undefined && tmp[layer].achievements[data].unlocked" v-bind:class="{ [layer]: true, achievement: true, locked: !hasAchievement(layer, data), bought: hasAchievement(layer, data)}"
v-bind:tooltip=" v-bind:tooltip="
hasAchievement(layer, data) ? (tmp[layer].achievements[data].doneTooltip ? tmp[layer].achievements[data].doneTooltip : 'You did it!') hasAchievement(layer, data) ? (tmp[layer].achievements[data].doneTooltip ? tmp[layer].achievements[data].doneTooltip : (tmp[layer].achievements[data].tooltip ? tmp[layer].achievements[data].tooltip : 'You did it!'))
: (tmp[layer].achievements[data].goalTooltip ? tmp[layer].achievements[data].goalTooltip : 'LOCKED') : (tmp[layer].achievements[data].goalTooltip ? tmp[layer].achievements[data].goalTooltip : (tmp[layer].achievements[data].tooltip ? tmp[layer].achievements[data].tooltip : 'LOCKED'))
" "
v-bind:style="[(!tmp[layer].achievements[data].unlocked) ? {'visibility': 'hidden'} : {}, tmp[layer].achievements[data].style,]"> v-bind:style="[(!tmp[layer].achievements[data].unlocked) ? {'visibility': 'hidden'} : {}, tmp[layer].achievements[data].style,]">