1
0
Fork 0
mirror of https://github.com/Acamaeda/The-Modding-Tree.git synced 2024-11-22 00:21:32 +00:00

Added Clickables

This commit is contained in:
Acamaeda 2020-10-11 16:16:36 -04:00
parent 61788c6bdd
commit dee1f93298
12 changed files with 326 additions and 122 deletions

View file

@ -25,7 +25,9 @@ plain number, and perform operations on them by calling functions. e.g, instead
- [Milestones](milestones.md): How to create milestones for a layer. - [Milestones](milestones.md): How to create milestones for a layer.
- [Challenges](challenges.md): How to create challenges for a layer. - [Challenges](challenges.md): How to create challenges for a layer.
- [Buyables](buyables.md): Create rebuyable upgrades for your layer (with the option to make them respec-able). - [Buyables](buyables.md): Create rebuyable upgrades for your layer (with the option to make them respec-able).
Can be used to make Enhancers or Space Buildings, but they're flexible enough to do anything. Can be used to make Enhancers or Space Buildings.
- [Clickables](clickables.md): A more generalized variant of buyables, for any kind of thing that is sometimes clickable.
Between these and Buyables, you can do just about anything.
- [Custom Tab Layouts](custom-tab-layouts.md): An optional way to give your tabs a different layout. - [Custom Tab Layouts](custom-tab-layouts.md): An optional way to give your tabs a different layout.
You can even create entirely new components to use. You can even create entirely new components to use.
- [Subtabs and Microtabs](subtabs-and-microtabs.md): Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs. - [Subtabs and Microtabs](subtabs-and-microtabs.md): Create subtabs for your tabs, as well as "microtab" components that you can put inside the tabs.

View file

@ -3,9 +3,8 @@
Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function, Buyables are usually things that can be bought multiple times with scaling costs. If you set a respec function,
the player can reset the purchases to get their currency back. the player can reset the purchases to get their currency back.
However, if you're creative, you can use them for basically anything. "canAfford()" is effectively "canClick()" and "buy()" is effectively "onClick()". The amount of a buyable owned is a Decimal.
You can get or set the amount of a buyable with getBuyableAmt(layer, id) and setBuyableAmt(layer, id, amt).
The amount of a buyable owned is a Decimal, and can be accessed with buyablesOwned(layer, id).
You can use buyableEffect(layer, id) to get the current effects of a buyable. You can use buyableEffect(layer, id) to get the current effects of a buyable.
Buyables should be formatted like this: Buyables should be formatted like this:
@ -36,7 +35,7 @@ Features:
- effect(): **optional**, A function that calculates and returns the current values of bonuses - effect(): **optional**, A function that calculates and returns the current values of bonuses
of this buyable. Can return a value or an object containing multiple values. 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 buyable after the title, likely
including the description, amount bought, cost, and current effect. Can use basic HTML. including the description, amount bought, cost, and current effect. Can use basic HTML.
- 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.

51
docs/clickables.md Normal file
View file

@ -0,0 +1,51 @@
# Clickables
Clickables are any kind of thing that you can click for an effect. They're a more generalized version of Buyables.
There are several differences between the two. One is that a buyable's saved data is its amount as a Decimal, while
Clickables store a "state" which can be a number or string, but not Decimal, array, or object).
Buyables have a number of extra features which you can see on their page.
Clickables also have a smaller default size.
You can get and set a clickable's state with getClickableState(layer, id) and setClickableState(layer, id, state).
You can use clickableEffect(layer, id) to get the current effects of a clickable.
Clickables should be formatted like this:
```js
clickables: {
rows: # of rows
cols: # of columns
masterButtonPress() // **optional** If this is present, an additional button will appear above the clickables.
// pressing it will call the function.
masterButtonText: "Press me!" // **optional** text to display on the Master Button
11: {
desc:() => "Blah",
etc
}
etc
}
```
Features:
- title: **optional**, displayed at the top in a larger font
It can also be a function that returns updating text.
- effect(): **optional**, A function that calculates and returns the current values of bonuses
of this clickable. Can return a value or an object containing multiple values.
- display(): A function returning everything that should be displayed on the clickable after the title, likely
changing based on its state. Can use basic HTML.
- unl(): A function returning a bool to determine if the clickable is visible or not.
- canClick(): A function returning a bool to determine if you can click the clickable.
- onClick(): A function that implements clicking one of the clickable.
- style: **Optional**, A CSS object, which affects this clickable.
- 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 clickable.

