// ************ 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 \"" + (tmp[layer].name ? tmp[layer].name : layer) + "\" reset as well!")) return run(layers[layer].buyables.respec, layers[layer].buyables) updateBuyableTemp(layer) document.activeElement.blur() } function canAffordUpgrade(layer, id) { let upg = tmp[layer].upgrades[id] if (tmp[layer].upgrades[id].canAfford !== undefined) return tmp[layer].upgrades[id].canAfford let cost = tmp[layer].upgrades[id].cost return canAffordPurchase(layer, upg, cost) } function hasUpgrade(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 hasAchievement(layer, id) { return (player[layer].achievements.includes(toNumber(id)) || player[layer].achievements.includes(id.toString())) } function hasChallenge(layer, id) { return (player[layer].challenges[id]) } function maxedChallenge(layer, id) { return (player[layer].challenges[id] >= tmp[layer].challenges[id].completionLimit) } function challengeCompletions(layer, id) { return (player[layer].challenges[id]) } function getBuyableAmount(layer, id) { return (player[layer].buyables[id]) } function setBuyableAmount(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 upgradeEffect(layer, id) { return (tmp[layer].upgrades[id].effect) } function challengeEffect(layer, id) { return (tmp[layer].challenges[id].rewardEffect) } function buyableEffect(layer, id) { return (tmp[layer].buyables[id].effect) } function clickableEffect(layer, id) { return (tmp[layer].clickables[id].effect) } function achievementEffect(layer, id) { return (tmp[layer].achievements[id].effect) } function canAffordPurchase(layer, thing, cost) { if (thing.currencyInternalName) { let name = thing.currencyInternalName if (thing.currencyLocation) { return !(thing.currencyLocation[name].lt(cost)) } else 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 buyUpgrade(layer, id) { buyUpg(layer, id) } function buyUpg(layer, id) { if (!tmp[layer].upgrades || !tmp[layer].upgrades[id]) return let upg = tmp[layer].upgrades[id] if (!player[layer].unlocked) return if (!tmp[layer].upgrades[id].unlocked) return if (player[layer].upgrades.includes(id)) return if (upg.canAfford === false) return let pay = layers[layer].upgrades[id].pay if (pay !== undefined) run(pay, layers[layer].upgrades[id]) else { let cost = tmp[layer].upgrades[id].cost if (upg.currencyInternalName) { let name = upg.currencyInternalName 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 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) run(upg.onPurchase, upg) } function buyMaxBuyable(layer, id) { if (!player[layer].unlocked) return if (!tmp[layer].buyables[id].unlocked) return if (!tmp[layer].buyables[id].canAfford) return if (!layers[layer].buyables[id].buyMax) return run(layers[layer].buyables[id].buyMax, layers[layer].buyables[id]) updateBuyableTemp(layer) } function buyBuyable(layer, id) { if (!player[layer].unlocked) return if (!tmp[layer].buyables[id].unlocked) return if (!tmp[layer].buyables[id].canAfford) return run(layers[layer].buyables[id].buy, layers[layer].buyables[id]) updateBuyableTemp(layer) } function clickClickable(layer, id) { if (!player[layer].unlocked) return if (!tmp[layer].clickables[id].unlocked) return if (!tmp[layer].clickables[id].canClick) return run(layers[layer].clickables[id].onClick, layers[layer].clickables[id]) updateClickableTemp(layer) } // Function to determine if the player is in a challenge function inChallenge(layer, id) { let challenge = player[layer].activeChallenge if (!challenge) return false id = toNumber(id) if (challenge == id) return true if (layers[layer].challenges[challenge].countsAs) return tmp[layer].challenges[challenge].countsAs.includes(id) } // ************ Misc ************ var onTreeTab = true function showTab(name) { if (LAYERS.includes(name) && !layerunlocked(name)) return if (player.tab === name && isPlainObject(tmp[name].tabFormat)) { player.subtabs[name].mainTabs = Object.keys(layers[name].tabFormat)[0] } var toTreeTab = name == "none" player.tab = name if (player.navTab == "none" && (tmp[name].row !== "side") && (tmp[name].row !== "otherside")) player.lastSafeTab = name delete player.notify[name] needCanvasUpdate = true document.activeElement.blur() } function showNavTab(name) { if (LAYERS.includes(name) && !layerunlocked(name)) return var toTreeTab = name == "tree" player.navTab = name player.notify[name] = false needCanvasUpdate = true } function goBack() { if (player.navTab !== "none") showTab("none") else showTab(player.lastSafeTab) } function layOver(obj1, obj2) { for (let x in obj2) { if (obj2[x] instanceof Object) layOver(obj1[x], obj2[x]); else obj1[x] = obj2[x]; } } function prestigeNotify(layer) { if (layers[layer].prestigeNotify) return layers[layer].prestigeNotify() else if (tmp[layer].autoPrestige || tmp[layer].passiveGeneration) return false else if (tmp[layer].type == "static") return tmp[layer].canReset else if (tmp[layer].type == "normal") return (tmp[layer].canReset && (tmp[layer].resetGain.gte(player[layer].points.div(10)))) else return false } function notifyLayer(name) { if (player.tab == name || !layerunlocked(name)) return player.notify[name] = 1 } function subtabShouldNotify(layer, family, id) { let subtab = {} if (family == "mainTabs") subtab = tmp[layer].tabFormat[id] else subtab = tmp[layer].microtabs[family][id] if (subtab.embedLayer) return tmp[subtab.embedLayer].notify else return subtab.shouldNotify } function subtabResetNotify(layer, family, id) { let subtab = {} if (family == "mainTabs") subtab = tmp[layer].tabFormat[id] else subtab = tmp[layer].microtabs[family][id] if (subtab.embedLayer) return tmp[subtab.embedLayer].prestigeNotify else return false } function nodeShown(layer) { if (layerShown(layer)) return true switch (layer) { case "idk": return player.idk.unlocked break; } return false } function layerunlocked(layer) { if (tmp[layer] && tmp[layer].type == "none") return (player[layer].unlocked) return LAYERS.includes(layer) && (player[layer].unlocked || (tmp[layer].canReset && tmp[layer].layerShown)) } function keepGoing() { player.keepGoing = true; needCanvasUpdate = true; } function toNumber(x) { if (x.mag !== undefined) return x.toNumber() if (x + 0 !== x) return parseFloat(x) return x } function updateMilestones(layer) { for (id in layers[layer].milestones) { if (!(hasMilestone(layer, id)) && layers[layer].milestones[id].done()) { player[layer].milestones.push(id) if (tmp[layer].milestonePopups || tmp[layer].milestonePopups === undefined) doPopup("milestone", tmp[layer].milestones[id].requirementDescription, "Milestone Gotten!", 3, tmp[layer].color); } } } function updateAchievements(layer) { for (id in layers[layer].achievements) { if (isPlainObject(layers[layer].achievements[id]) && !(hasAchievement(layer, id)) && layers[layer].achievements[id].done()) { player[layer].achievements.push(id) if (layers[layer].achievements[id].onComplete) layers[layer].achievements[id].onComplete() if (tmp[layer].achievementPopups || tmp[layer].achievementPopups === undefined) doPopup("achievement", tmp[layer].achievements[id].name, "Achievement Gotten!", 3, tmp[layer].color); } } } function addTime(diff, layer) { let data = player let time = data.timePlayed if (layer) { data = data[layer] time = data.time } //I am not that good to perfectly fix that leak. ~ DB Aarex if (time + 0 !== time) { console.log("Memory leak detected. Trying to fix...") time = toNumber(time) if (isNaN(time) || time == 0) { console.log("Couldn't fix! Resetting...") time = layer ? player.timePlayed : 0 if (!layer) player.timePlayedReset = true } } time += toNumber(diff) if (layer) data.time = time else data.timePlayed = time } document.onkeydown = function (e) { if (player === undefined) return; if (gameEnded && !player.keepGoing) return; let shiftDown = e.shiftKey let ctrlDown = e.ctrlKey let key = e.key if (ctrlDown) key = "ctrl+" + key if (onFocused) return if (ctrlDown && hotkeys[key]) e.preventDefault() if (hotkeys[key]) { if (player[hotkeys[key].layer].unlocked) hotkeys[key].onPress() } } var onFocused = false function focused(x) { onFocused = x } function prestigeButtonText(layer) { if (layers[layer].prestigeButtonText !== undefined) return layers[layer].prestigeButtonText() else if (tmp[layer].type == "normal") return `${player[layer].points.lt(1e3) ? (tmp[layer].resetDescription !== undefined ? tmp[layer].resetDescription : "Reset for ") : ""}+${formatWhole(tmp[layer].resetGain)} ${tmp[layer].resource} ${tmp[layer].resetGain.lt(100) && player[layer].points.lt(1e3) ? `

