// ************ Big Feature related ************ function respecBuyables(layer) { if (!layers[layer].buyables) return if (!layers[layer].buyables.respec) return if (!player[layer].noRespecConfirm && !confirm(tmp[layer].buyables.respecMessage || "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].deactivated) { return false; } 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 canBuyBuyable(layer, id) { let b = temp[layer].buyables[id] return (b.unlocked && run(b.canAfford, b) && player[layer].buyables[id].lt(b.purchaseLimit) && !tmp[layer].deactivated) } 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].canBuy) { 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].canBuy) { return; } run(layers[layer].buyables[id].buy, layers[layer].buyables[id]); updateBuyableTemp(layer); } function clickClickable(layer, id) { if (!player[layer].unlocked || tmp[layer].deactivated) { return; } if (tmp[layer].clickables[id].unlocked === false) { return; } if (tmp[layer].clickables[id].canClick === false) { return; } run(layers[layer].clickables[id].onClick, layers[layer].clickables[id]); updateClickableTemp(layer); } function clickGrid(layer, id) { if (!player[layer].unlocked || tmp[layer].deactivated) return if (!run(layers[layer].grid.getUnlocked, layers[layer].grid, id)) return if (!gridRun(layer, 'getCanClick', player[layer].grid[id], id)) return gridRun(layer, 'onClick', player[layer].grid[id], id) } // 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 ************ const onTreeTab = true; function showTab(name) { if (LAYERS.includes(name) && !layerunlocked(name)) { return; } if (player.tab !== name) { clearParticles(function(p) { return p.layer === player.tab }); } 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] updateTabFormats() needCanvasUpdate = true document.activeElement.blur() } function showNavTab(name) { if (LAYERS.includes(name) && !layerunlocked(name)) { return; } if (player.navTab !== name) { clearParticles(function(p) { return p.layer === player.navTab }); } var toTreeTab = name == "tree" player.navTab = name player.notify[name] = false updateTabFormats() 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 Decimal) { obj1[x] = new Decimal(obj2[x]); } else 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() if (isPlainObject(tmp[layer].tabFormat)) { for (subtab in tmp[layer].tabFormat){ if (subtabResetNotify(layer, 'mainTabs', subtab)) return true } } for (family in tmp[layer].microtabs) { for (subtab in tmp[layer].microtabs[family]){ if (subtabResetNotify(layer, family, subtab)) return true } } 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 subtab.prestigeNotify } function nodeShown(layer) { return layerShown(layer); } // noinspection SpellCheckingInspection 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; goBack() } function toNumber(x) { if (x.mag !== undefined) { return x.toNumber(); } if (x + 0 !== x) { return parseFloat(x); } return x; } function updateMilestones(layer) { for (let id in layers[layer].milestones) { if (!(hasMilestone(layer, id)) && layers[layer].milestones[id].done()) { player[layer].milestones.push(id); if (isFunction(layers[layer].milestones[id].onComplete)) { layers[layer].milestones[id].onComplete(); } if (tmp[layer].milestonePopups || tmp[layer].milestonePopups === undefined) { doPopup("milestone", tmp[layer].milestones[id].requirementDescription, "Milestone Gotten!", 3, tmp[layer].color); } player[layer].lastMilestone = id; } } } function updateAchievements(layer) { for (let 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; // TODO what's the leak mentioned above? Do I need to worry about it? player.chapterTime[player.chapter] += toNumber(diff); } } shiftDown = false ctrlDown = false document.onkeydown = function (e) { if (player === undefined) return; if (gameEnded && !player.keepGoing) return; shiftDown = e.shiftKey ctrlDown = e.ctrlKey let key = e.key if (ctrlDown) key = "ctrl+" + key if (onFocused) return if (ctrlDown && hotkeys[key]) e.preventDefault() if (hotkeys[key]) { let k = hotkeys[key] if (player[k.layer].unlocked && tmp[k.layer].hotkeys[k.id].unlocked) k.onPress() } }; onFocused = false; document.onkeyup = function (e) { shiftDown = e.shiftKey ctrlDown = e.ctrlKey } var onFocused = false function focused(x) { onFocused = x; } function isFunction(obj) { return !!(obj && obj.constructor && obj.call && obj.apply); } function isPlainObject(obj) { return (!!obj) && (obj.constructor === Object); } document.title = modInfo.name; // Converts a string value to whatever it's supposed to be function toValue(value, oldValue) { if (oldValue instanceof Decimal) { value = new Decimal (value) if (value.eq(decimalNaN)) return decimalZero return value } if (!isNaN(oldValue)) return parseFloat(value) || 0 return value } // Variables that must be defined to display popups const activePopups = []; let popupID = 0; // Function to show popups function doPopup(type = "none", text = "This is a test popup.", title = "", timer = 3, color = "") { let popupTitle, popupType; 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; } activePopups.push({ "time": timer, "type": popupType, "title": popupTitle, "message": (text + "\n"), "id": popupID, "color": color }); popupID++; } //Function to reduce time on active popups function adjustPopupTime(diff) { for (let 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 (isFunction(func)) { let bound = func.bind(target); return bound(args); } else { return func; } } function gridRun(layer, func, data, id) { if (isFunction(layers[layer].grid[func])) { let bound = layers[layer].grid[func].bind(layers[layer].grid) return bound(data, id) } else { return layers[layer].grid[func]; } }