533 lines
13 KiB
JavaScript
533 lines
13 KiB
JavaScript
|
// ************ 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 === false) {
|
||
|
return;
|
||
|
}
|
||
|
if (tmp[layer].clickables[id].canClick === false) {
|
||
|
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 (inChallenge("tree-tab", 1)) {
|
||
|
if (player.tab === "color") {
|
||
|
completeChallenge("tree-tab", 1);
|
||
|
} else {
|
||
|
showTab("color");
|
||
|
}
|
||
|
} else 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();
|
||
|
} 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 (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!", 5, 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!", 5, 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 ") : ""}+<b>${formatWhole(tmp[layer].resetGain)}</b> ${tmp[layer].resource} ${tmp[layer].resetGain.lt(100) && player[layer].points.lt(1e3) ? `<br><br>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 "}+<b>${formatWhole(tmp[layer].resetGain)}</b> ${tmp[layer].resource}<br><br>${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;
|
||
|
}
|
||
|
}
|