Next at ${(tmp[layer].roundUpCost ? formatWhole(tmp[layer].nextAt) : format(tmp[layer].nextAt))} ${tmp[layer].baseResource}` : ""}` else if (tmp[layer].type == "static") return `${tmp[layer].resetDescription !== undefined ? tmp[layer].resetDescription : "Reset for "}+${formatWhole(tmp[layer].resetGain)} ${tmp[layer].resource}

${player[layer].points.lt(30) ? (tmp[layer].baseAmount.gte(tmp[layer].nextAt) && (tmp[layer].canBuyMax !== undefined) && tmp[layer].canBuyMax ? "Next:" : "Req:") : ""} ${formatWhole(tmp[layer].baseAmount)} / ${(tmp[layer].roundUpCost ? formatWhole(tmp[layer].nextAtDisp) : format(tmp[layer].nextAtDisp))} ${tmp[layer].baseResource} ` else if (tmp[layer].type == "none") return "" else return "You need prestige button text" } function isFunction(obj) { return !!(obj && obj.constructor && obj.call && obj.apply); }; function isPlainObject(obj) { return (!!obj) && (obj.constructor === Object) } document.title = modInfo.name // Variables that must be defined to display popups var activePopups = []; var popupID = 0; // Function to show popups function doPopup(type = "none", text = "This is a test popup.", title = "", timer = 3, color = "") { switch (type) { case "achievement": popupTitle = "Achievement Unlocked!"; popupType = "achievement-popup" break; case "challenge": popupTitle = "Challenge Complete"; popupType = "challenge-popup" break; default: popupTitle = "Something Happened?"; popupType = "default-popup" break; } if (title != "") popupTitle = title; popupMessage = text; popupTimer = timer; activePopups.push({ "time": popupTimer, "type": popupType, "title": popupTitle, "message": (popupMessage + "\n"), "id": popupID, "color": color }) popupID++; } //Function to reduce time on active popups function adjustPopupTime(diff) { for (popup in activePopups) { activePopups[popup].time -= diff; if (activePopups[popup]["time"] < 0) { activePopups.splice(popup, 1); // Remove popup when time hits 0 } } } function run(func, target, args = null) { if (!!(func && func.constructor && func.call && func.apply)) { let bound = func.bind(target) return bound(args) } else return func; }