View file

@ -35,8 +35,8 @@ These are the existing components, but you can create more in v.js:
- 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.
- buyables: Display all of the buyables for this layer, as appropriate. The argument optional, and is the size of the - buyables, clickables: Display all of the buyables/clickables for this layer, as appropriate. The argument optional,
boxes in pixels. and is the size of the boxes in pixels.
- microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature. - microtabs: Display a set of subtabs for an area. The argument is the name of the set of microtabs in the "microtabs" feature.

View file

@ -6,9 +6,9 @@
<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/layerSupport.js"></script>
<script type="text/javascript" src="js/test.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/gametest.js"></script> <script type="text/javascript" src="js/game.js"></script>
<script type="text/javascript" src="js/utils.js"></script> <script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/v.js"></script> <script type="text/javascript" src="js/v.js"></script>
<script type="text/javascript" src="js/canvas.js"></script> <script type="text/javascript" src="js/canvas.js"></script>
@ -139,6 +139,7 @@
<div v-if="Array.isArray(layers[layer].midsection)"> <div v-if="Array.isArray(layers[layer].midsection)">
<column :layer="layer" :data="tmp[layer].midsection"></column> <column :layer="layer" :data="tmp[layer].midsection"></column>
</div> </div>
<clickables v-bind:style="tmp[layer].componentStyles['clickables']" :layer="layer"></clickables>
<buyables v-bind:style="tmp[layer].componentStyles.buyables" :layer="layer"></buyables> <buyables v-bind:style="tmp[layer].componentStyles.buyables" :layer="layer"></buyables>
<upgrades v-bind:style="tmp[layer].componentStyles['upgrades']" :layer="layer"></upgrades> <upgrades v-bind:style="tmp[layer].componentStyles['upgrades']" :layer="layer"></upgrades>
<challs v-bind:style="tmp[layer].componentStyles['challs']" :layer="layer"></challs> <challs v-bind:style="tmp[layer].componentStyles['challs']" :layer="layer"></challs>

View file

