1
0
Fork 0
mirror of https://github.com/Acamaeda/The-Modding-Tree.git synced 2025-02-16 09:41:41 +00:00

Merge branch 'master' into 2.4-dev

This commit is contained in:
Harley White 2021-05-11 00:45:47 -04:00
commit 583a9898e3
22 changed files with 263 additions and 140 deletions

View file

@ -1,6 +1,6 @@
# The-Modding-Tree
A modified version of The Prestige Tree that is much easier to mod. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.
An incremental game engine based on The Prestige Tree. It still requires programming knowledge, but it's mostly pretty easy things and copy/pasting.
[Look here for a tutorial on getting started with modding with TMT](docs/getting-started.md)

View file

@ -1,6 +1,32 @@
# The Modding Tree changelog:
# v2.5: Dreams Really Do Come True - 5/7/21
# v2.5.4 - 5/10/21
- Added a setting to always use single-tab mode.
- Added directMult, which multiplies prestige gain after exponents and softcaps. It actually multiplies gain for static layers.
- Added onEnter and onExit for challenges.
- Improved displaying numbers between 0.0001 and 0.1.
- Added documentation on how gainMult/Exp work for static layers.
- Fixed a visual issue on mobile, thanks to thepaperpilot.
- Improved documentation in general.
# v2.5.3 - 5/8/21
- Improved performance of tab formats and bars.
- Respec confirmation settings are now kept on resets.
- Improved compatibility with older browsers.
- Fixed missing pixel on vertical bars.
# v2.5.2.1 - 5/7/21
- Fixed microtabs making layers highlight incorrectly.
# v2.5.2 - 5/7/21
- Added glowColor for subtabs.
- Improved the display for extremely small numbers.
- Fixed issues in the buyable docs.
# v2.5.1 - 5/7/21
- Fixed dynamic things in tabFormat not updating.
## v2.5: Dreams Really Do Come True - 5/7/21
- Optimizations, hopefully a significant amount.
- Added OOM/s point gen display at high values (thanks to Ducdat!)
- Only one tab will display if the window is not wide enough (also thanks to Ducdat!)
@ -14,7 +40,8 @@
- Locked (not yet visible) milestones no longer take up space. Also fixed hidden milestones taking a tiny bit of space.
- Re-centered respec buttons.
- Force-displayed tooltips are not hidden by resets.
- Added formatting support for very small numbers. Disabled in most places by default because rounding errors can cause issues. Access it with formatSmall, or enable it globally by adding "allowSmall: true" to modInfo.
- Added formatting support for very small numbers. Disabled in most places by default because rounding errors might cause issues. Access it with formatSmall, or enable it globally by adding "allowSmall: true" to modInfo.
# v2.4.1 - 4/29/21
- A number of minor fixes, many thanks to thepaperpilot.

View file

