538 lines
14 KiB
JavaScript
538 lines
14 KiB
JavaScript
let player;
|
|
let needCanvasUpdate = true;
|
|
let gameEnded = false;
|
|
|
|
|
|
// Don't change this
|
|
const TMT_VERSION = {
|
|
tmtNum: "2.5.9.2",
|
|
tmtName: "Dreams Really Do Come True"
|
|
}
|
|
|
|
function getResetGain(layer, useType = null) {
|
|
let type = useType;
|
|
if (!useType) {
|
|
type = tmp[layer].type;
|
|
if (layers[layer].getResetGain !== undefined) {
|
|
return layers[layer].getResetGain();
|
|
}
|
|
}
|
|
if (tmp[layer].type === "none") {
|
|
return decimalZero;
|
|
}
|
|
if (tmp[layer].gainExp.eq(0)) {
|
|
return decimalZero;
|
|
}
|
|
if (type === "static") {
|
|
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 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 decimalZero;
|
|
}
|
|
}
|
|
|
|
function getNextAt(layer, canMax = false, useType = null) {
|
|
let type = useType;
|
|
if (!useType) {
|
|
type = tmp[layer].type;
|
|
if (layers[layer].getNextAt !== undefined) {
|
|
return layers[layer].getNextAt(canMax);
|
|
}
|
|
|
|
}
|
|
if (tmp[layer].type === "none") {
|
|
return new Decimal(Infinity);
|
|
}
|
|
|
|
if (tmp[layer].gainMult.lte(0)) {
|
|
return new Decimal(Infinity);
|
|
}
|
|
if (tmp[layer].gainExp.lte(0)) {
|
|
return new Decimal(Infinity);
|
|
}
|
|
|
|
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).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).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();
|
|
}
|
|
return next;
|
|
} else if (type === "custom") {
|
|
return layers[layer].getNextAt(canMax);
|
|
} else {
|
|
return decimalZero;
|
|
}
|
|
}
|
|
|
|
function softcap(value, cap, power = 0.5) {
|
|
if (value.lte(cap)) {
|
|
return value;
|
|
} else {
|
|
return value.pow(power).times(cap.pow(decimalOne.sub(power)));
|
|
}
|
|
}
|
|
|
|
// Return true if the layer should be highlighted. By default checks for upgrades only.
|
|
function shouldNotify(layer) {
|
|
for (let id in tmp[layer].upgrades) {
|
|
if (isPlainObject(layers[layer].upgrades[id])) {
|
|
if (canAffordUpgrade(layer, id) && !hasUpgrade(layer, id) && tmp[layer].upgrades[id].unlocked) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if (player[layer].activeChallenge && canCompleteChallenge(layer, player[layer].activeChallenge)) {
|
|
return true;
|
|
}
|
|
|
|
if (tmp[layer].shouldNotify)
|
|
return true
|
|
|
|
if (isPlainObject(tmp[layer].tabFormat)) {
|
|
for (let subtab in tmp[layer].tabFormat) {
|
|
if (subtabShouldNotify(layer, "mainTabs", subtab)) {
|
|
tmp[layer].trueGlowColor = tmp[layer].tabFormat[subtab].glowColor
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let family in tmp[layer].microtabs) {
|
|
for (let subtab in tmp[layer].microtabs[family]) {
|
|
if (subtabShouldNotify(layer, family, subtab)) {
|
|
tmp[layer].trueGlowColor = tmp[layer].microtabs[family][subtab].glowColor
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
function canReset(layer) {
|
|
if (layers[layer].canReset !== undefined) {
|
|
return run(layers[layer].canReset, layers[layer]);
|
|
} else if (tmp[layer].type === "normal") {
|
|
return tmp[layer].baseAmount.gte(tmp[layer].requires);
|
|
} else if (tmp[layer].type === "static") {
|
|
return tmp[layer].baseAmount.gte(tmp[layer].nextAt);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function rowReset(row, layer) {
|
|
for (let lr in ROW_LAYERS[row]) {
|
|
if (layers[lr].doReset) {
|
|
|
|
player[lr].activeChallenge = null; // Exit challenges on any row reset on an equal or higher row
|
|
run(layers[lr].doReset, layers[lr], layer);
|
|
} else if (tmp[layer].row > tmp[lr].row && row !== "side" && !isNaN(row)) {
|
|
layerDataReset(lr);
|
|
}
|
|
}
|
|
}
|
|
|
|
function layerDataReset(layer, keep = []) {
|
|
let storedData = {unlocked: player[layer].unlocked, forceTooltip: player[layer].forceTooltip, noRespecConfirm: player[layer].noRespecConfirm} // Always keep these
|
|
|
|
for (let thing in keep) {
|
|
if (player[layer][keep[thing]] !== undefined) {
|
|
storedData[keep[thing]] = player[layer][keep[thing]];
|
|
}
|
|
}
|
|
Vue.set(player[layer], "buyables", getStartBuyables(layer));
|
|
Vue.set(player[layer], "clickables", getStartClickables(layer));
|
|
Vue.set(player[layer], "challenges", getStartChallenges(layer));
|
|
|
|
layOver(player[layer], getStartLayerData(layer));
|
|
player[layer].upgrades = [];
|
|
player[layer].milestones = [];
|
|
player[layer].achievements = [];
|
|
player[layer].challenges = getStartChallenges(layer);
|
|
resetBuyables(layer);
|
|
|
|
if (layers[layer].clickables && !player[layer].clickables) {
|
|
player[layer].clickables = getStartClickables(layer);
|
|
}
|
|
for (let thing in storedData) {
|
|
player[layer][thing] = storedData[thing];
|
|
}
|
|
}
|
|
|
|
function resetBuyables(layer) {
|
|
if (layers[layer].buyables) {
|
|
player[layer].buyables = getStartBuyables(layer);
|
|
}
|
|
player[layer].spentOnBuyables = decimalZero;
|
|
}
|
|
|
|
|
|
function addPoints(layer, gain) {
|
|
if (isFunction(layers[layer].onAddPoints)) {
|
|
layers[layer].onAddPoints(gain);
|
|
}
|
|
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].total) {
|
|
player[layer].total = player[layer].total.add(gain);
|
|
}
|
|
}
|
|
|
|
function generatePoints(layer, diff) {
|
|
addPoints(layer, tmp[layer].resetGain.times(diff));
|
|
}
|
|
|
|
let prevOnReset;
|
|
|
|
function doReset(layer, force = false) {
|
|
if (tmp[layer].type === "none") {
|
|
return;
|
|
}
|
|
let row = tmp[layer].row;
|
|
if (!force) {
|
|
if (tmp[layer].baseAmount.lt(tmp[layer].requires)) {
|
|
return;
|
|
}
|
|
let gain = tmp[layer].resetGain;
|
|
if (tmp[layer].type === "static") {
|
|
if (tmp[layer].baseAmount.lt(tmp[layer].nextAt)) {
|
|
return;
|
|
}
|
|
gain = (tmp[layer].canBuyMax ? gain : 1);
|
|
}
|
|
if (tmp[layer].type === "custom") {
|
|
if (!tmp[layer].canReset) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (layers[layer].onPrestige) {
|
|
run(layers[layer].onPrestige, layers[layer], gain);
|
|
}
|
|
|
|
addPoints(layer, gain);
|
|
updateMilestones(layer);
|
|
updateAchievements(layer);
|
|
|
|
if (!player[layer].unlocked) {
|
|
player[layer].unlocked = true;
|
|
needCanvasUpdate = true;
|
|
|
|
if (tmp[layer].increaseUnlockOrder) {
|
|
let lrs = tmp[layer].increaseUnlockOrder;
|
|
for (let lr in lrs) {
|
|
if (!player[lrs[lr]].unlocked) {
|
|
player[lrs[lr]].unlockOrder++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp[layer].baseAmount = decimalZero; // quick fix
|
|
}
|
|
|
|
if (tmp[layer].resetsNothing) {
|
|
return;
|
|
}
|
|
|
|
|
|
for (let layerResetting in layers) {
|
|
if (row >= layers[layerResetting].row && (!force || layerResetting !== layer)) {
|
|
completeChallenge(layerResetting);
|
|
}
|
|
}
|
|
|
|
prevOnReset = {...player}; //Deep Copy
|
|
player.points = (row === 0 ? decimalZero : getStartPoints());
|
|
|
|
for (let x = row; x >= 0; x--) {
|
|
rowReset(x, layer);
|
|
}
|
|
rowReset("side", layer);
|
|
prevOnReset = undefined;
|
|
|
|
player[layer].resetTime = 0;
|
|
|
|
updateTemp();
|
|
updateTemp();
|
|
}
|
|
|
|
function startChallenge(layer, x) {
|
|
let enter = false;
|
|
if (!player[layer].unlocked) {
|
|
return;
|
|
}
|
|
if (player[layer].activeChallenge === x) {
|
|
completeChallenge(layer, x);
|
|
player[layer].activeChallenge = null;
|
|
} else {
|
|
enter = true;
|
|
}
|
|
doReset(layer, true);
|
|
if (enter) {
|
|
player[layer].activeChallenge = x;
|
|
run(layers[layer].challenges[x].onEnter, layers[layer].challenges[x]);
|
|
}
|
|
|
|
updateChallengeTemp(layer);
|
|
}
|
|
|
|
function canCompleteChallenge(layer, x) {
|
|
if (x !== player[layer].activeChallenge) {
|
|
return;
|
|
}
|
|
let challenge = tmp[layer].challenges[x];
|
|
if (challenge.canComplete !== undefined) {
|
|
return challenge.canComplete;
|
|
}
|
|
|
|
if (challenge.currencyInternalName) {
|
|
let name = challenge.currencyInternalName;
|
|
if (challenge.currencyLocation) {
|
|
return !(challenge.currencyLocation[name].lt(challenge.goal));
|
|
} else if (challenge.currencyLayer) {
|
|
let lr = challenge.currencyLayer;
|
|
return !(player[lr][name].lt(challenge.goal));
|
|
} else {
|
|
return !(player[name].lt(challenge.goal));
|
|
}
|
|
} else {
|
|
return !(player.points.lt(challenge.goal));
|
|
}
|
|
|
|
}
|
|
|
|
function completeChallenge(layer) {
|
|
let x = player[layer].activeChallenge;
|
|
if (!x) {
|
|
return;
|
|
}
|
|
|
|
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) {
|
|
needCanvasUpdate = true;
|
|
player[layer].challenges[x] += completions;
|
|
player[layer].challenges[x] = Math.min(player[layer].challenges[x], tmp[layer].challenges[x].completionLimit);
|
|
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);
|
|
}
|
|
|
|
VERSION.withoutName = "v" + VERSION.num + (VERSION.pre ? " Pre-Release " + VERSION.pre : VERSION.pre ? " Beta " + VERSION.beta : "");
|
|
VERSION.withName = VERSION.withoutName + (VERSION.name ? ": " + VERSION.name : "");
|
|
|
|
|
|
function autobuyUpgrades(layer) {
|
|
if (!tmp[layer].upgrades) {
|
|
return;
|
|
}
|
|
for (let id in tmp[layer].upgrades) {
|
|
if (isPlainObject(tmp[layer].upgrades[id]) && (layers[layer].upgrades[id].canAfford === undefined || layers[layer].upgrades[id].canAfford() === true)) {
|
|
buyUpg(layer, id);
|
|
}
|
|
}
|
|
}
|
|
|
|
function gameLoop(diff) {
|
|
if (isEndgame() || gameEnded) {
|
|
gameEnded = 1;
|
|
}
|
|
|
|
if (isNaN(diff)) {
|
|
diff = 0;
|
|
}
|
|
if (gameEnded && !player.keepGoing) {
|
|
diff = 0;
|
|
player.tab = "gameEnded";
|
|
clearParticles();
|
|
}
|
|
|
|
if (maxTickLength) {
|
|
let limit = maxTickLength();
|
|
if (diff > limit) {
|
|
diff = limit;
|
|
}
|
|
}
|
|
addTime(diff);
|
|
const modifiedDiff = diff * ritualEffect("speed").toNumber();
|
|
player.points = player.points.add(tmp.pointGen.times(modifiedDiff)).max(0);
|
|
|
|
for (let x = 0; x <= maxRow; x++) {
|
|
for (let item in TREE_LAYERS[x]) {
|
|
let layer = TREE_LAYERS[x][item];
|
|
player[layer].resetTime += diff;
|
|
if (tmp[layer].passiveGeneration) {
|
|
generatePoints(layer, modifiedDiff * tmp[layer].passiveGeneration);
|
|
}
|
|
if (layers[layer].update) {
|
|
layers[layer].update(modifiedDiff);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let row in OTHER_LAYERS) {
|
|
for (let item in OTHER_LAYERS[row]) {
|
|
let layer = OTHER_LAYERS[row][item];
|
|
player[layer].resetTime += diff;
|
|
if (tmp[layer].passiveGeneration) {
|
|
generatePoints(layer, modifiedDiff * tmp[layer].passiveGeneration);
|
|
}
|
|
if (layers[layer].update) {
|
|
layers[layer].update(modifiedDiff);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let x = maxRow; x >= 0; x--) {
|
|
for (let item in TREE_LAYERS[x]) {
|
|
let layer = TREE_LAYERS[x][item];
|
|
if (tmp[layer].autoPrestige && tmp[layer].canReset) {
|
|
doReset(layer);
|
|
}
|
|
if (layers[layer].automate) {
|
|
layers[layer].automate();
|
|
}
|
|
if (tmp[layer].autoUpgrade) {
|
|
autobuyUpgrades(layer);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let row in OTHER_LAYERS) {
|
|
for (let item in OTHER_LAYERS[row]) {
|
|
let layer = OTHER_LAYERS[row][item];
|
|
if (tmp[layer].autoPrestige && tmp[layer].canReset) {
|
|
doReset(layer);
|
|
}
|
|
if (layers[layer].automate) {
|
|
layers[layer].automate();
|
|
}
|
|
player[layer].best = player[layer].best.max(player[layer].points);
|
|
if (tmp[layer].autoUpgrade) {
|
|
autobuyUpgrades(layer);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (let layer in layers) {
|
|
if (layers[layer].milestones) {
|
|
updateMilestones(layer);
|
|
}
|
|
if (layers[layer].achievements) {
|
|
updateAchievements(layer);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function hardReset(override = false) {
|
|
if (!(override || confirm("Are you sure you want to do this? You will lose all your progress!"))) {
|
|
return;
|
|
}
|
|
player = null;
|
|
save();
|
|
window.location.reload();
|
|
}
|
|
|
|
let ticking = false;
|
|
let lastTenTicks = [];
|
|
|
|
const interval = setInterval(function () {
|
|
if (player === undefined || tmp === undefined) {
|
|
return;
|
|
}
|
|
if (ticking) {
|
|
return;
|
|
}
|
|
if (gameEnded && !player.keepGoing) {
|
|
return;
|
|
}
|
|
ticking = true;
|
|
let now = Date.now();
|
|
let diff = (now - player.time) / 1e3;
|
|
let trueDiff = diff;
|
|
if (player.offTime !== undefined) {
|
|
if (player.offTime.remain > modInfo.offlineLimit * 3600) {
|
|
player.offTime.remain = modInfo.offlineLimit * 3600;
|
|
}
|
|
if (player.offTime.remain > 0) {
|
|
let offlineDiff = Math.max(player.offTime.remain / 10, diff);
|
|
player.offTime.remain -= offlineDiff;
|
|
diff += offlineDiff;
|
|
}
|
|
if (!player.offlineProd || player.offTime.remain <= 0) {
|
|
player.offTime = undefined;
|
|
}
|
|
}
|
|
if (player.devSpeed != null) {
|
|
diff *= player.devSpeed;
|
|
}
|
|
player.time = now;
|
|
if (needCanvasUpdate) {
|
|
resizeCanvas();
|
|
needCanvasUpdate = false;
|
|
}
|
|
tmp.scrolled = document.getElementById("treeTab")?.scrollTop > 30;
|
|
updateTemp();
|
|
updateOomps(diff);
|
|
updateWidth()
|
|
updateTabFormats()
|
|
gameLoop(diff);
|
|
fixNaNs();
|
|
adjustPopupTime(trueDiff);
|
|
updateParticles(trueDiff);
|
|
lastTenTicks.push(trueDiff);
|
|
if (lastTenTicks.length > 10) {
|
|
lastTenTicks = lastTenTicks.slice(1);
|
|
}
|
|
Vue.set(app, "lastTenTicks", lastTenTicks);
|
|
ticking = false;
|
|
}, 50);
|
|
|
|
setInterval(function () {
|
|
needCanvasUpdate = true;
|
|
}, 500);
|