@ -27,7 +27,7 @@ function showPointGen(){
// Calculate points/sec! // Calculate points/sec!
function getPointGen() { function getPointGen() {
if(!hasUpg("p", 11)) if(!hasUpg("c", 11))
return new Decimal(0) return new Decimal(0)
let gain = new Decimal(1) let gain = new Decimal(1)
@ -164,6 +164,16 @@ function getStartBuyables(layer){
return data return data
} }
function getStartClickables(layer){
let data = {}
if (layers[layer].buyables) {
for (id in layers[layer].buyables)
if (!isNaN(id))
data[id] = ""
}
return data
}
function addPoints(layer, gain) { function addPoints(layer, gain) {
player[layer].points = player[layer].points.add(gain).max(0) player[layer].points = player[layer].points.add(gain).max(0)
if (player[layer].best) player[layer].best = player[layer].best.max(player[layer].points) if (player[layer].best) player[layer].best = player[layer].best.max(player[layer].points)
@ -226,116 +236,6 @@ function doReset(layer, force=false) {
updateTemp() updateTemp()
} }
function respecBuyables(layer) {
if (!layers[layer].buyables) return
if (!layers[layer].buyables.respec) return
if (!confirm("Are you sure you want to respec? This will force you to do a \"" + (layers[layer].name ? layers[layer].name : layer) + "\" reset as well!")) return
layers[layer].buyables.respec()
updateBuyableTemp(layer)
}
function canAffordUpg(layer, id) {
let upg = layers[layer].upgrades[id]
let cost = tmp[layer].upgrades[id].cost
return canAffordPurchase(layer, upg, cost)
}
function hasUpg(layer, id){
return (player[layer].upgrades.includes(toNumber(id)) || player[layer].upgrades.includes(id.toString()))
}
function hasMilestone(layer, id){
return (player[layer].milestones.includes(toNumber(id)) || player[layer].milestones.includes(id.toString()))
}
function hasChall(layer, id){
return (player[layer].challs.includes(toNumber(id)) || player[layer].challs.includes(id.toString()))
}
function buyablesOwned(layer, id){
return (player[layer].buyables[id])
}
function clickableState(layer, id){
return (player[layer].clickables[id])
}
function upgEffect(layer, id){
return (tmp[layer].upgrades[id].effect)
}
function challEffect(layer, id){
return (tmp[layer].challs[id].effect)
}
function buyableEffect(layer, id){
return (tmp[layer].buyables[id].effect)
}
function canAffordPurchase(layer, thing, cost) {
if (thing.currencyInternalName){
let name = thing.currencyInternalName
if (thing.currencyLayer){
let lr = thing.currencyLayer
return !(player[lr][name].lt(cost))
}
else {
return !(player[name].lt(cost))
}
}
else {
return !(player[layer].points.lt(cost))
}
}
function buyUpg(layer, id) {
if (!player[layer].unl) return
if (!layers[layer].upgrades[id].unl()) return
if (player[layer].upgrades.includes(id)) return
let upg = layers[layer].upgrades[id]
let cost = tmp[layer].upgrades[id].cost
if (upg.currencyInternalName){
let name = upg.currencyInternalName
if (upg.currencyLayer){
let lr = upg.currencyLayer
if (player[lr][name].lt(cost)) return
player[lr][name] = player[lr][name].sub(cost)
}
else {
if (player[name].lt(cost)) return
player[name] = player[name].sub(cost)
}
}
else {
if (player[layer].points.lt(cost)) return
player[layer].points = player[layer].points.sub(cost)
}
player[layer].upgrades.push(id);
if (upg.onPurchase != undefined)
upg.onPurchase()
}
function buyMaxBuyable(layer, id) {
if (!player[layer].unl) return
if (!tmp[layer].buyables[id].unl) return
if (!tmp[layer].buyables[id].canAfford) return
if (!layers[layer].buyables[id].buyMax) return
layers[layer].buyables[id].buyMax()
updateBuyableTemp(layer)
}
function buyBuyable(layer, id) {
if (!player[layer].unl) return
if (!tmp[layer].buyables[id].unl) return
if (!tmp[layer].buyables[id].canAfford) return
layers[layer].buyables[id].buy()
updateBuyableTemp(layer)
}
function resetRow(row) { function resetRow(row) {
if (prompt('Are you sure you want to reset this row? It is highly recommended that you wait until the end of your current run before doing this! Type "I WANT TO RESET THIS" to confirm')!="I WANT TO RESET THIS") return if (prompt('Are you sure you want to reset this row? It is highly recommended that you wait until the end of your current run before doing this! Type "I WANT TO RESET THIS" to confirm')!="I WANT TO RESET THIS") return
let pre_layers = ROW_LAYERS[row-1] let pre_layers = ROW_LAYERS[row-1]

View file

@ -266,6 +266,14 @@ function hasChall(layer, id){
return (player[layer].challs.includes(toNumber(id)) || player[layer].challs.includes(id.toString())) return (player[layer].challs.includes(toNumber(id)) || player[layer].challs.includes(id.toString()))
} }
function buyablesOwned(layer, id){
return (player[layer].buyables[id])
}
function clickableState(layer, id){
return (player[layer].clickables[id])
}
function upgEffect(layer, id){ function upgEffect(layer, id){
if (!layers[layer].upgrades) return {} if (!layers[layer].upgrades) return {}

View file

@ -73,6 +73,18 @@ function updateLayers(){
} }
} }
if (layers[layer].clickables){
layers[layer].clickables.layer = layer
for (thing in layers[layer].clickables){
if (!isNaN(thing)){
layers[layer].clickables[thing].id = thing
layers[layer].clickables[thing].layer = layer
if (layers[layer].clickables[thing].unl === undefined)
layers[layer].clickables[thing].unl = true
}
}
}
if(!layers[layer].componentStyles) layers[layer].componentStyles = {} if(!layers[layer].componentStyles) layers[layer].componentStyles = {}
if(layers[layer].symbol === undefined) layers[layer].symbol = layer.charAt(0).toUpperCase() + layer.slice(1) if(layers[layer].symbol === undefined) layers[layer].symbol = layer.charAt(0).toUpperCase() + layer.slice(1)

View file

@ -295,12 +295,13 @@ addLayer("c", {
resetDesc: "Melt your points into ", resetDesc: "Melt your points into ",
}) })
// This layer is mostly minimal but it uses a custom prestige type // This layer is mostly minimal but it uses a custom prestige type and a clickable
addLayer("f", { addLayer("f", {
startData() { return { startData() { return {
unl: false, unl: false,
points: new Decimal(0), points: new Decimal(0),
boop: false, boop: false,
clickables: {[11]: "Start"} // Optional default Clickable state
}}, }},
color:() => "#FE0102", color:() => "#FE0102",
requires() {return new Decimal(10)}, requires() {return new Decimal(10)},
@ -345,6 +346,66 @@ addLayer("f", {
canReset() { canReset() {
return tmp[this.layer].baseAmount.gte(tmp[this.layer].nextAt) return tmp[this.layer].baseAmount.gte(tmp[this.layer].nextAt)
}, },
// This is also non minimal, a Clickable!
clickables: {
rows: 1,
cols: 1,
masterButtonPress() { // Optional, reset things and give back your currency. Having this function makes a respec button appear
if (getClickableState(this.layer, 11) == "Borkened...")
player[this.layer].clickables[11] = "Start"
},
masterButtonText() {return (getClickableState(this.layer, 11) == "Borkened...") ? "Fix the clickable!" : "Does nothing"}, // Text on Respec button, optional
11: {
title:() => "Clicky clicky!", // Optional, displayed at the top in a larger font
display() { // Everything else displayed in the buyable button after the title
let data = getClickableState(this.layer, this.id)
return "Current state:<br>" + data
},
unl() { return player[this.layer].unl },
canClick() {
return getClickableState(this.layer, this.id) !== "Borkened..."},
onClick() {
switch(getClickableState(this.layer, this.id)){
case "Start":
player[this.layer].clickables[this.id] = "A new state!"
break;
case "A new state!":
player[this.layer].clickables[this.id] = "Keep going!"
break;
case "Keep going!":
player[this.layer].clickables[this.id] = "Maybe that's a bit too far..."
break;
case "Maybe that's a bit too far...":
player[this.layer].clickables[this.id] = "Borkened..."
break;
default:
player[this.layer].clickables[this.id] = "Start"
break;
}
},
style() {
switch(getClickableState(this.layer, this.id)){
case "Start":
return {'background-color': 'green'}
break;
case "A new state!":
return {'background-color': 'yellow'}
break;
case "Keep going!":
return {'background-color': 'orange'}
break;
case "Maybe that's a bit too far...":
return {'background-color': 'red'}
break;
default:
return {}
break;
}},
},
},
}, },
) )

View file

@ -3,7 +3,7 @@ var tmp = {}
// Tmp will not call these // Tmp will not call these
var activeFunctions = [ var activeFunctions = [
"startData", "onPrestige", "doReset", "update", "automate", "startData", "onPrestige", "doReset", "update", "automate",
"buy", "buyMax", "respec", "onComplete", "onPurchase", "onPress" "buy", "buyMax", "respec", "onComplete", "onPurchase", "onPress", "onClick", "masterButtonPress"
] ]
function setupTemp() { function setupTemp() {
@ -89,3 +89,8 @@ function updateBuyableTemp(layer)
{ {
updateTempData(layers[layer].buyables, tmp[layer].buyables) updateTempData(layers[layer].buyables, tmp[layer].buyables)
} }
function updateClickableTemp(layer)
{
updateTempData(layers[layer].clickables, tmp[layer].clickables)
}

View file

@ -89,6 +89,7 @@ function getStartPlayer() {
for (layer in layers){ for (layer in layers){
playerdata[layer] = layers[layer].startData() playerdata[layer] = layers[layer].startData()
playerdata[layer].buyables = getStartBuyables(layer) playerdata[layer].buyables = getStartBuyables(layer)
if(playerdata[layer].clickables == undefined) playerdata[layer].clickables = getStartClickables(layer)
playerdata[layer].spentOnBuyables = new Decimal(0) playerdata[layer].spentOnBuyables = new Decimal(0)
playerdata[layer].upgrades = [] playerdata[layer].upgrades = []
playerdata[layer].milestones = [] playerdata[layer].milestones = []
@ -310,6 +311,137 @@ function milestoneShown(layer, id) {
return false; return false;
} }
// ************ Big Feature related ************
function respecBuyables(layer) {
if (!layers[layer].buyables) return
if (!layers[layer].buyables.respec) return
if (!confirm("Are you sure you want to respec? This will force you to do a \"" + (layers[layer].name ? layers[layer].name : layer) + "\" reset as well!")) return
layers[layer].buyables.respec()
updateBuyableTemp(layer)
}
function canAffordUpg(layer, id) {
let upg = layers[layer].upgrades[id]
let cost = tmp[layer].upgrades[id].cost
return canAffordPurchase(layer, upg, cost)
}
function hasUpg(layer, id){
return (player[layer].upgrades.includes(toNumber(id)) || player[layer].upgrades.includes(id.toString()))
}
function hasMilestone(layer, id){
return (player[layer].milestones.includes(toNumber(id)) || player[layer].milestones.includes(id.toString()))
}
function hasChall(layer, id){
return (player[layer].challs.includes(toNumber(id)) || player[layer].challs.includes(id.toString()))
}
function getBuyableAmt(layer, id){
return (player[layer].buyables[id])
}
function setBuyableAmt(layer, id, amt){
player[layer].buyables[id] = amt
}
function getClickableState(layer, id){
return (player[layer].clickables[id])
}
function setClickableState(layer, id, state){
player[layer].clickables[id] = state
}
function upgEffect(layer, id){
return (tmp[layer].upgrades[id].effect)
}
function challEffect(layer, id){
return (tmp[layer].challs[id].effect)
}
function buyableEffect(layer, id){
return (tmp[layer].buyables[id].effect)
}
function canAffordPurchase(layer, thing, cost) {
if (thing.currencyInternalName){
let name = thing.currencyInternalName
if (thing.currencyLayer){
let lr = thing.currencyLayer
return !(player[lr][name].lt(cost))
}
else {
return !(player[name].lt(cost))
}
}
else {
return !(player[layer].points.lt(cost))
}
}
function buyUpg(layer, id) {
if (!player[layer].unl) return
if (!layers[layer].upgrades[id].unl()) return
if (player[layer].upgrades.includes(id)) return
let upg = layers[layer].upgrades[id]
let cost = tmp[layer].upgrades[id].cost
if (upg.currencyInternalName){
let name = upg.currencyInternalName
if (upg.currencyLayer){
let lr = upg.currencyLayer
if (player[lr][name].lt(cost)) return
player[lr][name] = player[lr][name].sub(cost)
}
else {
if (player[name].lt(cost)) return
player[name] = player[name].sub(cost)
}
}
else {
if (player[layer].points.lt(cost)) return
player[layer].points = player[layer].points.sub(cost)
}
player[layer].upgrades.push(id);
if (upg.onPurchase != undefined)
upg.onPurchase()
}
function buyMaxBuyable(layer, id) {
if (!player[layer].unl) return
if (!tmp[layer].buyables[id].unl) return
if (!tmp[layer].buyables[id].canAfford) return
if (!layers[layer].buyables[id].buyMax) return
layers[layer].buyables[id].buyMax()
updateBuyableTemp(layer)
}
function buyBuyable(layer, id) {
if (!player[layer].unl) return
if (!tmp[layer].buyables[id].unl) return
if (!tmp[layer].buyables[id].canAfford) return
layers[layer].buyables[id].buy()
updateBuyableTemp(layer)
}
function clickClickable(layer, id) {
if (!player[layer].unl) return
if (!tmp[layer].clickables[id].unl) return
if (!tmp[layer].clickables[id].canClick) return
layers[layer].clickables[id].onClick()
updateClickableTemp(layer)
}
// ************ Misc ************ // ************ Misc ************
var onTreeTab = true var onTreeTab = true

33
js/v.js
View file

@ -218,6 +218,39 @@ function loadVue() {
` `
}) })
// data = button size, in px
Vue.component('clickables', {
props: ['layer', 'data'],
template: `
<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].unl, locked: !player[layer].unl }">{{tmp[layer].clickables.masterButtonText ? tmp[layer].clickables.masterButtonText : "Click me!"}}</button><br>
<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].unl" 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>
</div></div>
<br>
</div>
</div>
`
})
// data = id of clickable
Vue.component('clickable', {
props: ['layer', 'data', 'size'],
template: `
<button
v-if="layers[layer].clickables && layers[layer].clickables[data]!== undefined && tmp[layer].clickables[data].unl"
v-bind:class="{ upg: true, can: tmp[layer].clickables[data].canClick, locked: !tmp[layer].clickables[data].canClick}"
v-bind:style="[tmp[layer].clickables[data].canClick ? {'background-color': tmp[layer].color} : {}, size ? {'height': size, 'width': size} : {}, tmp[layer].clickables[data].style]"
v-on:click="clickClickable(layer, data)">
<span v-if= "tmp[layer].clickables[data].title"><h2 v-html="tmp[layer].clickables[data].title"></h2><br></span>
<span v-bind:style="{'white-space': 'pre-line'}" v-html="tmp[layer].clickables[data].display"></span>
</button>
`
})
// data = button size, in px // data = button size, in px
Vue.component('microtabs', { Vue.component('microtabs', {
props: ['layer', 'data'], props: ['layer', 'data'],