@ -1,10 +1,10 @@
# 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 [layerSupport.js](/js/layerSupport.js), or declare it in another file and register it by calling `addLayer(layername, layerdata)`. There is an example layer registration in [layers.js](/js/layers.js) showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.
Making a game in The Modding Tree mostly involves defining parameters or functions on objects. If you aren't following the [getting started guide](getting-started.md), you should start by [setting up your basic mod info](main-mod-info.md) in [mod.js](/js/mod.js). It's important to set a mod id to ensure saving works properly.
The first thing you need to do is fill out the modInfo object at the top of [mod.js](/js/mod.js) to set your mod's name, ID (a string), and other information. A unique modId will prevent your mod's saves from conflicting with other mods. Note that changing this after people have started playing will reset their saves.
Beyond that, the main way to add content is through creating layers, often in [layers.js](/js/layers.js). You can add new layers by calling `addLayer(layername, layerdata)`. There is an example of a basic layer in [layers.js](/js/layers.js) showing the recommended method. It is just an example and can be freely deleted. You can also use it as a reference or a base for your own layers.
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, for example to add new Vue components in [v.js](/js/v.js).
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, for example to add new Vue components in [components.js](/js/components.js).
The Modding Tree uses [break\_eternity.js](https://github.com/Patashu/break_eternity.js) to store large values. This means that many numbers are `Decimal` objects, and must be treated differently. For example, you have to use `new Decimal(x)` to create a `Decimal` value instead of a plain number, and perform operations on them by calling functions. e.g, instead of `x = x + y`, use `x = x.add(y)`. Keep in mind this also applies to comparison operators, which should be replaced with calling the `.gt`, `.gte`, `.lt`, `.lte`, `.eq`, and `.neq` functions. See the [break\_eternity.js](https://github.com/Patashu/break_eternity.js) docs for more details on working with `Decimal` values.

View file

@ -1,6 +1,6 @@
# Achievements
Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit. Currently they are pretty basic, but additional features will be added later to help.
Achievements are awarded to the player when they meet a certain goal, and optionally give some benefit.
You can make global achievements by putting them in a side layer by making its row equal to "side" instead of a number.

View file

@ -29,6 +29,10 @@ addLayer("p", {
return new Decimal(1)
},
layerShown() { return true } // Returns a bool for if this layer's node should be visible in the tree.
layerShown() { return true }, // Returns a bool for if this layer's node should be visible in the tree.
upgrades: {
// Look in the upgrades docs to see what goes here!
},
})
```

View file

@ -15,12 +15,12 @@ Buyables should be formatted like this:
```js
buyables: {
11: {
cost(x) { return new Decimal(1).mul(x || getBuyableAmt(this.layer, this.id)) },
cost(x) { return new Decimal(1).mul(x) },
display() { return "Blah" },
canAfford() { return player[this.layer].points.gte(this.cost()) },
buy() {
player[this.layer].points = player[this.layer].points.sub(this.cost())
setBuyableAmount(this.layer, this.id, getBuyableAmt(this.layer, this.id).add(1))
setBuyableAmount(this.layer, this.id, getBuyableAmount(this.layer, this.id).add(1))
},
etc
},
@ -68,7 +68,7 @@ Including a `sellOne` or `sellAll` function will cause an additional button to a
To add a respec button, or something similar, add the respecBuyables function to the main buyables object (not individual buyables).
You can use these features along with it:
- respecBuyables(): **optional**. This is called when the button is pressed (after a toggleable confirmation message).
- respec(): **optional**. This is called when the button is pressed (after a toggleable confirmation message).
- respecText: **optional**. Text to display on the respec Button.

View file

@ -15,7 +15,7 @@ challenges: {
11: {
name: "Ouch",
challengeDescription: "description of ouchie",
goal: new Decimal(100),
canComplete: function() {return player.points.gte(100)},
etc
},
etc
@ -48,6 +48,10 @@ Individual Challenges can have these features:
- onComplete() - **optional**. this function will be called when the challenge is completed when previously incomplete.
- onEnter() - **optional**. this function will be called when entering the challenge
- onExit() - **optional**. this function will be called when exiting the challenge in any way
- countsAs: **optional**. If a challenge combines the effects of other challenges in this layer, you can use this. An array of challenge ids. The player is effectively in all of those challenges when in the current one.
- completionLimit: **optional**. the amount of times you can complete this challenge. Default is 1 completion.

View file

@ -1,6 +1,6 @@
# Custom tab layouts
Note: If you are using subtabs, `tabFormat` is used differently, but you still use the same format within each subtabs. [See here for more on subtabs](subtabs-and-microtabs.md).
Note: If you are using subtabs, `tabFormat` is used differently, but the same format is used for defining their layouts. [See here for more on subtabs](subtabs-and-microtabs.md).
Custom tab layouts can be used to do basically anything in a tab window, especially combined with the "style" layer feature. The `tabFormat` feature is an array of things, like this:

View file

@ -101,7 +101,10 @@ You can make almost any value dynamic by using a function in its place, includin
- roundUpCost: **optional**. a bool, which is true if the resource cost needs to be rounded up. (use if the base resource is a "static" currency.)
- gainMult(), gainExp(): **optional**. Functions that calculate the multiplier and exponent on resource gain from upgrades and boosts and such. Plug in any bonuses here.
- gainMult(), gainExp(): **optional**. For normal layers, these functions calculate the multiplier and exponent on resource gain from upgrades and boosts and such. Plug in most bonuses here.
For static layers, they instead divide and root the cost of the resource.
- directMult(): **optional**. Directly multiplies the resource gain, after exponents and softcaps. For static layers, actually multiplies resource gain instead of reducing the cost.
- softcap, softcapPower: **optional**. For normal layers, gain beyond [softcap] points is put to the [softcapPower]th power
Default for softcap is e1e7, and for power is 0.5.

View file

@ -1,12 +1,13 @@
# mod.js
All of the non-layer code and data that you're likely to edit is here in [mod.js](/js/mod.js)! Everything in [mod.js](/js/mod.js) will not be altered by updates, besides the addition of new things.
Most of the non-layer code and data that you're likely to edit is here in [mod.js](/js/mod.js).
Everything in [mod.js](/js/mod.js) will not be altered by updates, besides the addition of new things.
Here's a breakdown of what's in it:
- modInfo is where most of the basic configuration for the mod is. It contains:
- name: The name of your mod. (a string)
- id: The id for your mod, a unique string that is used to determine savefile location. Setting it is important!
- id: The id for your mod, a unique string that is used to determine savefile location. Be sure to set it when you start making a mod, and don't change it later because it will erase all saves.
- author: The name of the author, displayed in the info tab.
- pointsName: This changes what is displayed instead of "points" for the main currency. (It does not affect it in the code.)
- discordName, discordLink: If you have a Discord server or other discussion place, you can add a link to it.
@ -25,7 +26,7 @@ Here's a breakdown of what's in it:
- changelog is the HTML displayed in the changelog tab.
- doNotCallTheseFunctionsEveryTick is very important. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.
- doNotCallTheseFunctionsEveryTick is very important, if you are adding non-standard functions. TMT calls every function anywhere in "layers" every tick to store the result, unless specifically told not to. Functions that have are used to do an action need to be identified. "Official" functions (those in the documentation) are all fine, but if you make any new ones, add their names to this array.
```js
// (The ones here are examples, all official functions are already taken care of)
@ -53,4 +54,6 @@ function addedPlayerData() { return {
Less important things beyond this point!
- maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).
- maxTickLength(): Returns the maximum tick length, in milliseconds. Only really useful if you have something that reduces over time, which long ticks mess up (usually a challenge).
- fixOldSave(): Can be used to modify a save file when loading into a new version of the game. Use this to undo inflation, never forcibly hard reset your players.

View file

@ -52,5 +52,8 @@ Normal subtabs and microtab subtabs both use the same features:
- shouldNotify()/prestigeNotify(): **optional**, if true, the tab button will be highlighted to notify the player that there is something there.
- glowColor: **optional**, specifies the color that the subtab glows. If this subtab is causing the main layer to node glow
(and it would't otherwise) the node also glows this color. Is NOT overridden by embedding a layer.
- embedLayer: **SIGNIFICANT**, the id of another layer. If you have this, it will override "content", "style" and "shouldNotify",
instead displaying the entire layer in the subtab.

View file

@ -95,7 +95,10 @@ addLayer("c", {
rewardDisplay() { return format(this.rewardEffect())+"x" },
countsAs: [12, 21], // Use this for if a challenge includes the effects of other challenges. Being in this challenge "counts as" being in these.
rewardDescription: "Says hi",
onComplete() {console.log("hiii")} // Called when you complete the challenge
onComplete() {console.log("hiii")}, // Called when you successfully complete the challenge
onEnter() {console.log("So challenging")},
onExit() {console.log("Sweet freedom!")},
},
},
upgrades: {
@ -221,6 +224,8 @@ addLayer("c", {
content: ["upgrades", ["display-text", function() {return "confirmed"}]]
},
second: {
embedLayer: "f",
content: [["upgrade", 11],
["row", [["upgrade", 11], "blank", "blank", ["upgrade", 11],]],
@ -302,6 +307,8 @@ addLayer("c", {
function() {return 'I have ' + format(player.points) + ' ' + player.c.thingy + ' points!'},
{"color": "red", "font-size": "32px", "font-family": "Comic Sans MS"}],
"h-line", "milestones", "blank", "upgrades", "challenges"],
glowColor: "blue",
},
thingies: {
prestigeNotify: true,
@ -391,7 +398,8 @@ addLayer("f", {
exponent: 0.5,
base: 3,
roundUpCost: true,
canBuyMax() {return hasAchievement('a', 13)},
canBuyMax() {return false},
//directMult() {return new Decimal(player.c.otherThingy)},
row: 1,
layerShown() {return true},

View file

@ -11,7 +11,7 @@ let modInfo = {
// Set your version in num and name
let VERSION = {
num: "2.5",
num: "2.5.4",
name: "Dreams Really Do Come True",
}

View file

@ -377,15 +377,15 @@ function loadVue() {
Vue.component('bar', {
props: ['layer', 'data'],
computed: {
style() {return constructBarStyle(layer, data)}
style() {return constructBarStyle(this.layer, this.data)}
},
template: `
<div v-if="tmp[layer].bars && tmp[layer].bars[data].unlocked" v-bind:style="{'position': 'relative'}"><div v-bind:style="[tmp[layer].bars[data].style, tmp[layer].bars[data].dims, {'display': 'table'}]">
<div class = "overlayTextContainer barBorder" v-bind:style="[tmp[layer].bars[data].borderStyle, tmp[layer].bars[data].dims]">
<div v-if="tmp[layer].bars && tmp[layer].bars[data].unlocked" v-bind:style="{'position': 'relative'}"><div v-bind:style="[tmp[layer].bars[data].style, style.dims, {'display': 'table'}]">
<div class = "overlayTextContainer barBorder" v-bind:style="[tmp[layer].bars[data].borderStyle, style.dims]">
<span class = "overlayText" v-bind:style="[tmp[layer].bars[data].style, tmp[layer].bars[data].textStyle]" v-html="run(layers[layer].bars[data].display, layers[layer].bars[data])"></span>
</div>
<div class ="barBG barBorder" v-bind:style="[tmp[layer].bars[data].style, tmp[layer].bars[data].baseStyle, tmp[layer].bars[data].borderStyle, tmp[layer].bars[data].dims]">
<div class ="fill" v-bind:style="[tmp[layer].bars[data].style, tmp[layer].bars[data].fillStyle, tmp[layer].bars[data].fillDims]"></div>
<div class ="barBG barBorder" v-bind:style="[tmp[layer].bars[data].style, tmp[layer].bars[data].baseStyle, tmp[layer].bars[data].borderStyle, style.dims]">
<div class ="fill" v-bind:style="[tmp[layer].bars[data].style, tmp[layer].bars[data].fillStyle, style.fillDims]"></div>
</div>
</div></div>
`
@ -513,6 +513,7 @@ function loadVue() {
subtabResetNotify,
challengeStyle,
challengeButtonText,
constructBarStyle,
VERSION,
LAYERS,
hotkeys,

View file

@ -5,7 +5,7 @@ var scrolled = false;
// Don't change this
const TMT_VERSION = {
tmtNum: "2.5",
tmtNum: "2.5.4",
tmtName: "Dreams Really Do Come True"
}
@ -18,20 +18,22 @@ function getResetGain(layer, useType = null) {
}
if(tmp[layer].type == "none")
return new Decimal (0)
if (tmp[layer].gainExp.eq(0)) return new Decimal(0)
if (tmp[layer].gainExp.eq(0)) return decimalZero
if (type=="static") {
if ((!tmp[layer].canBuyMax) || tmp[layer].baseAmount.lt(tmp[layer].requires)) return new Decimal(1)
if ((!tmp[layer].canBuyMax) || tmp[layer].baseAmount.lt(tmp[layer].requires)) return decimalOne
let gain = tmp[layer].baseAmount.div(tmp[layer].requires).div(tmp[layer].gainMult).max(1).log(tmp[layer].base).times(tmp[layer].gainExp).pow(Decimal.pow(tmp[layer].exponent, -1))
gain = gain.times(tmp[layer].directMult)
return gain.floor().sub(player[layer].points).add(1).max(1);
} else if (type=="normal"){
if (tmp[layer].baseAmount.lt(tmp[layer].requires)) return new Decimal(0)
if (tmp[layer].baseAmount.lt(tmp[layer].requires)) return decimalZero
let gain = tmp[layer].baseAmount.div(tmp[layer].requires).pow(tmp[layer].exponent).times(tmp[layer].gainMult).pow(tmp[layer].gainExp)
if (gain.gte(tmp[layer].softcap)) gain = gain.pow(tmp[layer].softcapPower).times(tmp[layer].softcap.pow(decimalOne.sub(tmp[layer].softcapPower)))
gain = gain.times(tmp[layer].directMult)
return gain.floor().max(0);
} else if (type=="custom"){
return layers[layer].getResetGain()
} else {
return new Decimal(0)
return decimalZero
}
}
@ -52,13 +54,13 @@ function getNextAt(layer, canMax=false, useType = null) {
if (type=="static")
{
if (!tmp[layer].canBuyMax) canMax = false
let amt = player[layer].points.plus((canMax&&tmp[layer].baseAmount.gte(tmp[layer].nextAt))?tmp[layer].resetGain:0)
let amt = player[layer].points.plus((canMax&&tmp[layer].baseAmount.gte(tmp[layer].nextAt))?tmp[layer].resetGain:0).div(tmp[layer].directMult)
let extraCost = Decimal.pow(tmp[layer].base, amt.pow(tmp[layer].exponent).div(tmp[layer].gainExp)).times(tmp[layer].gainMult)
let cost = extraCost.times(tmp[layer].requires).max(tmp[layer].requires)
if (tmp[layer].roundUpCost) cost = cost.ceil()
return cost;
} else if (type=="normal"){
let next = tmp[layer].resetGain.add(1)
let next = tmp[layer].resetGain.add(1).div(tmp[layer].directMult)
if (next.gte(tmp[layer].softcap)) next = next.div(tmp[layer].softcap.pow(decimalOne.sub(tmp[layer].softcapPower))).pow(decimalOne.div(tmp[layer].softcapPower))
next = next.root(tmp[layer].gainExp).div(tmp[layer].gainMult).root(tmp[layer].exponent).times(tmp[layer].requires).max(tmp[layer].requires)
if (tmp[layer].roundUpCost) next = next.ceil()
@ -66,7 +68,7 @@ function getNextAt(layer, canMax=false, useType = null) {
} else if (type=="custom"){
return layers[layer].getNextAt(canMax)
} else {
return new Decimal(0)
return decimalZero
}}
function softcap(value, cap, power = 0.5) {
@ -88,21 +90,28 @@ function shouldNotify(layer){
return true
}
if (tmp[layer].shouldNotify)
return true
if (isPlainObject(tmp[layer].tabFormat)) {
for (subtab in tmp[layer].tabFormat){
if (subtabShouldNotify(layer, 'mainTabs', subtab))
if (subtabShouldNotify(layer, 'mainTabs', subtab)) {
tmp[layer].trueGlowColor = tmp[layer].tabFormat[subtab].glowColor
return true
}
}
}
for (family in tmp[layer].microtabs) {
for (subtab in tmp[layer].microtabs[family]){
if (subtabShouldNotify(layer, family, subtab))
if (subtabShouldNotify(layer, family, subtab)) {
tmp[layer].trueGlowColor = tmp[layer].microtabs[family][subtab].glowColor
return true
}
}
}
return tmp[layer].shouldNotify
return false
}
@ -131,7 +140,7 @@ function rowReset(row, layer) {
}
function layerDataReset(layer, keep = []) {
let storedData = {unlocked: player[layer].unlocked, forceTooltip: player[layer].forceTooltip} // Always keep these
let storedData = {unlocked: player[layer].unlocked, forceTooltip: player[layer].forceTooltip, noRespecConfirm: player[layer].noRespecConfirm} // Always keep these
for (thing in keep) {
if (player[layer][keep[thing]] !== undefined)
@ -158,7 +167,7 @@ function layerDataReset(layer, keep = []) {
function resetBuyables(layer){
if (layers[layer].buyables)
player[layer].buyables = getStartBuyables(layer)
player[layer].spentOnBuyables = new Decimal(0)
player[layer].spentOnBuyables = decimalZero
}
@ -206,7 +215,7 @@ function doReset(layer, force=false) {
}
}
tmp[layer].baseAmount = new Decimal(0) // quick fix
tmp[layer].baseAmount = decimalZero // quick fix
}
if (tmp[layer].resetsNothing) return
@ -217,7 +226,7 @@ function doReset(layer, force=false) {
}
prevOnReset = {...player} //Deep Copy
player.points = (row == 0 ? new Decimal(0) : getStartPoints())
player.points = (row == 0 ? decimalZero : getStartPoints())
for (let x = row; x >= 0; x--) rowReset(x, layer)
rowReset("side", layer)
@ -255,8 +264,10 @@ function startChallenge(layer, x) {
enter = true
}
doReset(layer, true)
if(enter) player[layer].activeChallenge = x
if(enter) {
player[layer].activeChallenge = x
run(layers[layer].challenges[x].onEnter, layers[layer].challenges[x])
}
updateChallengeTemp(layer)
}
@ -292,6 +303,7 @@ function completeChallenge(layer, x) {
let completions = canCompleteChallenge(layer, x)
if (!completions){
player[layer].activeChallenge = null
run(layers[layer].challenges[x].onExit, layers[layer].challenges[x])
return
}
if (player[layer].challenges[x] < tmp[layer].challenges[x].completionLimit) {
@ -301,6 +313,7 @@ function completeChallenge(layer, x) {
if (layers[layer].challenges[x].onComplete) run(layers[layer].challenges[x].onComplete, layers[layer].challenges[x])
}
player[layer].activeChallenge = null
run(layers[layer].challenges[x].onExit, layers[layer].challenges[x])
updateChallengeTemp(layer)
}
@ -333,7 +346,7 @@ function gameLoop(diff) {
addTime(diff)
player.points = player.points.add(tmp.pointGen.times(diff)).max(0)
for (x = 0; x <= maxRow; x++){
for (let x = 0; x <= maxRow; x++){
for (item in TREE_LAYERS[x]) {
let layer = TREE_LAYERS[x][item]
player[layer].resetTime += diff
@ -351,7 +364,7 @@ function gameLoop(diff) {
}
}
for (x = maxRow; x >= 0; x--){
for (let x = maxRow; x >= 0; x--){
for (item in TREE_LAYERS[x]) {
let layer = TREE_LAYERS[x][item]
if (tmp[layer].autoPrestige && tmp[layer].canReset) doReset(layer);
@ -411,6 +424,7 @@ var interval = setInterval(function() {
updateTemp();
updateOomps(diff);
updateWidth()
updateTabFormats()
gameLoop(diff)
fixNaNs()
adjustPopupTime(0.05)

View file

@ -18,8 +18,8 @@ function constructNodeStyle(layer){
style.push({'background-color': tmp[layer].color})
if (tmp[layer].image !== undefined)
style.push({'background-image': 'url("' + tmp[layer].image + '")'})
if(tmp[layer].glowColor !== undefined && tmp[layer].notify && player[layer].unlocked)
style.push({'box-shadow': 'var(--hqProperty2a), 0 0 20px ' + tmp[layer].glowColor})
if(tmp[layer].notify && player[layer].unlocked)
style.push({'box-shadow': 'var(--hqProperty2a), 0 0 20px ' + tmp[layer].trueGlowColor})
style.push(tmp[layer].nodeStyle)
return style
}
@ -53,10 +53,7 @@ function achievementStyle(layer, id){
function updateWidth() {
var screenWidth = window.innerWidth
var splitScreen = screenWidth >= 1024
if (player.splitMode === "disabled") splitScreen = false
if (player.splitMode === "enabled") splitScreen = true
if (player.forceOneTab) splitScreen = false
tmp.other.screenWidth = screenWidth
tmp.other.splitScreen = splitScreen
tmp.other.lastPoints = player.points
@ -85,4 +82,110 @@ function updateOomps(diff)
}
}
}
function constructBarStyle(layer, id) {
let bar = tmp[layer].bars[id]
let style = {}
if (bar.progress instanceof Decimal)
bar.progress = bar.progress.toNumber()
bar.progress = (1 -Math.min(Math.max(bar.progress, 0), 1)) * 100
style.dims = {'width': bar.width + "px", 'height': bar.height + "px"}
let dir = bar.direction
style.fillDims = {'width': (bar.width + 0.5) + "px", 'height': (bar.height + 0.5) + "px"}
switch(bar.direction) {
case UP:
style.fillDims['clip-path'] = 'inset(' + bar.progress + '% 0% 0% 0%)'
style.fillDims.width = bar.width + 1 + 'px'
break;
case DOWN:
style.fillDims['clip-path'] = 'inset(0% 0% ' + bar.progress + '% 0%)'
style.fillDims.width = bar.width + 1 + 'px'
break;
case RIGHT:
style.fillDims['clip-path'] = 'inset(0% ' + bar.progress + '% 0% 0%)'
break;
case LEFT:
style.fillDims['clip-path'] = 'inset(0% 0% 0% ' + bar.progress + '%)'
break;
case DEFAULT:
style.fillDims['clip-path'] = 'inset(0% 50% 0% 0%)'
}
return style
}
function constructTabFormat(layer, id, family){
let tabTemp, tabLayer, tabFunc, location, key
if (id === undefined){
tabTemp = tmp[layer].tabFormat
tabLayer = layers[layer].tabFormat
tabFunc = funcs[layer].tabFormat
location = tmp[layer]
key = "tabFormat"
}
else if (family === undefined) {
tabTemp = tmp[layer].tabFormat[id].content
tabLayer = layers[layer].tabFormat[id].content
tabFunc = funcs[layer].tabFormat[id].content
location = tmp[layer].tabFormat[id]
key = "content"
}
else {
tabTemp = tmp[layer].microtabs[family][id].content
tabLayer = layers[layer].microtabs[family][id].content
tabFunc = funcs[layer].microtabs[family][id].content
location = tmp[layer].microtabs[family][id]
key = "tabFormat"
}
if (isFunction(tabLayer)) {
let bound = tabLayer.bind(layers[layer])
Vue.set(tabTemp, key, bound())
}
updateTempData(tabLayer, tabTemp, tabFunc)
return tabTemp
}
function updateTabFormats() {
updateTabFormat(player.tab)
updateTabFormat(player.navTab)
}
function updateTabFormat(layer) {
if (layers[layer]?.tabFormat === undefined) return
let tab = player.subtabs[layer]?.mainTabs
if (isFunction(layers[layer].tabFormat)) {
Vue.set(temp[layer], 'tabFormat', layers[layer].tabFormat())
}
else if (Array.isArray(layers[layer].tabFormat)) {
Vue.set(temp[layer], 'tabFormat', constructTabFormat(layer))
}
else if (isPlainObject(layers[layer].tabFormat)) {
if (layers[layer].tabFormat[tab].embedLayer === undefined)
Vue.set(temp[layer].tabFormat[tab], 'content', constructTabFormat(layer, tab))
}
// Check for embedded layer
if (isPlainObject(tmp[layer].tabFormat) && tmp[layer].tabFormat[tab].embedLayer !== undefined) {
constructTabFormat(tmp[layer].tabFormat[tab].embedLayer)
}
// Update microtabs
for (family in layers[layer].microtabs) {
tab = player.subtabs[layer][family]
if (tmp[layer].microtabs[family][tab]) {
if (tmp[layer].microtabs[family][tab].embedLayer)
constructTabFormat(tmp[layer].microtabs[family][tab].embedLayer)
else
constructTabFormat(layer, tab, family)
}
}
}

View file

@ -165,8 +165,9 @@ function setupLayer(layer){
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].unlockOrder === undefined) layers[layer].unlockOrder = []
if(layers[layer].gainMult === undefined) layers[layer].gainMult = new Decimal(1)
if(layers[layer].gainExp === undefined) layers[layer].gainExp = new Decimal(1)
if(layers[layer].gainMult === undefined) layers[layer].gainMult = decimalOne
if(layers[layer].gainExp === undefined) layers[layer].gainExp = decimalOne
if(layers[layer].directMult === undefined) layers[layer].directMult = decimalOne
if(layers[layer].type === undefined) layers[layer].type = "none"
if(layers[layer].base === undefined || layers[layer].base <= 1) layers[layer].base = 2
if(layers[layer].softcap === undefined) layers[layer].softcap = new Decimal("e1e7")
@ -174,6 +175,7 @@ function setupLayer(layer){
if(layers[layer].displayRow === undefined) layers[layer].displayRow = layers[layer].row
if(layers[layer].name === undefined) layers[layer].name = layer
if(layers[layer].layerShown === undefined) layers[layer].layerShown = true
if(layers[layer].glowColor === undefined) layers[layer].glowColor = "#ff0000"
let row = layers[layer].row

View file

@ -4,8 +4,9 @@ var systemComponents = {
template: `
<div class="upgRow">
<div v-for="tab in Object.keys(data)">
<button v-if="data[tab].unlocked == undefined || data[tab].unlocked" v-bind:class="{tabButton: true, notify: subtabShouldNotify(layer, name, tab), resetNotify: subtabResetNotify(layer, name, tab)}" v-bind:style="[{'border-color': tmp[layer].color}, tmp[layer].componentStyles['tab-button'], data[tab].buttonStyle]"
v-on:click="function(){player.subtabs[layer][name] = tab; needCanvasUpdate = true;}">{{tab}}</button>
<button v-if="data[tab].unlocked == undefined || data[tab].unlocked" v-bind:class="{tabButton: true, notify: subtabShouldNotify(layer, name, tab), resetNotify: subtabResetNotify(layer, name, tab)}"
v-bind:style="[{'border-color': tmp[layer].color}, (data[tab].glowColor && subtabShouldNotify(layer, name, tab) ? {'box-shadow': 'var(--hqProperty2a), 0 0 20px ' + data[tab].glowColor} : {}), tmp[layer].componentStyles['tab-button'], data[tab].buttonStyle]"
v-on:click="function(){player.subtabs[layer][name] = tab; updateTabFormats(); needCanvasUpdate = true;}">{{tab}}</button>
</div>
</div>
`
@ -158,10 +159,10 @@ var systemComponents = {
<td><button class="opt" onclick="adjustMSDisp()">Show Milestones: {{ MS_DISPLAYS[MS_SETTINGS.indexOf(player.msDisplay)]}}</button></td>
<td><button class="opt" onclick="toggleOpt('hqTree')">High-Quality Tree: {{ player.hqTree?"ON":"OFF" }}</button></td>
</tr>
<tr>
<td><button class="opt" onclick="toggleOpt('hideChallenges')">Completed Challenges: {{ player.hideChallenges?"HIDDEN":"SHOWN" }}</button></td>
<!-- <td><button class="opt" onclick="toggleOpt('oldStyle')">Style: {{ player.oldStyle?"v1.0":"NEW" }}</button></td>-->
</tr>
<tr>
<td><button class="opt" onclick="toggleOpt('hideChallenges')">Completed Challenges: {{ player.hideChallenges?"HIDDEN":"SHOWN" }}</button></td>
<td><button class="opt" onclick="toggleOpt('forceOneTab'); needsCanvasUpdate = true">Single-Tab Mode: {{ player.forceOneTab?"ALWAYS":"AUTO" }}</button></td>
</tr>
</table>`
},

View file

@ -6,9 +6,11 @@ var NaNalert = false;
// Tmp will not call these
var activeFunctions = [
"startData", "onPrestige", "doReset", "update", "automate",
"buy", "buyMax", "respec", "onComplete", "onPurchase", "onPress", "onClick", "onHold", "masterButtonPress",
"buy", "buyMax", "respec", "onPress", "onClick", "onHold", "masterButtonPress",
"sellOne", "sellAll", "pay", "actualCostFunction", "actualEffectFunction",
"effectDescription", "display", "fullDisplay", "effectDisplay", "rewardDisplay",
"tabFormat", "content",
"onComplete", "onPurchase", "onEnter", "onExit",
]
var noCall = doNotCallTheseFunctionsEveryTick
@ -35,24 +37,16 @@ function setupTemp() {
tmp[layer].notify = {}
tmp[layer].prestigeNotify = {}
tmp[layer].computedNodeStyle = []
setupBarStyles(layer)
setupBuyables(layer)
tmp[layer].trueGlowColor = []
}
tmp.other = {
screenWidth: window.innerWidth,
splitScreen: window.innerWidth >=1024,
lastPoints: player.points || new Decimal(0),
oomps: new Decimal(0),
held: {
time: null,
id: null,
layer: null,
type: null,
}
lastPoints: player.points || decimalZero,
oomps: decimalZero,
}
updateWidth()
temp = tmp
}
@ -80,7 +74,7 @@ function setupTempData(layerData, tmpData, funcsData) {
}
else if (isFunction(layerData[item]) && !activeFunctions.includes(item)){
funcsData[item] = layerData[item]
tmpData[item] = new Decimal(1) // The safest thing to put probably?
tmpData[item] = decimalOne // The safest thing to put probably?
} else {
tmpData[item] = layerData[item]
}
@ -98,9 +92,9 @@ function updateTemp() {
tmp[layer].nextAt = getNextAt(layer)
tmp[layer].nextAtDisp = getNextAt(layer, true)
tmp[layer].canReset = canReset(layer)
tmp[layer].trueGlowColor = tmp[layer].glowColor
tmp[layer].notify = shouldNotify(layer)
tmp[layer].prestigeNotify = prestigeNotify(layer)
constructBarStyles(layer)
}
tmp.pointGen = getPointGen()
@ -116,6 +110,7 @@ function updateTempData(layerData, tmpData, funcsData) {
for (item in funcsData){
if (Array.isArray(layerData[item])) {
if (item === "tabFormat" || item === "content") return // These are only updated when needed
updateTempData(layerData[item], tmpData[item], funcsData[item])
}
else if ((!!layerData[item]) && (layerData[item].constructor === Object) || (typeof layerData[item] === "object") && traversableClasses.includes(layerData[item].constructor.name)){
@ -134,11 +129,7 @@ function updateTempData(layerData, tmpData, funcsData) {
NaNalert = true;
}
}
if (tmpData[item] === undefined)
Vue.set(tmpData, item, value)
else
tmpData[item]=value
Vue.set(tmpData, item, value)
}
}
}
@ -159,64 +150,18 @@ function updateClickableTemp(layer)
updateTempData(layers[layer].clickables, tmp[layer].clickables, funcs[layer].clickables)
}
function constructBarStyles(layer){
if (layers[layer].bars === undefined)
return
for (id in layers[layer].bars){
if (id !== "layer") {
let bar = tmp[layer].bars[id]
if (bar.progress instanceof Decimal)
bar.progress = bar.progress.toNumber()
bar.progress = (1 -Math.min(Math.max(bar.progress, 0), 1)) * 100
bar.dims = {'width': bar.width + "px", 'height': bar.height + "px"}
let dir = bar.direction
bar.fillDims = {'width': (bar.width + 0.5) + "px", 'height': (bar.height + 0.5) + "px"}
if (dir !== undefined)
{
bar.fillDims['clip-path'] = 'inset(0% 50% 0% 0%)'
if(dir == UP){
bar.fillDims['clip-path'] = 'inset(' + bar.progress + '% 0% 0% 0%)'
}
else if(dir == DOWN){
bar.fillDims['clip-path'] = 'inset(0% 0% ' + bar.progress + '% 0%)'
}
else if(dir == RIGHT){
bar.fillDims['clip-path'] = 'inset(0% ' + bar.progress + '% 0% 0%)'
}
else if(dir == LEFT){
bar.fillDims['clip-path'] = 'inset(0% 0% 0% ' + bar.progress + '%)'
}
}
}
}
}
function setupBarStyles(layer){
if (layers[layer].bars === undefined)
return
for (id in layers[layer].bars){
let bar = tmp[layer].bars[id]
bar.dims = {}
bar.fillDims = {}
}
}
function setupBuyables(layer) {
for (id in layers[layer].buyables) {
if (!isNaN(id)) {
let b = layers[layer].buyables[id]
b.actualCostFunction = b.cost
b.cost = function(x) {
x = x ?? player[this.layer].buyables[this.id]
x = (x === undefined ? player[this.layer].buyables[this.id] : x)
return layers[this.layer].buyables[this.id].actualCostFunction(x)
}
b.actualEffectFunction = b.effect
b.effect = function(x) {
x = x ?? player[this.layer].buyables[this.id]
x = (x === undefined ? player[this.layer].buyables[this.id] : x)
return layers[this.layer].buyables[this.id].actualEffectFunction(x)
}
}

View file

@ -195,8 +195,10 @@ function showTab(name) {
player.tab = name
if (player.navTab == "none" && (tmp[name].row !== "side") && (tmp[name].row !== "otherside")) player.lastSafeTab = name
delete player.notify[name]
updateTabFormats()
needCanvasUpdate = true
document.activeElement.blur()
}
function showNavTab(name) {
@ -205,6 +207,7 @@ function showNavTab(name) {
var toTreeTab = name == "tree"
player.navTab = name
player.notify[name] = false
updateTabFormats()
needCanvasUpdate = true
}
@ -425,7 +428,7 @@ function adjustPopupTime(diff) {
}
function run(func, target, args = null) {
if (!!(func && func.constructor && func.call && func.apply)) {
if (isFunction(func)) {
let bound = func.bind(target)
return bound(args)
}

View file

@ -3,7 +3,7 @@ function exponentialFormat(num, precision, mantissa = true) {
let e = num.log10().floor()
let m = num.div(Decimal.pow(10, e))
if (m.toStringWithDecimalPlaces(precision) == 10) {
m = new Decimal(1)
m = decimalOne
e = e.add(1)
}
e = (e.gte(1e9) ? format(e, 1) : (e.gte(10000) ? commaFormat(e, 0) : e.toStringWithDecimalPlaces(0)))
@ -21,8 +21,8 @@ function commaFormat(num, precision) {
function regularFormat(num, precision) {
if (num === null || num === undefined) return "NaN"
if (num.mag < 0.001) return (0).toFixed(precision)
if (num.mag < 0.01) precision = 3
if (num.mag < 0.0001) return (0).toFixed(precision)
if (num.mag < 0.1 && precision !==0) precision = 4
return num.toStringWithDecimalPlaces(precision)
}
@ -32,7 +32,7 @@ function fixValue(x, y = 0) {
function sumValues(x) {
x = Object.values(x)
if (!x[0]) return new Decimal(0)
if (!x[0]) return decimalZero
return x.reduce((a, b) => Decimal.add(a, b))
}
@ -54,17 +54,17 @@ function format(decimal, precision = 2, small) {
else if (decimal.gte("1e1000")) return exponentialFormat(decimal, 0)
else if (decimal.gte(1e9)) return exponentialFormat(decimal, precision)
else if (decimal.gte(1e3)) return commaFormat(decimal, 0)
else if (decimal.gte(0.001) || !small) return regularFormat(decimal, precision)
else if (decimal.gte(0.0001) || !small) return regularFormat(decimal, precision)
else if (decimal.eq(0)) return (0).toFixed(precision)
decimal = invertOOM(decimal)
let val = ""
if (decimal.lt(1e1000)){
if (decimal.lt("1e1000")){
val = exponentialFormat(decimal, precision)
return val.replace(/([^(?:e|F)]*)$/, '-$1')
}
else
val = format(decimal, precision)
return val.replace(/([^(?:e|F)]*)$/, '-$1')
return format(decimal, precision) + "⁻¹"
}

View file

@ -19,6 +19,7 @@ function startPlayerBase() {
hasNaN: false,
hideChallenges: false,
showStory: true,
forceOneTab: false,
points: modInfo.initialStartPoints,
subtabs: {},
lastSafeTab: (readData(layoutInfo.showTree) ? "none" : layoutInfo.startTab)
@ -65,9 +66,9 @@ function getStartLayerData(layer) {
if (layerdata.unlocked === undefined)
layerdata.unlocked = true;
if (layerdata.total === undefined)
layerdata.total = new Decimal(0);
layerdata.total = decimalZero;
if (layerdata.best === undefined)
layerdata.best = new Decimal(0);
layerdata.best = decimalZero;
if (layerdata.resetTime === undefined)
layerdata.resetTime = 0;
if (layerdata.forceTooltip === undefined)
@ -77,7 +78,7 @@ function getStartLayerData(layer) {
if (layerdata.noRespecConfirm === undefined) layerdata.noRespecConfirm = false
if (layerdata.clickables == undefined)
layerdata.clickables = getStartClickables(layer);
layerdata.spentOnBuyables = new Decimal(0);
layerdata.spentOnBuyables = decimalZero;
layerdata.upgrades = [];
layerdata.milestones = [];
layerdata.lastMilestone = null;
@ -90,7 +91,7 @@ function getStartBuyables(layer) {
if (layers[layer].buyables) {
for (id in layers[layer].buyables)
if (isPlainObject(layers[layer].buyables[id]))
data[id] = new Decimal(0);
data[id] = decimalZero;
}
return data;
}
@ -190,6 +191,7 @@ function load() {
setupTemp();
updateTemp();
updateTemp();
updateTabFormats()
loadVue();
}
function setupModInfo() {