Merge branch 'master' of https://github.com/IvarK/HahaSlabWontGetHere into omsi_sfx
@ -108,7 +108,6 @@
|
||||
"computed-property-spacing": "error",
|
||||
"consistent-this": "error",
|
||||
"func-call-spacing": "error",
|
||||
"guard-for-in": "warn",
|
||||
"id-blacklist": [
|
||||
"error",
|
||||
"ret",
|
||||
|
2
.github/ISSUE_TEMPLATE/ui-improvement.md
vendored
@ -8,7 +8,7 @@ assignees: ''
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when Blind shows me information
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
@ -4,7 +4,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/styles.css?3">
|
||||
<style>
|
||||
td {
|
||||
border: 1px solid gray;
|
||||
border: 0.1rem solid gray;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
@ -1,56 +1,54 @@
|
||||
body {
|
||||
font-family: Arial;
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#container {
|
||||
body {
|
||||
font-family: Arial, serif;
|
||||
}
|
||||
|
||||
.depression {
|
||||
text-align: center;
|
||||
padding: 4%;
|
||||
font-size: 2.5rem
|
||||
}
|
||||
|
||||
.depression-amount {
|
||||
font-size: 4.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stuff-container {
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#depression {
|
||||
text-align:center;
|
||||
padding: 4%;
|
||||
font-size: 25px
|
||||
.button {
|
||||
margin: 1rem auto;
|
||||
width: 13rem;
|
||||
height: 5rem;
|
||||
border: .2rem solid green;
|
||||
border-radius: 1rem;
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
|
||||
#amount {
|
||||
font-size: 45px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 10px auto;
|
||||
width: 130px;
|
||||
height: 50px;
|
||||
border: 2px solid green;
|
||||
border-radius: 10px;
|
||||
.button--stuff {
|
||||
background-color: grey;
|
||||
color: white;
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: rgb(125, 151, 118);
|
||||
.button--stuff:hover {
|
||||
background-color: #7d9776;
|
||||
}
|
||||
|
||||
.prestigebtn {
|
||||
margin: 10px auto;
|
||||
width: 130px;
|
||||
height: 50px;
|
||||
border: 2px solid green;
|
||||
border-radius: 10px;
|
||||
background-color: rgb(221, 221, 221);
|
||||
color: rgb(0, 0, 0);
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
transition-duration: 0.3s;
|
||||
.button--prestige {
|
||||
background-color: #dddddd;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.prestigebtn:hover {
|
||||
background-color: rgb(141, 177, 221);
|
||||
.button--prestige:hover {
|
||||
background-color: #8db1dd;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
@ -7,11 +7,10 @@
|
||||
<title>The Depression Game</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="depression">You have <span id="amount">0</span> depression</p>
|
||||
<div id="container">
|
||||
<button id="1" class="btn" onclick="buyStuff(1)">Amount: 0<br>Cost:1</button>
|
||||
</div>
|
||||
<div id="depression"></div>
|
||||
</body>
|
||||
<script type="text/javascript" src="../javascripts/lib/vue.min.js"></script>
|
||||
<script type="text/javascript" src="../javascripts/lib/break_infinity.min.js"></script>
|
||||
<script type="text/javascript" src="../javascripts/lib/ad-notations.min.js"></script>
|
||||
<script type="text/javascript" src="depression.js"></script>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -1,172 +1,308 @@
|
||||
"use strict";
|
||||
|
||||
const UPDATE_INTERVAL = 33;
|
||||
const SAVE_INTERVAL = 5000;
|
||||
const notation = new ADNotations.ScientificNotation();
|
||||
|
||||
let uiUpdateHooks = [];
|
||||
|
||||
function updateUI() {
|
||||
for (const hook of uiUpdateHooks) {
|
||||
hook.update();
|
||||
}
|
||||
}
|
||||
|
||||
let game = {
|
||||
costs: [new Decimal(1)],
|
||||
amounts: [new Decimal(0)],
|
||||
purchases: [new Decimal(0)],
|
||||
depression: new Decimal(1),
|
||||
prestige: [new Decimal(1)]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
function formatValue(x, places) {
|
||||
if (x instanceof Decimal) {
|
||||
if (x.lt(1000)) return x.toFixed(0);
|
||||
else return (x.m.toFixed(places) + "e" + x.e)
|
||||
class StuffState {
|
||||
constructor(id) {
|
||||
this._id = id;
|
||||
}
|
||||
const power = Math.floor(Math.log10(x))
|
||||
const matissa = x / Math.pow(10, power)
|
||||
if (x < 1000) return x.toString()
|
||||
else return ((matissa).toFixed(places) + "e" + power)
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
function insertAfter(newElement,targetElement) {
|
||||
// target is what you want it to go after. Look for this elements parent.
|
||||
const parent = targetElement.parentNode;
|
||||
get previousStuff() {
|
||||
return this.id > 1 ? Stuff(this.id - 1) : undefined;
|
||||
}
|
||||
|
||||
// if the parents lastchild is the targetElement...
|
||||
if (parent.lastChild == targetElement) {
|
||||
// add the newElement after the target element.
|
||||
parent.appendChild(newElement);
|
||||
get nextStuff() {
|
||||
return Stuff(this.id + 1);
|
||||
}
|
||||
|
||||
get isUnlocked() {
|
||||
return Stuffs.count >= this.id;
|
||||
}
|
||||
|
||||
get amount() {
|
||||
return game.amounts[this.id - 1];
|
||||
}
|
||||
|
||||
set amount(value) {
|
||||
game.amounts[this.id - 1] = value;
|
||||
}
|
||||
|
||||
get purchases() {
|
||||
return game.purchases[this.id - 1];
|
||||
}
|
||||
|
||||
set purchases(value) {
|
||||
game.purchases[this.id - 1] = value;
|
||||
}
|
||||
|
||||
get cost() {
|
||||
const baseCost = Decimal.pow(100, this.id - 1);
|
||||
const costIncrease = Decimal.pow(2, this.purchases);
|
||||
return baseCost.times(costIncrease);
|
||||
}
|
||||
|
||||
get isAffordable() {
|
||||
return game.depression.gte(this.cost);
|
||||
}
|
||||
|
||||
purchase() {
|
||||
if (!this.isAffordable) return;
|
||||
game.depression = game.depression.minus(this.cost);
|
||||
const nextStuff = this.nextStuff;
|
||||
if (!nextStuff.isUnlocked) {
|
||||
nextStuff.amount = new Decimal(0);
|
||||
nextStuff.purchases = new Decimal(0);
|
||||
nextStuff.prestige = new Decimal(1);
|
||||
}
|
||||
this.amount = this.amount.plus(1).max(this.amount.times(1.05).min(nextStuff.amount.times(10000)));
|
||||
this.purchases = this.purchases.plus(1);
|
||||
updateUI();
|
||||
}
|
||||
|
||||
get prestige() {
|
||||
return game.prestige[this.id - 1];
|
||||
}
|
||||
|
||||
set prestige(value) {
|
||||
game.prestige[this.id - 1] = Decimal.max(this.prestige, value);
|
||||
}
|
||||
|
||||
get canPrestige() {
|
||||
return Stuff(this.id + 6).isUnlocked;
|
||||
}
|
||||
|
||||
get nextPrestige() {
|
||||
return Decimal.max(Stuffs.count - this.id - 5, 1);
|
||||
}
|
||||
|
||||
doPrestige() {
|
||||
this.prestige = this.nextPrestige;
|
||||
game = {
|
||||
amounts: [new Decimal(0)],
|
||||
purchases: [new Decimal(0)],
|
||||
depression: new Decimal(1),
|
||||
prestige: game.prestige
|
||||
};
|
||||
updateUI();
|
||||
}
|
||||
|
||||
tick() {
|
||||
const production = this.amount.times(this.prestige.dividedBy(UPDATE_INTERVAL));
|
||||
if (this.id === 1) {
|
||||
game.depression = game.depression.plus(production);
|
||||
} else {
|
||||
// else the target has siblings, insert the new element between the target and it's next sibling.
|
||||
parent.insertBefore(newElement, targetElement.nextSibling);
|
||||
this.previousStuff.amount = this.previousStuff.amount.plus(production);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Stuff = id => new StuffState(id);
|
||||
|
||||
|
||||
function buyStuff(id) {
|
||||
const elem = document.getElementById(id)
|
||||
var i = id-1
|
||||
|
||||
if (game.depression.gte(game.costs[i])) {
|
||||
const next = document.getElementById(id+1)
|
||||
if (next == null) {
|
||||
const btn = document.createElement("button")
|
||||
const br = document.createElement("br")
|
||||
btn.innerHTML = "Amount: 0<br>Cost:"+formatValue(game.costs[i].times(100), 2)
|
||||
btn.id = id+1
|
||||
btn.className = "btn"
|
||||
btn.onclick = function() {buyStuff(id+1);}
|
||||
insertAfter(br, elem)
|
||||
insertAfter(btn, br)
|
||||
game.costs.push(game.costs[i].times(100))
|
||||
game.amounts.push(new Decimal(0))
|
||||
if (game.prestige[id] === undefined) game.prestige[id] = 1
|
||||
|
||||
if (id > 5) {
|
||||
const pbtn = document.createElement("button")
|
||||
const otherbtn = document.getElementById(id-5)
|
||||
pbtn.id = id-5+"prestige"
|
||||
pbtn.className = "prestigebtn"
|
||||
pbtn.onclick = function() {prestige(parseInt(this.id));}
|
||||
insertAfter(pbtn, otherbtn)
|
||||
for (var i=1; i<game.costs.length-5; i++) document.getElementById(i+"prestige").innerHTML = "Reset to increase bonus to "+Math.max(game.costs.length-i-5, game.prestige[id-1])+"x boost."
|
||||
const Stuffs = {
|
||||
get count() {
|
||||
return game.amounts.length;
|
||||
},
|
||||
get unlocked() {
|
||||
return Stuffs.range(Stuffs.count);
|
||||
},
|
||||
range(count) {
|
||||
const stuffs = [];
|
||||
for (let i = 1; i < count + 1; i++) {
|
||||
stuffs.push(Stuff(i));
|
||||
}
|
||||
|
||||
|
||||
|
||||
return stuffs;
|
||||
},
|
||||
tick() {
|
||||
for (const stuff of Stuffs.unlocked) {
|
||||
stuff.tick();
|
||||
}
|
||||
},
|
||||
get last() {
|
||||
return Stuff(Stuffs.count);
|
||||
}
|
||||
game.amounts[i] = game.amounts[i].plus(1).max(game.amounts[i].times(1.05).min(game.amounts[id].times(10000)))
|
||||
game.depression = game.depression.minus(game.costs[i])
|
||||
game.costs[i] = game.costs[i].times(2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function hardreset() {
|
||||
game = {
|
||||
costs: [new Decimal(1)],
|
||||
amounts: [new Decimal(0)],
|
||||
depression: new Decimal(1),
|
||||
prestige: [1]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function prestige(id) {
|
||||
console.log(id)
|
||||
game.prestige[id-1] = Math.max(game.costs.length-id-5, game.prestige[id-1])
|
||||
for (var i=2; i<=game.costs.length; i++) {
|
||||
var btn = document.getElementById(i)
|
||||
btn.parentNode.removeChild(btn)
|
||||
}
|
||||
var prestiges = document.getElementsByClassName("prestigebtn")
|
||||
while(prestiges[0]) prestiges[0].parentNode.removeChild(prestiges[0])
|
||||
const brs = document.getElementsByTagName("br")
|
||||
while(brs[0]) brs[0].parentNode.removeChild(brs[0])
|
||||
game = {
|
||||
costs: [new Decimal(1)],
|
||||
amounts: [new Decimal(0)],
|
||||
depression: new Decimal(1),
|
||||
prestige: game.prestige
|
||||
}
|
||||
for (var i=1; i<game.costs.length-5; i++) document.getElementById(i+"prestige").innerHTML = "Reset to increase bonus to "+Math.max(game.costs.length-id-5, game.prestige[id-1])+"x boost."
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function save() {
|
||||
localStorage.setItem("funsave",JSON.stringify(game));
|
||||
localStorage.setItem("funsave", JSON.stringify(game));
|
||||
}
|
||||
|
||||
function load() {
|
||||
var save = JSON.parse(localStorage.getItem("funsave"))
|
||||
if (save) game = save
|
||||
var elem = document.getElementById("1")
|
||||
for (var i=1; i<game.costs.length; i++) {
|
||||
var btn = document.createElement("button")
|
||||
var br = document.createElement("br")
|
||||
btn.innerHTML = "Amount: 0<br>Cost:"+formatValue(game.costs[i])
|
||||
btn.id = i+1
|
||||
btn.className = "btn"
|
||||
btn.onclick = function() {buyStuff(parseInt(this.id));}
|
||||
insertAfter(br, elem)
|
||||
insertAfter(btn, br)
|
||||
elem = btn
|
||||
const saveData = JSON.parse(localStorage.getItem("funsave"));
|
||||
if (saveData === null) return;
|
||||
saveData.depression = new Decimal(saveData.depression);
|
||||
for (let i = 0; i < Object.keys(saveData.amounts).length; i++) {
|
||||
saveData.amounts[i] = new Decimal(saveData.amounts[i]);
|
||||
}
|
||||
for (var i=1; i<game.costs.length-5; i++) {
|
||||
var pbtn = document.createElement("button")
|
||||
var otherbtn = document.getElementById(i)
|
||||
pbtn.innerHTML = "Reset to increase bonus to "+Math.max(game.costs.length-i-5, game.prestige[i-1])+"x boost."
|
||||
pbtn.id = i+"prestige"
|
||||
pbtn.className = "prestigebtn"
|
||||
pbtn.onclick = function() {prestige(parseInt(this.id));}
|
||||
insertAfter(pbtn, otherbtn)
|
||||
for (let i = 0; i < Object.keys(saveData.prestige).length; i++) {
|
||||
saveData.prestige[i] = new Decimal(saveData.prestige[i]);
|
||||
}
|
||||
game.depression = new Decimal(game.depression)
|
||||
for (var i=0; i<Object.keys(game.amounts).length; i++) {
|
||||
game.amounts[i] = new Decimal(game.amounts[i])
|
||||
if (saveData.purchases !== undefined) {
|
||||
for (let i = 0; i < Object.keys(saveData.purchases).length; i++) {
|
||||
saveData.purchases[i] = new Decimal(saveData.purchases[i]);
|
||||
}
|
||||
}
|
||||
for (var i=0; i<Object.keys(game.costs).length; i++) {
|
||||
game.costs[i] = new Decimal(game.costs[i])
|
||||
if (saveData.costs !== undefined) {
|
||||
saveData.purchases = [];
|
||||
for (let i = 0; i < Object.keys(saveData.costs).length; i++) {
|
||||
const cost = new Decimal(saveData.costs[i]);
|
||||
const baseCost = Decimal.pow(100, i);
|
||||
const costIncrease = cost.dividedBy(baseCost);
|
||||
saveData.purchases[i] = Decimal.floor(Decimal.log2(costIncrease)).max(0);
|
||||
}
|
||||
}
|
||||
game = saveData;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let cheat = false;
|
||||
|
||||
function gameLoop() {
|
||||
Stuffs.tick();
|
||||
|
||||
var cheat = false;
|
||||
|
||||
|
||||
setInterval(function() {
|
||||
game.depression = game.depression.plus(game.amounts[0].times(game.prestige[0]/33))
|
||||
document.getElementById("1").innerHTML = "Amount: "+formatValue(game.amounts[0], 2)+"<br>Power: "+formatValue(game.prestige[0], 2)+"x<br>Cost:"+formatValue(game.costs[0], 2)
|
||||
for (var i=2; i <= game.costs.length; i++) {
|
||||
document.getElementById(i).innerHTML = "Amount: "+formatValue(game.amounts[i-1], 2)+"<br>Power: "+formatValue(game.prestige[i-1], 2)+"x<br>Cost:"+formatValue(game.costs[i-1], 2)
|
||||
game.amounts[i-2] = game.amounts[i-2].plus(game.amounts[i-1].times(game.prestige[i-1]/33))
|
||||
}
|
||||
|
||||
if (cheat) {
|
||||
if (game.amounts[game.amounts.length-2] < 5) document.getElementById(game.amounts.length-1).click()
|
||||
document.getElementById(game.amounts.length).click()}
|
||||
|
||||
document.getElementById("amount").innerHTML = formatValue(game.depression, 2)
|
||||
}, 33)
|
||||
const preLastStuff = Stuffs.last.previousStuff;
|
||||
if (preLastStuff !== undefined && preLastStuff.amount.lessThan(5)) {
|
||||
preLastStuff.purchase();
|
||||
}
|
||||
Stuffs.last.purchase();
|
||||
}
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
setInterval(function() { save() }, 5000)
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
format(value, places, placesUnder1000) {
|
||||
return notation.format(value, places, placesUnder1000);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.update) {
|
||||
uiUpdateHooks.push(this);
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
uiUpdateHooks = uiUpdateHooks.filter(h => h !== this);
|
||||
}
|
||||
});
|
||||
|
||||
const StuffButton = {
|
||||
props: {
|
||||
stuff: Object
|
||||
},
|
||||
data: () => ({
|
||||
amount: new Decimal(0),
|
||||
cost: new Decimal(0),
|
||||
prestige: new Decimal(1)
|
||||
}),
|
||||
methods: {
|
||||
update() {
|
||||
if (!this.stuff.isUnlocked) return;
|
||||
this.amount.fromDecimal(this.stuff.amount);
|
||||
this.cost.fromDecimal(this.stuff.cost);
|
||||
this.prestige.fromDecimal(this.stuff.prestige);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<button class="button button--stuff" @click="stuff.purchase()">
|
||||
Amount: {{format(amount, 2)}}
|
||||
<br>
|
||||
Power: {{format(prestige, 2)}}x
|
||||
<br>
|
||||
Cost: {{format(cost, 2)}}
|
||||
</button>
|
||||
`
|
||||
};
|
||||
|
||||
const PrestigeButton = {
|
||||
props: {
|
||||
stuff: Object
|
||||
},
|
||||
data: () => ({
|
||||
canPrestige: false,
|
||||
nextPrestige: new Decimal(1)
|
||||
}),
|
||||
methods: {
|
||||
update() {
|
||||
if (!this.stuff.isUnlocked) return;
|
||||
this.canPrestige = this.stuff.canPrestige;
|
||||
this.nextPrestige.fromDecimal(this.stuff.nextPrestige);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<button v-if="canPrestige" class="button button--prestige" @click="stuff.doPrestige()">
|
||||
Reset to increase bonus to {{format(nextPrestige, 2)}}x boost.
|
||||
</button>
|
||||
`
|
||||
};
|
||||
|
||||
load()
|
||||
const Depression = {
|
||||
components: {
|
||||
"stuff-button": StuffButton,
|
||||
"prestige-button": PrestigeButton
|
||||
},
|
||||
data: () => ({
|
||||
depression: new Decimal(1),
|
||||
stuffCount: 0
|
||||
}),
|
||||
computed: {
|
||||
stuffs() {
|
||||
return Stuffs.range(this.stuffCount);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.depression.fromDecimal(game.depression);
|
||||
this.stuffCount = Stuffs.count;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="app">
|
||||
<p class="depression">You have <span class="depression-amount">{{format(depression, 2)}}</span> depression</p>
|
||||
<div class="stuff-container">
|
||||
<template v-for="stuff in stuffs">
|
||||
<br v-if="stuff.id > 1">
|
||||
<stuff-button :stuff="stuff"/>
|
||||
<prestige-button :stuff="stuff"/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
|
||||
let vue;
|
||||
|
||||
window.onload = () => {
|
||||
load();
|
||||
setInterval(gameLoop, UPDATE_INTERVAL);
|
||||
setInterval(save, SAVE_INTERVAL);
|
||||
vue = new Vue({
|
||||
el: "#depression",
|
||||
components: {
|
||||
depression: Depression
|
||||
},
|
||||
template: "<depression/>"
|
||||
});
|
||||
};
|
||||
|
Before Width: | Height: | Size: 199 KiB |
Before Width: | Height: | Size: 615 KiB After Width: | Height: | Size: 744 KiB |
BIN
images/celestial-navigation-bg.png
Normal file
After Width: | Height: | Size: 3.6 MiB |
BIN
images/kred_single.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
images/loading.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
BIN
images/std_coin.png
Normal file
After Width: | Height: | Size: 586 KiB |
107
index.html
@ -40,7 +40,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<img id="loading" src="images/Loading.png">
|
||||
<div id="loading"></div>
|
||||
<div id="ui"></div>
|
||||
<div id="background-animations">
|
||||
<div class="videocontainer videocontainer--background">
|
||||
@ -48,10 +48,10 @@
|
||||
<source src="images/s6-bg.webm" type="video/webm">
|
||||
</video>
|
||||
</div>
|
||||
<div id="snow" style="display: none; "></div>
|
||||
<div id="snow" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="videocontainer">
|
||||
<video preload muted id="realityanimbg" style="opacity: 0; display: none; ">
|
||||
<video preload muted id="realityanimbg" style="opacity: 0; display: none;">
|
||||
<source src="images/realityanimbg.webm" type="video/webm">
|
||||
</video>
|
||||
</div>
|
||||
@ -62,7 +62,6 @@
|
||||
<script type="text/javascript" src="javascripts/lib/v-tooltip.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/mousetrap.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/break_infinity.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/chart.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/lz-string.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/vis-network.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/sha512.min.js"></script>
|
||||
@ -80,6 +79,7 @@
|
||||
<script type="text/javascript" src="javascripts/lib/active-line.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/closebrackets.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/ad-notations.min.js"></script>
|
||||
<script type="text/javascript" src="javascripts/lib/svg-pan-zoom.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="PlayFab/PlayFabClientApi.js"></script>
|
||||
<script type="text/javascript" src="javascripts/DragDropTouch.js"></script>
|
||||
@ -94,14 +94,20 @@
|
||||
<script type="text/javascript" src="javascripts/core/math.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/async-utils.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/effect.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/game-mechanic.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/puchasable.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/set-purchasable.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/bit-purchasable.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanics/rebuyable.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/automator/automator-backend.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/game-database.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/glyph-effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/player.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/performance-stats.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/currency.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/game-mechanic.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/event-hub.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/cache.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/intervals.js"></script>
|
||||
@ -122,12 +128,14 @@
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/storage/serializer.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/storage/storage.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/storage/migrations.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/storage/migrations.js?1"></script>
|
||||
<script type="text/javascript" src="javascripts/core/storage/dev-migrations.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/notations.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/tutorial.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/tabs.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/tabs.js?1"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/tab-notifications.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/news.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/sounds.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/achievements/normal-achievements.js"></script>
|
||||
@ -149,10 +157,12 @@
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/reality/glyph-sacrifices.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/perk-shop.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/effarig.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/enslaved.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/v.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/alchemy.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/compression.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/annihilation-upgrade.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/shop-purchases.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/navigation.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/secret-formula/celestials/singularity-milestones.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/common/primary-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/common/description-display.js"></script>
|
||||
@ -169,7 +179,7 @@
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-amounts-line.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-tickspeed-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-gamma-display.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-gamespeed-display.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-big-crunch-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-new-dim-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/header/game-header-eternity-button.js"></script>
|
||||
@ -179,30 +189,28 @@
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/old-ui-subtab-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/old-ui/old-ui.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/normal/normal-dim-tab-header.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/normal/normal-dim-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/normal/normal-dim-shift-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/normal/normal-dim-galaxy-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/normal/normal-dim-tab-progress-bar.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/normal/normal-dim-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/antimatter/antimatter-dim-tab-header.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/antimatter/antimatter-dim-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/antimatter/antimatter-dim-shift-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/antimatter/antimatter-dim-galaxy-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/antimatter/antimatter-dim-tab-progress-bar.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/antimatter/antimatter-dim-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/infinity/infinity-dim-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/infinity/infinity-dim-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/time/time-dim-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/time/time-dim-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/dimensions/dim-production-tab.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/options/options-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/options/options-button-grid.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/options/options-saving-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/options/options-visual-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/options/options-gameplay-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/options/select-notation.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/options/select-theme.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/statistics/statistics-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/challenges/challenge-records-list.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/challenges/challenge-records-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/runs/past-runs-container.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/runs/past-runs-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/runs/past-infinities-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/runs/past-eternities-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/statistics/runs/past-realities-tab.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/achievements/normal/normal-achievement.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/achievements/normal/normal-achievement-row.js"></script>
|
||||
@ -214,6 +222,7 @@
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/celestials/modal-celestial-quote.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/celestial-quote-history.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/navigation.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/teresa/teresa-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/teresa/perk-shop-upgrade.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/effarig/effarig-tab.js"></script>
|
||||
@ -223,12 +232,16 @@
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/ra-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/ra-pet.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/ra-pet-level-bar.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/ra-pet-recollection-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/ra-upgrade-icon.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/ra-level-chevron.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/alchemy-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/alchemy-resource-info.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/alchemy-circle-node.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/reality-glyph-creation.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/laitela-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/laitela/singularity-milestone.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/laitela/singularity-milestones-modal.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/laitela/laitela-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/pelle-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/matter-dimension-row.js"></script>
|
||||
|
||||
@ -239,10 +252,9 @@
|
||||
<script type="text/javascript" src="javascripts/core/celestials/V.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/ra/ra.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/ra/alchemy.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/ra/compression.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/laitela/laitela.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/laitela/matter_dimension.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/laitela/annihilation-upgrades.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/laitela/singularity.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/celestials/celestials.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/challenges/challenge-box.js"></script>
|
||||
@ -276,12 +288,14 @@
|
||||
<script type="text/javascript" src="javascripts/components/infinity/replicanti/replicanti-gain-text.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/infinity/replicanti/replicanti-galaxy-button.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/eternity/eternity-points-header.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/rem.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/time-study.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/secret-time-study.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/normal-time-study.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/ec-time-study.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/dilation-time-study.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/triad-time-study.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/time-study-connection.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/time-studies/time-studies-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/upgrades/eternity-upgrade-button.js"></script>
|
||||
@ -293,9 +307,6 @@
|
||||
<script type="text/javascript" src="javascripts/components/eternity/dilation/dilation-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/dilation/dilation-upgrade.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/eternity/dilation/tachyon-particles.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/time-compression-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/compression-upgrade.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/celestials/subtabs/ra/compression-button.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/reality/reality-machines-header.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/pp-label.js"></script>
|
||||
@ -304,19 +315,26 @@
|
||||
<script type="text/javascript" src="javascripts/components/reality/upgrades/reality-upgrade-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyphs-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/reality-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/reset-reality-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-levels-and-weights.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-component.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-sacrifice-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-auto-pick-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-selection.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-set-preview.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-sort-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-clean-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-header.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/equipped-glyphs.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/current-glyph-effects.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/sacrificed-glyphs.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-inventory.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/reality-amplify-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/glyphs/glyph-peek.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-animation.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-state-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-header-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-unlock-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-upgrade-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/reality/black-hole/black-hole-upgrade-row.js"></script>
|
||||
@ -337,18 +355,30 @@
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-popup.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-shortcuts.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-message.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-ui-choice.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-import.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-import-tree.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-edit-tree.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-load-game.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-std-store.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-h2p.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-progress-bar.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-delete-companion.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-start-normal-challenge.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-start-infinity-challenge.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/modal-start-eternity-challenge.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/options/modal-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/options/modal-news-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/options/modal-animation-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/options/modal-confirmation-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/options/modal-info-display-options.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/cloud/modal-cloud-conflict-record.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/cloud/modal-cloud-load-conflict.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/modals/cloud/modal-cloud-save-conflict.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/shop/shop-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/shop/shop-button.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/sidebar.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/tab-button.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/challenges/challenges-header.js"></script>
|
||||
@ -361,13 +391,11 @@
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/time-dimensions-tab/new-time-dimension-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/time-dimensions-tab/new-time-dimensions-tab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/dimensions-tab/new-galaxy-row.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/sidebar-resources/sidebar-am.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/sidebar-resources/sidebar-ip.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/sidebar-resources/sidebar-ep.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/sidebar-resources/sidebar-rm.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/new-ui/new-ui.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/components/common/news-ticker.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/failable-ec-text.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/game-ui.js"></script>
|
||||
<script type="text/javascript" src="javascripts/components/help-me.js"></script>
|
||||
|
||||
@ -378,7 +406,6 @@
|
||||
<script type="text/javascript" src="javascripts/core/automator/compiler.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/app/ui.init.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/ui/tabs.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/app/player-progress.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/app/modal.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/app/themes.js"></script>
|
||||
@ -386,13 +413,15 @@
|
||||
<script type="text/javascript" src="javascripts/core/app/ui.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/app/notify.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/achievements/normal-achievement.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/achievements/secret-achievement.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/achievements/achievement-timer.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/time.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/achievements.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/sound.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/chart.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/tickspeed.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/dimensions/dimension.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/dimensions/normal-dimension.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/dimensions/antimatter-dimension.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/dimensions/infinity-dimension.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/dimensions/time-dimension.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/dimboost.js"></script>
|
||||
@ -410,6 +439,10 @@
|
||||
<script type="text/javascript" src="javascripts/core/black_hole.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/devtools.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/kong.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/playfab.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/playfab.js?10"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/core/ui/tabs.js"></script>
|
||||
<script type="text/javascript" src="javascripts/core/ui/tab-notifications.js"></script>
|
||||
|
||||
<script type="text/javascript" src="javascripts/game.js?85"></script>
|
||||
</html>
|
||||
|
@ -19,7 +19,7 @@ Vue.component("normal-achievement-row", {
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isCompleted = this.row.every(a => a.isEnabled);
|
||||
this.isCompleted = this.row.every(a => a.isUnlocked);
|
||||
}
|
||||
},
|
||||
template:
|
||||
|
@ -66,7 +66,7 @@ Vue.component("normal-achievement", {
|
||||
:ach-tooltip="tooltip"
|
||||
@mouseenter="onMouseEnter"
|
||||
@mouseleave="onMouseLeave">
|
||||
<hint-text class="l-hint-text--achievement">{{id}}</hint-text>
|
||||
<hint-text type="achievements" class="l-hint-text--achievement">{{id}}</hint-text>
|
||||
<br>
|
||||
</div>`
|
||||
});
|
||||
|
@ -3,23 +3,56 @@
|
||||
Vue.component("normal-achievements-tab", {
|
||||
data() {
|
||||
return {
|
||||
achPower: new Decimal(0),
|
||||
achievementPower: 0,
|
||||
achCountdown: 0,
|
||||
disableAutoAchieve: false,
|
||||
isCancer: 0
|
||||
showAutoAchieve: false,
|
||||
isAutoAchieveActive: false,
|
||||
isCancer: 0,
|
||||
achMultToIDS: false,
|
||||
achMultToTDS: false,
|
||||
achMultToBH: false,
|
||||
canSwapImages: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
rows: () => Achievements.rows(1, 15),
|
||||
rows: () => Achievements.allRows,
|
||||
swapImagesButton() {
|
||||
return Theme.current().name === "S4" || this.isCancer ? "😂" : ".";
|
||||
},
|
||||
achievementMultiplierText() {
|
||||
let text = "Current achievement multiplier to ";
|
||||
if (this.achMultToIDS && this.achMultToTDS && this.achMultToBH)
|
||||
text += "Black Hole power, Antimatter, Infinity, and Time";
|
||||
else if (this.achMultToTDS && this.achMultToIDS) text += "Antimatter, Infinity, and Time";
|
||||
else if (this.achMultToTDS) text += "Antimatter and Time";
|
||||
else if (this.achMultToIDS) text += "Antimatter and Infinity";
|
||||
else text += "Antimatter";
|
||||
text += " Dimensions:";
|
||||
return text;
|
||||
},
|
||||
imageSwapperStyleObject() {
|
||||
if (this.canSwapImages) {
|
||||
return { "cursor": "pointer" };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isAutoAchieveActive(newValue) {
|
||||
player.reality.autoAchieve = newValue;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.achPower.copyFrom(Player.achievementPower);
|
||||
this.achCountdown = Achievements.timeToNextAutoAchieve();
|
||||
this.achievementPower = Achievements.power;
|
||||
this.achCountdown = Achievements.timeToNextAutoAchieve() / getGameSpeedupFactor();
|
||||
this.showAutoAchieve = player.realities > 0 && !Perk.achievementGroup6.isBought;
|
||||
this.isAutoAchieveActive = player.reality.autoAchieve;
|
||||
this.isCancer = player.secretUnlocks.cancerAchievements;
|
||||
this.achMultToIDS = Achievement(75).isUnlocked;
|
||||
this.achMultToTDS = EternityUpgrade.tdMultAchs.isBought;
|
||||
this.achMultToBH = V.has(V_UNLOCKS.ACHIEVEMENT_BH);
|
||||
this.canSwapImages = Themes.available().find(v => v.name === "S4") !== undefined && Theme.current().name !== "S4";
|
||||
},
|
||||
timeDisplay(value) {
|
||||
return timeDisplay(value);
|
||||
@ -27,29 +60,30 @@ Vue.component("normal-achievements-tab", {
|
||||
timeDisplayNoDecimals(value) {
|
||||
return timeDisplayNoDecimals(value);
|
||||
},
|
||||
toggleAutoAchieve() {
|
||||
// Negated because it happens before the v-model
|
||||
player.reality.disableAutoAchieve = !this.disableAutoAchieve;
|
||||
},
|
||||
swapImages() {
|
||||
if (Themes.available().find(v => v.name === "S4") !== undefined && Theme.current().name !== "S4") {
|
||||
if (this.canSwapImages) {
|
||||
player.secretUnlocks.cancerAchievements = !player.secretUnlocks.cancerAchievements;
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.disableAutoAchieve = player.reality.disableAutoAchieve;
|
||||
},
|
||||
template:
|
||||
`<div>
|
||||
template: `
|
||||
<div class="l-achievements-tab">
|
||||
<div class="c-subtab-option-container" v-if="showAutoAchieve">
|
||||
<primary-button-on-off
|
||||
v-model="isAutoAchieveActive"
|
||||
class="o-primary-btn--subtab-option"
|
||||
text="Auto achievement:"
|
||||
/>
|
||||
</div>
|
||||
<div class="c-achievements-tab__header">
|
||||
Current achievement multiplier on each Dimension: {{ shorten(achPower, 2, 3) }}x
|
||||
<span @click="swapImages()" style="cursor: pointer">{{ swapImagesButton }}</span>
|
||||
<span>
|
||||
{{ achievementMultiplierText }} {{ formatX(achievementPower, 2, 3) }}<span
|
||||
@click="swapImages()" :style="imageSwapperStyleObject">{{ swapImagesButton }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="achCountdown > 0" class="c-achievements-tab__header">
|
||||
Next automatic achievement in {{timeDisplayNoDecimals(achCountdown)}}
|
||||
<input type="checkbox" name="autoAchieve" v-model="disableAutoAchieve" @click="toggleAutoAchieve()"/>
|
||||
<label for="autoAchieve">Disable auto achievements</label>
|
||||
Automatically gain the next missing achievement in {{timeDisplayNoDecimals(achCountdown)}}.
|
||||
(left-to-right, top-to-bottom)
|
||||
</div>
|
||||
<div class="l-achievement-grid">
|
||||
<normal-achievement-row v-for="(row, i) in rows" :key="i" :row="row" />
|
||||
|
@ -18,7 +18,7 @@ Vue.component("secret-achievement-row", {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.on$(GameEvent.ACHIEVEMENT_UNLOCKED, this.updateState);
|
||||
this.on$(GAME_EVENT.ACHIEVEMENT_UNLOCKED, this.updateState);
|
||||
this.updateState();
|
||||
},
|
||||
methods: {
|
||||
|
@ -32,12 +32,15 @@ Vue.component("secret-achievement", {
|
||||
};
|
||||
},
|
||||
tooltip() {
|
||||
function evaluateText(prop) {
|
||||
return typeof prop === "function" ? prop() : prop;
|
||||
}
|
||||
const config = this.achievement.config;
|
||||
return this.isUnlocked ? config.tooltip : config.name;
|
||||
return this.isUnlocked ? evaluateText(config.tooltip) : config.name;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.on$(GameEvent.ACHIEVEMENT_UNLOCKED, this.updateState);
|
||||
this.on$(GAME_EVENT.ACHIEVEMENT_UNLOCKED, this.updateState);
|
||||
this.updateState();
|
||||
},
|
||||
methods: {
|
||||
@ -56,6 +59,7 @@ Vue.component("secret-achievement", {
|
||||
:style="styleObject"
|
||||
:ach-tooltip="tooltip"
|
||||
@click="onClick">
|
||||
<hint-text type="achievements" class="l-hint-text--achievement">S{{row}}{{column}}</hint-text>
|
||||
<br>
|
||||
</div>`
|
||||
});
|
||||
|
542
javascripts/components/celestials/navigation.js
Normal file
@ -0,0 +1,542 @@
|
||||
"use strict";
|
||||
|
||||
const BezTestData = {
|
||||
P0: new Vector(300, 300),
|
||||
scale: 100,
|
||||
rate: Math.log(2) / (2 * Math.PI),
|
||||
t0: 0,
|
||||
t1: Math.PI / 2,
|
||||
offset: 10,
|
||||
};
|
||||
|
||||
function cubicBezierArrayToPath(a, initialCommand = "M") {
|
||||
const prefix = `${initialCommand} ${a[0].p0.x} ${a[0].p0.y}\n`;
|
||||
const parts = a.map(b => `C ${b.p1.x} ${b.p1.y} ${b.p2.x} ${b.p2.y} ${b.p3.x} ${b.p3.y}\n`);
|
||||
return prefix + parts.join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} d
|
||||
* @param {number} d.rMajor
|
||||
* @param {number} [d.rMinor]
|
||||
* @param {number} [d.gapCenterDeg]
|
||||
* @param {number} [d.gapDeg]
|
||||
* @param {number} [d.gapAngleDeg]
|
||||
*/
|
||||
function svgRingPath(d) {
|
||||
if (!d.gapDeg) {
|
||||
if (!d.rMinor) {
|
||||
d.rMinor = 0;
|
||||
}
|
||||
return `M -0.1, ${-d.rMajor}
|
||||
a ${d.rMajor} ${d.rMajor} 0 1 0 0.2 0
|
||||
z
|
||||
m 0.2 ${d.rMajor - d.rMinor}
|
||||
a ${d.rMinor} ${d.rMinor} 0 1 1 -0.2 0
|
||||
z`;
|
||||
}
|
||||
const toRad = Math.PI / 180;
|
||||
const gapAngleDeg = d.gapAngleDeg === undefined ? d.gapDeg / 2 : d.gapAngleDeg;
|
||||
const edge0 = toRad * (d.gapCenterDeg + d.gapDeg / 2);
|
||||
const c0 = Math.cos(edge0), s0 = Math.sin(edge0);
|
||||
const edge1 = toRad * (d.gapCenterDeg - d.gapDeg / 2);
|
||||
const c1 = Math.cos(edge1), s1 = Math.sin(edge1);
|
||||
const x = d.rMajor / d.rMinor * Math.sin(toRad * (d.gapDeg / 2 - gapAngleDeg));
|
||||
const innerAngle = Math.asin(x) + toRad * gapAngleDeg;
|
||||
const edge2 = toRad * d.gapCenterDeg + innerAngle;
|
||||
const c2 = Math.cos(edge2), s2 = Math.sin(edge2);
|
||||
const edge3 = toRad * d.gapCenterDeg - innerAngle;
|
||||
const c3 = Math.cos(edge3), s3 = Math.sin(edge3);
|
||||
const big = d.gapDeg <= 180 ? 1 : 0;
|
||||
return `M ${c0 * d.rMajor - 1e-3 * s0} ${s0 * d.rMajor + 1e-3 * c0}
|
||||
A ${d.rMajor} ${d.rMajor} 0 ${big} 1 ${c1 * d.rMajor + 1e-3 * s1} ${s1 * d.rMajor - 1e-3 * c1}
|
||||
L ${c3 * d.rMinor + 1e-3 * s3} ${s3 * d.rMinor - 1e-3 * c3}
|
||||
A ${d.rMinor} ${d.rMinor} 0 ${big} 0 ${c2 * d.rMinor - 1e-3 * s2} ${s2 * d.rMinor + 1e-3 * c2}
|
||||
z`;
|
||||
}
|
||||
|
||||
const CelestialNavigationViewportCache = {
|
||||
pan: { x: 125, y: 125 },
|
||||
zoom: 0.75,
|
||||
};
|
||||
|
||||
Vue.component("celestial-navigation", {
|
||||
components: {
|
||||
"node-ring": {
|
||||
props: {
|
||||
complete: Number,
|
||||
position: Vector,
|
||||
ring: Object,
|
||||
symbol: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
symbolScale: {
|
||||
type: Number,
|
||||
default: 1.4
|
||||
},
|
||||
symbolOffset: {
|
||||
type: String,
|
||||
default: "0"
|
||||
},
|
||||
completeClass: String,
|
||||
incompleteClass: String,
|
||||
fill: String,
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
baseTransform() {
|
||||
return this.position.asTranslate();
|
||||
},
|
||||
pathData() {
|
||||
return svgRingPath(this.ring);
|
||||
},
|
||||
ringClass() {
|
||||
return this.complete >= 1 ? this.completeClass : this.incompleteClass;
|
||||
},
|
||||
symbolFontSize() {
|
||||
return this.ring.rMajor * this.symbolScale;
|
||||
},
|
||||
ringFilter() {
|
||||
return this.complete >= 1 && !this.isStacked ? "url(#completeGlow)" : "";
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<g :transform="baseTransform">
|
||||
<path :class="ringClass"
|
||||
:d="pathData"
|
||||
stroke="none" :fill="fill" :filter="ringFilter" />
|
||||
<text v-if="symbol"
|
||||
class="o-celestial-nav__symbol o-no-mouse"
|
||||
fill="#000"
|
||||
dominant-baseline="middle"
|
||||
:font-size="symbolFontSize"
|
||||
:dy="symbolOffset">{{symbol}}</text>
|
||||
</g>
|
||||
`
|
||||
},
|
||||
"node-background": {
|
||||
props: {
|
||||
position: Vector,
|
||||
ring: Object,
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
ringBackgroundTransform() {
|
||||
return this.position.asTranslate();
|
||||
},
|
||||
ringBackgroundPath() {
|
||||
return svgRingPath(this.ring);
|
||||
},
|
||||
ringBackgroundFilter() {
|
||||
return this.isStacked ? "" : "url(#backgroundGlow)";
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<path :transform="ringBackgroundTransform"
|
||||
:d="ringBackgroundPath"
|
||||
fill="rgba(0,0,0,0.75)" stroke="none"
|
||||
:filter="ringBackgroundFilter" />
|
||||
`
|
||||
},
|
||||
"node-overlay": {
|
||||
props: {
|
||||
complete: Number,
|
||||
position: Vector,
|
||||
legend: Object,
|
||||
ring: Object,
|
||||
fill: String,
|
||||
alwaysShowLegend: Boolean,
|
||||
clickAction: Function,
|
||||
},
|
||||
computed: {
|
||||
LEGEND_FONT_SIZE: () => 16,
|
||||
baseTransform() {
|
||||
return this.position.asTranslate();
|
||||
},
|
||||
pathData() {
|
||||
return svgRingPath(this.ring);
|
||||
},
|
||||
hasLegend() {
|
||||
return Boolean(this.legend) && (!this.legend.hideWhenCompleted || this.complete < 1);
|
||||
},
|
||||
legendArrowPoints() {
|
||||
const dir = Vector.unitFromDegrees(this.legend.angle);
|
||||
const pts = [dir.times(this.ring.rMajor + 2)];
|
||||
pts.push(pts[0].plus(dir.times(this.legend.diagonal)));
|
||||
pts.push(pts[1].plus(Vector.horiz(this.legend.horizontal * Math.sign(dir.x))));
|
||||
return pts;
|
||||
},
|
||||
legendArrowPointString() {
|
||||
return this.legendArrowPoints.join(" ");
|
||||
},
|
||||
legendTransform() {
|
||||
const pts = this.legendArrowPoints;
|
||||
const xDir = Math.sign(pts[2].x - pts[0].x);
|
||||
return pts[2].plus(Vector.horiz(xDir * 4)).asTranslate();
|
||||
},
|
||||
legendTextAnchor() {
|
||||
const angle = (this.legend.angle + 360) % 360;
|
||||
return angle > 90 && angle < 270 ? "end" : "start";
|
||||
},
|
||||
legendLines() {
|
||||
const data = typeof (this.legend.text) === "function"
|
||||
? this.legend.text(this.complete) : this.legend.text;
|
||||
return typeof (data) === "string" ? [data] : data;
|
||||
},
|
||||
forceHoverClass() {
|
||||
return this.alwaysShowLegend ? "o-celestial-nav__force-hover" : "";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
legendLineY(idx) {
|
||||
const spacing = Math.round(this.LEGEND_FONT_SIZE * 1.25 / 2);
|
||||
const num = this.legendLines.length;
|
||||
return (2 * idx - (num - 1)) * spacing;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<g class="o-celestial-nav__hoverable" :class="forceHoverClass"
|
||||
:transform="baseTransform"
|
||||
v-on="clickAction ? { click: clickAction } : {}">
|
||||
<path :d="pathData" class="o-celestial-nav__node-overlay" />
|
||||
<g v-if="hasLegend" class="tooltiptext">
|
||||
<polyline :points="legendArrowPointString"
|
||||
class="o-celestial-nav__legend-arrow"/>
|
||||
<!-- The ring radii are adjusted slightly to offset the stroke outside the node -->
|
||||
<path :d="pathData" class="o-celestial-nav__legend-outline" />
|
||||
<g :transform="legendTransform">
|
||||
<text class="o-celestial-nav__legend-text"
|
||||
:text-anchor="legendTextAnchor"
|
||||
dominant-baseline="middle" :font-size="LEGEND_FONT_SIZE">
|
||||
<tspan v-for="(line, idx) in legendLines" :key="idx"
|
||||
x="0" :y="legendLineY(idx)">{{line}}</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
`
|
||||
},
|
||||
"progress-connector": {
|
||||
props: {
|
||||
complete: Number,
|
||||
completeWidth: {
|
||||
type: Number,
|
||||
default: 8
|
||||
},
|
||||
incompleteWidth: {
|
||||
type: Number,
|
||||
default: 6,
|
||||
},
|
||||
fill: {
|
||||
type: String,
|
||||
default: "#5151ec",
|
||||
},
|
||||
filterName: {
|
||||
type: String,
|
||||
default: "completeGlow",
|
||||
},
|
||||
path: Curve,
|
||||
pathStart: Number,
|
||||
pathEnd: Number,
|
||||
pathPadStart: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
pathPadEnd: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
unpaddedSpan() {
|
||||
return (this.pathEnd - this.pathPadEnd) - (this.pathStart + this.pathPadStart);
|
||||
},
|
||||
incompleteStart() {
|
||||
return this.complete >= 1
|
||||
? this.pathEnd
|
||||
: this.pathStart + this.pathPadStart + this.unpaddedSpan * this.complete;
|
||||
},
|
||||
incompleteStartShape() {
|
||||
return this.shapeAt(this.incompleteStart);
|
||||
},
|
||||
completeStartShape() {
|
||||
return this.shapeAt(this.pathStart);
|
||||
},
|
||||
incompleteTransform() {
|
||||
const shape = this.incompleteStartShape;
|
||||
return `${shape.position.asTranslate()} ${shape.direction.asRotate()}`;
|
||||
},
|
||||
pathEndShape() {
|
||||
return this.shapeAt(this.pathEnd);
|
||||
},
|
||||
// In order to support gradients that fill along a completed path,
|
||||
// we render in a coordinate system that's scaled to be 0..1 from start to end
|
||||
totalPathOffsetPx() {
|
||||
return this.pathEndShape.position.minus(this.completeStartShape.position);
|
||||
},
|
||||
completeTransform() {
|
||||
const shape = this.completeStartShape;
|
||||
const scale = this.totalPathOffsetPx.length;
|
||||
return `${shape.position.asTranslate()} ${shape.direction.asRotate()} scale(${scale})`;
|
||||
},
|
||||
incompleteFadeEnd() {
|
||||
const shape = this.incompleteStartShape;
|
||||
const fadeLength = 12 / shape.derivative.length;
|
||||
return this.pathEnd > this.pathStart
|
||||
? Math.min(this.incompleteStart + fadeLength, this.pathEnd)
|
||||
: Math.max(this.incompleteStart - fadeLength, this.pathEnd);
|
||||
},
|
||||
incompleteFadePath() {
|
||||
return this.generateIncompletePath(this.incompleteStart, this.incompleteFadeEnd);
|
||||
},
|
||||
incompleteSolidPath() {
|
||||
return this.generateIncompletePath(
|
||||
this.incompleteFadeEnd - 1e-3 * (this.pathEnd - this.incompleteFadeEnd), this.pathEnd);
|
||||
},
|
||||
completePath() {
|
||||
const startShape = this.completeStartShape;
|
||||
const scale = 1 / this.totalPathOffsetPx.length;
|
||||
const tform = AffineTransform
|
||||
.translation(startShape.position.negative)
|
||||
.rotated(-startShape.direction.angle)
|
||||
.scaled(scale);
|
||||
const tStart = this.pathStart, tEnd = this.incompleteStart;
|
||||
const w = this.completeWidth;
|
||||
const insetPath = this.getOffsetPath(-w / 2, tStart, tEnd).transformedBy(tform);
|
||||
const outsetPath = this.getOffsetPath(w / 2, tEnd, tStart).transformedBy(tform);
|
||||
const endVector = this.incompleteStartShape.direction.transformedBy(tform.withoutTranslation);
|
||||
const inEnd = insetPath.path[insetPath.path.length - 1];
|
||||
const outStart = outsetPath.path[0];
|
||||
const capCP0 = inEnd.position(1).plus(endVector.times(w / 2));
|
||||
const capCP1 = outStart.position(0).plus(endVector.times(w / 2));
|
||||
const cap = `C ${capCP0.x} ${capCP0.y} ${capCP1.x} ${capCP1.y} ${outStart.p0.x} ${outStart.p0.y}\n`;
|
||||
return insetPath.toSVG("M") + cap + outsetPath.toSVG("L");
|
||||
},
|
||||
hasIncompleteSolidPath() {
|
||||
return this.incompleteFadeEnd !== this.pathEnd;
|
||||
},
|
||||
filter() {
|
||||
return `url(#${this.filterName})`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateIncompletePath(tStart, tEnd) {
|
||||
const inset = this.getOffsetPath(-this.incompleteWidth / 2, tStart, tEnd);
|
||||
const outset = this.getOffsetPath(this.incompleteWidth / 2, tEnd, tStart);
|
||||
const s0 = this.incompleteStartShape;
|
||||
const tform = AffineTransform.translation(s0.position.negative).rotated(-s0.direction.angle);
|
||||
return inset.transformedBy(tform).toSVG("M") + outset.transformedBy(tform).toSVG("L");
|
||||
},
|
||||
getOffsetPath(offset, tStart, tEnd) {
|
||||
if (this.path instanceof LinearPath) {
|
||||
return new PiecewisePath([this.path.createOffsetLine(offset, tStart, tEnd)]);
|
||||
}
|
||||
const offsetPath = new OffsetCurve(this.path, offset);
|
||||
return PiecewisePath.cubicBezierFitToCurveSection(offsetPath, tStart, tEnd);
|
||||
},
|
||||
shapeAt(t) {
|
||||
const shape = this.path.shapeAt(t);
|
||||
if (this.pathStart > this.pathEnd) {
|
||||
shape.direction = shape.direction.negative;
|
||||
shape.derivative = shape.derivative.negative;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<g>
|
||||
<g :transform="incompleteTransform">
|
||||
<path :d="incompleteFadePath"
|
||||
fill="url(#incompleteFade)" />
|
||||
<path v-if="hasIncompleteSolidPath"
|
||||
:d="incompleteSolidPath"
|
||||
fill="#888" />
|
||||
</g>
|
||||
<g :filter="filter">
|
||||
<path :transform="completeTransform"
|
||||
:fill="fill" stroke="none" :d="completePath" />
|
||||
</g>
|
||||
</g>
|
||||
`
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
nodeState: Object.keys(GameDatabase.celestials.navigation).mapToObject(
|
||||
name => name,
|
||||
() => ({
|
||||
visible: false,
|
||||
complete: 0,
|
||||
})
|
||||
),
|
||||
}),
|
||||
computed: {
|
||||
db: () => GameDatabase.celestials.navigation,
|
||||
drawOrder: () => {
|
||||
const db = GameDatabase.celestials.navigation;
|
||||
const order = [];
|
||||
for (const nodeId of Object.keys(db)) {
|
||||
const node = db[nodeId];
|
||||
if (node.connector) {
|
||||
order.push({
|
||||
nodeId,
|
||||
is: "progress-connector",
|
||||
config: node.connector,
|
||||
drawOrder: node.connector.drawOrder || CELESTIAL_NAV_DRAW_ORDER.CONNECTORS,
|
||||
});
|
||||
}
|
||||
if (node.node) {
|
||||
order.push({
|
||||
nodeId,
|
||||
is: "node-background",
|
||||
config: node.node,
|
||||
drawOrder: node.node.bgDrawOrder || CELESTIAL_NAV_DRAW_ORDER.NODE_BG,
|
||||
});
|
||||
order.push({
|
||||
nodeId,
|
||||
is: "node-ring",
|
||||
config: node.node,
|
||||
drawOrder: node.node.drawOrder || CELESTIAL_NAV_DRAW_ORDER.NODES,
|
||||
});
|
||||
order.push({
|
||||
nodeId,
|
||||
is: "node-overlay",
|
||||
config: node.node,
|
||||
drawOrder: node.node.overlayDrawOrder || CELESTIAL_NAV_DRAW_ORDER.NODE_OVERLAYS,
|
||||
});
|
||||
}
|
||||
order.sort((a, b) => a.drawOrder - b.drawOrder);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const panLimiter = function(oldPan, newPan) {
|
||||
// In the callback context, "this" is the svgPanZoom object.
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
const sizes = this.getSizes();
|
||||
const leftLimit = sizes.width - ((sizes.viewBox.x + sizes.viewBox.width) * sizes.realZoom);
|
||||
const rightLimit = -sizes.viewBox.x * sizes.realZoom;
|
||||
const topLimit = sizes.height - ((sizes.viewBox.y + sizes.viewBox.height) * sizes.realZoom);
|
||||
const bottomLimit = -sizes.viewBox.y * sizes.realZoom;
|
||||
return {
|
||||
x: Math.max(leftLimit, Math.min(rightLimit, newPan.x)),
|
||||
y: Math.max(topLimit, Math.min(bottomLimit, newPan.y))
|
||||
};
|
||||
};
|
||||
this.panZoom = svgPanZoom(this.$el, {
|
||||
controlIconsEnabled: true,
|
||||
dblClickZoomEnabled: false,
|
||||
center: false,
|
||||
fit: false,
|
||||
zoomScaleSensitivity: 0.3,
|
||||
minZoom: 0.64,
|
||||
maxZoom: 3,
|
||||
beforePan: panLimiter,
|
||||
});
|
||||
if (CelestialNavigationViewportCache.pan) this.panZoom.pan(CelestialNavigationViewportCache.pan);
|
||||
if (CelestialNavigationViewportCache.zoom) this.panZoom.zoom(CelestialNavigationViewportCache.zoom);
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.panZoom) {
|
||||
CelestialNavigationViewportCache.zoom = this.panZoom.getZoom();
|
||||
CelestialNavigationViewportCache.pan = this.panZoom.getPan();
|
||||
this.panZoom.destroy();
|
||||
delete this.panZoom;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
for (const key of Object.keys(this.db)) {
|
||||
this.nodeState[key].visible = this.db[key].visible();
|
||||
this.nodeState[key].complete = this.db[key].complete();
|
||||
}
|
||||
},
|
||||
vec(x, y) {
|
||||
return new Vector(x, y);
|
||||
},
|
||||
nodeVisibility(obj) {
|
||||
return this.nodeState[obj.nodeId].visible ? "visible" : "hidden";
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<svg height="600" width="960" class="l-celestial-navigation">
|
||||
<defs>
|
||||
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient id="incompleteFade" x1="0" x2="8" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color: #888; stop-opacity: 0"/>
|
||||
<stop offset="8" style="stop-color: #888; stop-opacity: 1.0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="fadeGrad" y2="0" x2="1">
|
||||
<stop offset="0.5" stop-color="white" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity=".5"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradTeresaEffarig" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#5151ec"/>
|
||||
<stop offset="1" stop-color="#d13737"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradEffarigEnslaved" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d13737"/>
|
||||
<stop offset="1" stop-color="#ffa337"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradEnslavedV" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#ffa337"/>
|
||||
<stop offset="1" stop-color="#ffe066"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradRaTeresa" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#9063de"/>
|
||||
<stop offset="1" stop-color="#5151ec"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradRaEffarig" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#9063de"/>
|
||||
<stop offset="1" stop-color="#d13737"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradRaEnslaved" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#9063de"/>
|
||||
<stop offset="1" stop-color="#ffa337"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradRaV" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#9063de"/>
|
||||
<stop offset="1" stop-color="#ffe066"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="gradRaLaitela" y2="0" x2="1" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#9063de"/>
|
||||
<stop offset="1" stop-color="white"/>
|
||||
</linearGradient>
|
||||
<mask id="fade" maskContentUnits="objectBoundingBox">
|
||||
<rect width="1" height="1" fill="url(#fadeGrad)"/>
|
||||
</mask>
|
||||
<filter id="completeGlow" x="-100%" y="-100%" width="300%" height="300%">
|
||||
<feGaussianBlur in="SourceGraphic" result="blurred" stdDeviation="2" />
|
||||
<feMerge>
|
||||
<feMergeNode in="blurred" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<filter id="backgroundGlow" x="-100%" y="-100%" width="300%" height="300%">
|
||||
<feGaussianBlur in="SourceGraphic" result="blurred" stdDeviation="4" />
|
||||
<feMerge>
|
||||
<feMergeNode in="blurred" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<image x="-250" y="-350" height="1503" width="1503" href="images/celestial-navigation-bg.png" />
|
||||
<g v-for="(obj, index) in drawOrder" :key="index" :visibility="nodeVisibility(obj)">
|
||||
<component :is="obj.is"
|
||||
:complete="nodeState[obj.nodeId].complete"
|
||||
v-bind="obj.config" />
|
||||
</g>
|
||||
</svg>
|
||||
`
|
||||
});
|
@ -38,21 +38,20 @@ Vue.component("effarig-tab", {
|
||||
data() {
|
||||
return {
|
||||
relicShards: 0,
|
||||
shardRarityBoost: 0,
|
||||
shardsGained: 0,
|
||||
autosacrificeUnlocked: false,
|
||||
adjusterUnlocked: false,
|
||||
autopickerUnlocked: false,
|
||||
runUnlocked: false,
|
||||
quote: "",
|
||||
quoteIdx: 0,
|
||||
isRunning: false,
|
||||
vIsFlipped: false,
|
||||
relicShardRarityAlwaysMax: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
shopUnlocks: () => [
|
||||
EffarigUnlock.adjuster,
|
||||
EffarigUnlock.autosacrifice,
|
||||
EffarigUnlock.autopicker
|
||||
EffarigUnlock.basicFilter,
|
||||
EffarigUnlock.advancedFilter
|
||||
],
|
||||
runUnlock: () => EffarigUnlock.run,
|
||||
runUnlocks: () => [
|
||||
@ -69,52 +68,75 @@ Vue.component("effarig-tab", {
|
||||
},
|
||||
runDescription() {
|
||||
return this.isRunning
|
||||
? `All dimension multipliers, gamespeed, and tickspeed are severely lowered, like dilation. Infinity power
|
||||
? `All dimension multipliers, gamespeed, and tickspeed are severely lowered, like Dilation. Infinity power
|
||||
reduces the production and gamespeed penalties and time shards reduce the tickspeed penalty. Glyph levels
|
||||
are temporarily capped to ${Effarig.glyphLevelCap}, rarity is unaffected.`
|
||||
are temporarily capped to ${Effarig.glyphLevelCap}, rarity is unaffected. You will exit Effarig's Reality
|
||||
when you complete a Layer of it for the first time.`
|
||||
: `Start Effarig's Reality; all dimension multipliers, gamespeed, and tickspeed are severely lowered, like
|
||||
dilation. Infinity power reduces the production and gamespeed penalties and time shards reduce the tickspeed
|
||||
penalty. Glyph levels are temporarily capped, rarity is unaffected.`;
|
||||
Dilation. Infinity power reduces the production and gamespeed penalties and time shards reduce the tickspeed
|
||||
penalty. Glyph levels are temporarily capped, rarity is unaffected. You will exit Effarig's Reality when you
|
||||
complete a Layer of it for the first time.`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.relicShards = player.celestials.effarig.relicShards;
|
||||
this.shardRarityBoost = Effarig.maxRarityBoost;
|
||||
this.shardsGained = Effarig.shardsGained;
|
||||
this.quote = Effarig.quote;
|
||||
this.quoteIdx = player.celestials.effarig.quoteIdx;
|
||||
this.runUnlocked = EffarigUnlock.run.isUnlocked;
|
||||
this.autosacrificeUnlocked = EffarigUnlock.autosacrifice.isUnlocked;
|
||||
this.adjusterUnlocked = EffarigUnlock.adjuster.isUnlocked;
|
||||
this.autopickerUnlocked = EffarigUnlock.autopicker.isUnlocked;
|
||||
this.isRunning = Effarig.isRunning;
|
||||
this.vIsFlipped = V.isFlipped;
|
||||
this.relicShardRarityAlwaysMax = Ra.has(RA_UNLOCKS.EXTRA_CHOICES_AND_RELIC_SHARD_RARITY_ALWAYS_MAX);
|
||||
},
|
||||
startRun() {
|
||||
if (this.isRunning) startRealityOver();
|
||||
else Effarig.startRun();
|
||||
if (!resetReality()) return;
|
||||
Effarig.initializeRun();
|
||||
},
|
||||
nextQuote() {
|
||||
Effarig.nextQuote();
|
||||
},
|
||||
hasNextQuote() {
|
||||
return this.quoteIdx < Effarig.maxQuoteIdx;
|
||||
createCursedGlyph() {
|
||||
if (Glyphs.freeInventorySpace === 0) {
|
||||
Modal.message.show("Inventory cannot hold new glyphs. Delete/sacrifice (shift-click) some glyphs.");
|
||||
return;
|
||||
}
|
||||
const cursedCount = player.reality.glyphs.active
|
||||
.concat(player.reality.glyphs.inventory)
|
||||
.filter(g => g !== null && g.type === "cursed")
|
||||
.length;
|
||||
if (cursedCount >= 5) {
|
||||
GameUI.notify.error("You don't need any more cursed glyphs!");
|
||||
} else {
|
||||
Glyphs.addToInventory(GlyphGenerator.cursedGlyph());
|
||||
GameUI.notify.error("Created a cursed glyph");
|
||||
}
|
||||
this.emitClose();
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-teresa-celestial-tab">
|
||||
template: `
|
||||
<div class="l-teresa-celestial-tab">
|
||||
<celestial-quote-history celestial="effarig"/>
|
||||
<div class="c-effarig-relics">You have {{ shorten(relicShards, 2, 0) }} Relic Shards.</div>
|
||||
<div class="c-effarig-relic-description">
|
||||
You will gain {{ shorten(shardsGained, 2, 0) }} Relic Shards next reality. More EP slightly increases <br>
|
||||
shards gained. More distinct glyph effects significantly increases shards gained.
|
||||
</div>
|
||||
<div class="l-effarig-shop-and-run">
|
||||
<div class="l-effarig-shop">
|
||||
<div class="c-effarig-relics">
|
||||
You have {{ format(relicShards, 2, 0) }} Relic Shards, which increases <br>
|
||||
the rarity of new glyphs by {{ relicShardRarityAlwaysMax ? "" : "up to" }}
|
||||
+{{ format(shardRarityBoost, 2, 2) }}%.
|
||||
</div>
|
||||
<div class="c-effarig-relic-description">
|
||||
You will gain {{ format(shardsGained, 2, 0) }} Relic Shards next reality. More EP slightly increases <br>
|
||||
shards gained. More distinct glyph effects significantly increases shards gained.
|
||||
</div>
|
||||
<effarig-unlock-button
|
||||
v-for="(unlock, i) in shopUnlocks"
|
||||
:key="i"
|
||||
:unlock="unlock" />
|
||||
<effarig-unlock-button v-if="!runUnlocked" :unlock="runUnlock" />
|
||||
<button
|
||||
class="c-effarig-shop-button c-effarig-shop-button--available"
|
||||
@click="createCursedGlyph"
|
||||
v-if="vIsFlipped"
|
||||
>
|
||||
Get a cursed glyph...
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="runUnlocked" class="l-effarig-run">
|
||||
<div class="c-effarig-run-description">
|
||||
@ -133,4 +155,4 @@ Vue.component("effarig-tab", {
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
||||
});
|
||||
|
@ -4,14 +4,16 @@ Vue.component("effarig-unlock-button", {
|
||||
props: {
|
||||
unlock: Object
|
||||
},
|
||||
data: function() {
|
||||
data() {
|
||||
return {
|
||||
isBought: false
|
||||
isBought: false,
|
||||
isAvailable: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isBought = this.unlock.isUnlocked;
|
||||
this.isAvailable = Effarig.shardAmount >= this.unlock.cost;
|
||||
},
|
||||
purchase() {
|
||||
this.unlock.purchase();
|
||||
@ -20,14 +22,17 @@ Vue.component("effarig-unlock-button", {
|
||||
computed: {
|
||||
config() {
|
||||
return this.unlock.config;
|
||||
},
|
||||
classObject() {
|
||||
return {
|
||||
"c-effarig-shop-button": true,
|
||||
"c-effarig-shop-button--bought": this.isBought,
|
||||
"c-effarig-shop-button--available": this.isAvailable && !this.isBought
|
||||
};
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<button
|
||||
class="o-effarig-shop-button"
|
||||
:class="{ 'effarig-unlock-bought': isBought }"
|
||||
@click="purchase"
|
||||
>
|
||||
<button :class="classObject" @click="purchase">
|
||||
<description-display :config="config"/>
|
||||
<cost-display
|
||||
v-if="!isBought"
|
||||
|
@ -1,14 +1,140 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("modal-enslaved-hints", {
|
||||
data() {
|
||||
return {
|
||||
currentStored: 0,
|
||||
nextHintCost: 0,
|
||||
canGetHint: false,
|
||||
shownEntries: [],
|
||||
realityHintsLeft: 0,
|
||||
glyphHintsLeft: 0,
|
||||
hints: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.currentStored = player.celestials.enslaved.stored;
|
||||
this.nextHintCost = Enslaved.nextHintCost;
|
||||
this.canGetHint = this.currentStored >= this.nextHintCost;
|
||||
this.shownEntries = [];
|
||||
|
||||
this.realityHintsLeft = Object.values(EnslavedProgress).length;
|
||||
for (const prog of Object.values(EnslavedProgress)) {
|
||||
if (prog.hasHint) {
|
||||
this.shownEntries.push([prog.hasProgress
|
||||
? prog.config.progress
|
||||
: "(You haven't figured this hint out yet)", prog.config.hint]);
|
||||
this.realityHintsLeft--;
|
||||
}
|
||||
}
|
||||
|
||||
const glyphHintCount = player.celestials.enslaved.glyphHintsGiven;
|
||||
for (let hintNum = 0; hintNum < glyphHintCount; hintNum++) {
|
||||
this.shownEntries.push(["", GameDatabase.celestials.enslaved.glyphHints[hintNum]]);
|
||||
}
|
||||
this.glyphHintsLeft = GameDatabase.celestials.enslaved.glyphHints.length - glyphHintCount;
|
||||
|
||||
this.hints = Enslaved.hintCostIncreases;
|
||||
},
|
||||
giveRealityHint(available) {
|
||||
if (available <= 0 || !Enslaved.spendTimeForHint()) return;
|
||||
Object.values(EnslavedProgress).filter(prog => !prog.hasHint).randomElement().giveHint();
|
||||
},
|
||||
giveGlyphHint(available) {
|
||||
if (available <= 0 || !Enslaved.spendTimeForHint()) return;
|
||||
player.celestials.enslaved.glyphHintsGiven++;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hintCost() {
|
||||
return `${format(TimeSpan.fromMilliseconds(this.nextHintCost).totalYears, 2)} years`;
|
||||
},
|
||||
hasProgress(id) {
|
||||
return this.progressEntries.some(entry => entry.id === id);
|
||||
},
|
||||
// Note: This calculation seems to behave extremely poorly if the goal has been raised more than 12 hints worth
|
||||
// of cost bumps and I'm not entirely sure why. There's probably a numerical issue I can't quite figure out, but
|
||||
// considering that much cost raising can't happen in practice I think I'm just going to leave it be.
|
||||
timeEstimate() {
|
||||
if (this.currentStored >= this.nextHintCost) return "";
|
||||
|
||||
// Relevant values are stored as milliseconds, so multiply the rate by 1000 to get to seconds
|
||||
const storeRate = 1000 * (Enslaved.isStoringGameTime
|
||||
? Enslaved.currentBlackHoleStoreAmountPerMs
|
||||
: getGameSpeedupFactor());
|
||||
const alreadyWaited = this.currentStored / storeRate;
|
||||
const decaylessTime = this.nextHintCost / storeRate;
|
||||
|
||||
// Check if decay is irrelevant and don't do the hard calculations if so
|
||||
const minCostEstimate = (TimeSpan.fromYears(1e40).totalMilliseconds - this.currentStored) / storeRate;
|
||||
if (TimeSpan.fromSeconds(minCostEstimate).totalDays > this.hints) {
|
||||
return `${TimeSpan.fromSeconds(minCostEstimate).toStringShort(true)}`;
|
||||
}
|
||||
|
||||
// Decay is 3x per day, but the math needs decay per second
|
||||
const K = Math.pow(3, 1 / 86400);
|
||||
const x = decaylessTime * Math.log(K) * Math.pow(K, alreadyWaited);
|
||||
const timeToGoal = productLog(x) / Math.log(K) - alreadyWaited;
|
||||
return `${TimeSpan.fromSeconds(timeToGoal).toStringShort(true)}`;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="c-reality-glyph-creation">
|
||||
<modal-close-button @click="emitClose"/>
|
||||
<div>
|
||||
This Reality seems to be resisting your efforts to complete it. So far you have done the following:
|
||||
</div><br>
|
||||
<div v-for="entry in shownEntries">
|
||||
<div v-if="entry[0]">
|
||||
<b>{{ entry[0] }}</b>
|
||||
<br>
|
||||
- {{ entry[1] }}
|
||||
</div>
|
||||
<div v-else>
|
||||
* <i>Glyph hint: {{ entry[1] }}</i>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<div v-if="realityHintsLeft + glyphHintsLeft > 0">
|
||||
You can spend some time looking for some more cracks in the Reality, but every hint you spend time on
|
||||
will increase the time needed for the next by a factor of {{ formatInt(3) }}. This cost bump will
|
||||
gradually go away over {{ formatInt(24) }} hours and figuring out what the hint means will immediately
|
||||
divide the cost by {{ formatInt(2) }}. The cost can't be reduced below {{ format(1e40) }} years.
|
||||
<br>
|
||||
<br>
|
||||
The next hint requires {{ hintCost }} stored in your Black Hole, which will be used up.
|
||||
<span v-if="currentStored < nextHintCost">
|
||||
You will reach this if you charge your Black Hole for {{ timeEstimate }}.
|
||||
</span>
|
||||
<br>
|
||||
<br>
|
||||
<button class="o-primary-btn"
|
||||
:class="{ 'o-primary-btn--disabled': realityHintsLeft <= 0 || !canGetHint }"
|
||||
v-on:click="giveRealityHint(realityHintsLeft)">
|
||||
Get a hint about the Reality itself ({{ formatInt(realityHintsLeft) }} left)
|
||||
</button>
|
||||
<br>
|
||||
<button class="o-primary-btn"
|
||||
:class="{ 'o-primary-btn--disabled': glyphHintsLeft <= 0 || !canGetHint }"
|
||||
v-on:click="giveGlyphHint(glyphHintsLeft)">
|
||||
Get a hint on what glyphs to use ({{ formatInt(glyphHintsLeft) }} left)
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
There are no more hints left!
|
||||
</div>
|
||||
</div>`,
|
||||
});
|
||||
|
||||
Vue.component("enslaved-tab", {
|
||||
data: () => ({
|
||||
isStoringBlackHole: false,
|
||||
isStoringReal: false,
|
||||
autoStoreReal: false,
|
||||
hasAmplifyStoredReal: false,
|
||||
canAdjustStoredTime: false,
|
||||
storedFraction: 0,
|
||||
inEnslaved: false,
|
||||
isRunning: false,
|
||||
completed: false,
|
||||
storedBlackHole: 0,
|
||||
storedReal: 0,
|
||||
@ -17,14 +143,12 @@ Vue.component("enslaved-tab", {
|
||||
autoRelease: false,
|
||||
autoReleaseSpeed: 0,
|
||||
unlocks: [],
|
||||
buyableUnlocks: [],
|
||||
quote: "",
|
||||
quoteIdx: 0,
|
||||
currentSpeedUp: 0
|
||||
currentSpeedUp: 0,
|
||||
hintsUnlocked: false
|
||||
}),
|
||||
computed: {
|
||||
amplifiedGameDesc() {
|
||||
return `${formatPow(RA_UNLOCKS.IMPROVED_STORED_TIME.effect.gameTimeAmplification(), 2, 2)}`;
|
||||
},
|
||||
storedRealEfficiencyDesc() {
|
||||
return formatPercents(this.storedRealEffiency);
|
||||
},
|
||||
@ -38,10 +162,13 @@ Vue.component("enslaved-tab", {
|
||||
return Enslaved.storedTimeInsideEnslaved(this.storedBlackHole);
|
||||
},
|
||||
realityTitle() {
|
||||
return this.inEnslaved
|
||||
return this.isRunning
|
||||
? "You're inside Enslaved Ones' Reality"
|
||||
: "Start Enslaved One's Reality";
|
||||
},
|
||||
storedTimeRate() {
|
||||
return formatPercents(this.storedFraction / 1000, 1);
|
||||
},
|
||||
sliderProps() {
|
||||
return {
|
||||
min: 0,
|
||||
@ -51,28 +178,39 @@ Vue.component("enslaved-tab", {
|
||||
width: "60rem",
|
||||
tooltip: false
|
||||
};
|
||||
},
|
||||
runButtonClassObject() {
|
||||
return {
|
||||
"c-enslaved-run-button__icon": true,
|
||||
"c-enslaved-run-button__icon--running": this.isRunning,
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
autoRelease(newValue) {
|
||||
player.celestials.enslaved.isAutoReleasing = newValue;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isStoringBlackHole = player.celestials.enslaved.isStoring;
|
||||
this.isStoringBlackHole = Enslaved.isStoringGameTime;
|
||||
this.storedBlackHole = player.celestials.enslaved.stored;
|
||||
this.isStoringReal = player.celestials.enslaved.isStoringReal;
|
||||
this.isStoringReal = Enslaved.isStoringRealTime;
|
||||
this.autoStoreReal = player.celestials.enslaved.autoStoreReal;
|
||||
this.hasAmplifyStoredReal = Ra.has(RA_UNLOCKS.IMPROVED_STORED_TIME);
|
||||
this.canAdjustStoredTime = Ra.has(RA_UNLOCKS.ADJUSTABLE_STORED_TIME);
|
||||
this.inEnslaved = Enslaved.isRunning;
|
||||
this.isRunning = Enslaved.isRunning;
|
||||
this.completed = Enslaved.isCompleted;
|
||||
this.storedReal = player.celestials.enslaved.storedReal;
|
||||
this.storedRealEffiency = Enslaved.storedRealTimeEfficiency;
|
||||
this.storedRealCap = Enslaved.storedRealTimeCap;
|
||||
this.unlocks = Array.from(player.celestials.enslaved.unlocks);
|
||||
this.buyableUnlocks = Object.values(ENSLAVED_UNLOCKS).map(x => Enslaved.canBuy(x));
|
||||
this.quote = Enslaved.quote;
|
||||
this.quoteIdx = player.celestials.enslaved.quoteIdx;
|
||||
this.storedFraction = 1000 * player.celestials.enslaved.storedFraction;
|
||||
this.autoRelease = player.celestials.enslaved.isAutoReleasing;
|
||||
this.autoReleaseSpeed = Enslaved.isAutoReleasing ? Enslaved.autoReleaseSpeed : 0;
|
||||
this.currentSpeedUp = Enslaved.currentBlackHoleStoreAmountPerMs;
|
||||
this.hintsUnlocked = EnslavedProgress.hintsUnlocked.hasProgress;
|
||||
},
|
||||
toggleStoreBlackHole() {
|
||||
Enslaved.toggleStoreBlackHole();
|
||||
@ -96,19 +234,19 @@ Vue.component("enslaved-tab", {
|
||||
Enslaved.buyUnlock(info);
|
||||
},
|
||||
startRun() {
|
||||
Enslaved.startRun();
|
||||
// This needs to be added here before the reset so that TD autobuyers don't buy too much on start
|
||||
player.celestials.enslaved.run = true;
|
||||
if (!resetReality()) return;
|
||||
Enslaved.initializeRun();
|
||||
},
|
||||
hasUnlock(info) {
|
||||
return Enslaved.has(info);
|
||||
},
|
||||
canBuyUnlock(info) {
|
||||
return Enslaved.canBuy(info);
|
||||
},
|
||||
nextQuote() {
|
||||
Enslaved.nextQuote();
|
||||
},
|
||||
hasNextQuote() {
|
||||
return this.quoteIdx < Enslaved.maxQuoteIdx;
|
||||
// This (rather than just using Enslaved.canBuy(info) and removing this.buyableUnlocks)
|
||||
// is needed for proper reactivity of button styles (e.g., if you get a level 5000 glyph
|
||||
// while on the Enslaved tab).
|
||||
return this.buyableUnlocks[info.id];
|
||||
},
|
||||
unlockClassObject(info) {
|
||||
return {
|
||||
@ -120,9 +258,6 @@ Vue.component("enslaved-tab", {
|
||||
this.storedFraction = value;
|
||||
player.celestials.enslaved.storedFraction = value / 1000;
|
||||
},
|
||||
toggleAutoRelease() {
|
||||
player.celestials.enslaved.isAutoReleasing = !player.celestials.enslaved.isAutoReleasing;
|
||||
},
|
||||
glitchStyle(x) {
|
||||
const xScale = 15 / 27;
|
||||
const yScale = 5;
|
||||
@ -135,95 +270,111 @@ Vue.component("enslaved-tab", {
|
||||
};
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-enslaved-celestial-tab">
|
||||
<celestial-quote-history celestial="enslaved"/>
|
||||
<div class="l-enslaved-top-container">
|
||||
<div class="l-enslaved-top-container__half">
|
||||
Charging your black hole
|
||||
{{ canAdjustStoredTime ? "reduces your black hole speed" : "sets your game speed to 1" }}. You can use
|
||||
time from charging to unlock Enslaved upgrades. You can also discharge it all in a single "supertick"
|
||||
which acts as if it was the duration of all of your stored time.
|
||||
<button :class="['o-enslaved-mechanic-button',
|
||||
{'o-enslaved-mechanic-button--storing-time': isStoringBlackHole }]"
|
||||
@click="toggleStoreBlackHole">
|
||||
<div class="o-enslaved-stored-time">{{ timeDisplayShort(storedBlackHole) }}</div>
|
||||
<div>{{ isStoringBlackHole ? "Charging black hole": "Charge black hole" }}</div>
|
||||
</button>
|
||||
<button class="o-enslaved-mechanic-button" @click="useStored">
|
||||
Discharge black hole
|
||||
<p v-if="inEnslaved">{{timeDisplayShort(nerfedBlackHoleTime)}} in this reality</p>
|
||||
</button>
|
||||
<div v-if="hasAmplifyStoredReal"> Amplified: {{ amplifiedGameDesc }} </div>
|
||||
</div>
|
||||
<div class="l-enslaved-top-container__half">
|
||||
Storing real time completely halts all production, setting game speed to 0. You can use stored real time to
|
||||
"amplify" a reality, simulating repeated runs of it. Amplified realities give all the rewards that normal
|
||||
realities do.
|
||||
<button :class="['o-enslaved-mechanic-button',
|
||||
{'o-enslaved-mechanic-button--storing-time': isStoringReal}]"
|
||||
@click="toggleStoreReal">
|
||||
<div class="o-enslaved-stored-time">{{ timeDisplayShort(storedReal) }}</div>
|
||||
<div>{{ isStoringReal ? "Storing real time": "Store real time" }}</div>
|
||||
</button>
|
||||
<button :class="['o-enslaved-mechanic-button',
|
||||
{'o-enslaved-mechanic-button--storing-time': autoStoreReal}]"
|
||||
@click="toggleAutoStoreReal">
|
||||
<div>{{ autoStoreReal ? "Offline time stored": "Offline time used for production" }}</div>
|
||||
</button>
|
||||
<div> Efficiency: {{ storedRealEfficiencyDesc }} </div>
|
||||
<div> Maximum: {{ storedRealCapDesc }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="canAdjustStoredTime" class="l-enslaved-shop-container">
|
||||
<ad-slider-component
|
||||
v-bind="sliderProps"
|
||||
:value="storedFraction"
|
||||
@input="adjustSlider($event)"
|
||||
/>
|
||||
</div>
|
||||
<br>
|
||||
<div v-if="canAdjustStoredTime">
|
||||
<input type="checkbox"
|
||||
id="autoReleaseBox"
|
||||
template: `
|
||||
<div class="l-enslaved-celestial-tab">
|
||||
<div class="c-subtab-option-container" v-if="canAdjustStoredTime">
|
||||
<primary-button-on-off
|
||||
v-model="autoRelease"
|
||||
:value="autoRelease"
|
||||
@input="toggleAutoRelease()">
|
||||
<label for="autoReleaseBox">Pulse black hole (uses 1% every 5 ticks)</label>
|
||||
class="o-primary-btn--subtab-option"
|
||||
text="Pulse Black Hole:"
|
||||
/>
|
||||
</div>
|
||||
<div class="l-enslaved-shop-container">
|
||||
<button
|
||||
v-for="unlock in unlocksInfo"
|
||||
:key="unlock.id"
|
||||
class="o-enslaved-shop-button"
|
||||
:class="unlockClassObject(unlock)"
|
||||
@click="buyUnlock(unlock)">
|
||||
{{ unlock.description }} <br>
|
||||
Costs: {{ timeDisplayShort(unlock.price) }}<br>
|
||||
<span v-if="isStoringBlackHole && !hasUnlock(unlock)">Time to obtain:
|
||||
{{ timeDisplayShort(timeUntilBuy(unlock.price)) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="l-enslaved-unlocks-container" v-if="hasUnlock(unlocksInfo.RUN)">
|
||||
<div class="o-enslaved-run-box">
|
||||
<div class="o-enslaved-run-box__title">{{realityTitle}}</div>
|
||||
<div v-if="completed"><b>(Completed)</b></div>
|
||||
<div class="o-enslaved-run-button" @click="startRun">
|
||||
<div class="o-enslaved-run-button__sigil fas fa-link" />
|
||||
<div v-for="x in 25" class="o-enslaved-run-button__glitch"
|
||||
:style="glitchStyle(x)"/>
|
||||
<div class="l-enslaved-celestial-tab--inner">
|
||||
<div class="l-enslaved-run-container">
|
||||
<div v-if="hasUnlock(unlocksInfo.RUN)">
|
||||
<div class="c-enslaved-run-button">
|
||||
<div class="c-enslaved-run-button__title">{{realityTitle}}</div>
|
||||
<div v-if="completed"><b>(Completed)</b></div>
|
||||
<div :class="runButtonClassObject" @click="startRun">
|
||||
<div class="c-enslaved-run-button__icon__sigil fas fa-link" />
|
||||
<div v-if="isRunning" v-for="x in 25" class="c-enslaved-run-button__icon__glitch"
|
||||
:style="glitchStyle(x)"/>
|
||||
</div>
|
||||
<p>Glyph levels will be boosted to a minimum of {{ formatInt(5000) }}</p>
|
||||
<p>Infinity, Time, and 8th Antimatter Dimension purchases are limited to {{ formatInt(1) }} each</p>
|
||||
<p>Antimatter Dimension multipliers are always Dilated (the glyph effect still only
|
||||
applies in actual Dilation)</p>
|
||||
<p>Time study 192 (uncapped Replicanti) is locked</p>
|
||||
<p>The Black Hole is disabled</p>
|
||||
<p>Tachyon production and Dilated Time production are severely reduced</p>
|
||||
<p>Time Theorem generation from Dilation glyphs is disabled</p>
|
||||
<p>Certain challenge goals have been increased</p>
|
||||
<p>Stored time is effectively Dilated (exponent^{{ format(0.55, 2, 2) }})</p>
|
||||
<b>Reward: Unlock Tesseracts, which let you increase Infinity Dimension caps
|
||||
(see Infinity Dimension tab)</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-enslaved-upgrades-column">
|
||||
<celestial-quote-history celestial="enslaved"/>
|
||||
<primary-button
|
||||
v-if="hintsUnlocked"
|
||||
class="o-primary-btn"
|
||||
onclick="Modal.enslavedHints.show()">
|
||||
Examine the Reality more closely...
|
||||
</primary-button>
|
||||
<div class="l-enslaved-top-container">
|
||||
<div class="l-enslaved-top-container__half">
|
||||
While charging, the Black Hole's speed boost is {{ canAdjustStoredTime ? "decreased" : "disabled" }},
|
||||
and the lost speed is converted into stored time. Discharging the Black Hole allows you to skip
|
||||
forward in time. Stored time is also used to unlock certain upgrades.
|
||||
<button :class="['o-enslaved-mechanic-button',
|
||||
{'o-enslaved-mechanic-button--storing-time': isStoringBlackHole }]"
|
||||
@click="toggleStoreBlackHole">
|
||||
<div class="o-enslaved-stored-time">{{ timeDisplayShort(storedBlackHole) }}</div>
|
||||
<div>{{ isStoringBlackHole ? "Charging Black Hole": "Charge Black Hole" }}</div>
|
||||
</button>
|
||||
<button class="o-enslaved-mechanic-button" @click="useStored">
|
||||
Discharge Black Hole
|
||||
<p v-if="isRunning">{{timeDisplayShort(nerfedBlackHoleTime)}} in this reality</p>
|
||||
</button>
|
||||
</div>
|
||||
<div class="l-enslaved-top-container__half">
|
||||
Storing real time completely halts all production, setting game speed to {{ formatInt(0) }}.
|
||||
You can use stored real time to "amplify" a reality, simulating repeated runs of it.
|
||||
Amplified realities give all the rewards that normal realities do.
|
||||
<button :class="['o-enslaved-mechanic-button',
|
||||
{'o-enslaved-mechanic-button--storing-time': isStoringReal}]"
|
||||
@click="toggleStoreReal">
|
||||
<div class="o-enslaved-stored-time">{{ timeDisplayShort(storedReal) }}</div>
|
||||
<div>{{ isStoringReal ? "Storing real time": "Store real time" }}</div>
|
||||
</button>
|
||||
<button :class="['o-enslaved-mechanic-button',
|
||||
{'o-enslaved-mechanic-button--storing-time': autoStoreReal}]"
|
||||
@click="toggleAutoStoreReal">
|
||||
<div>{{ autoStoreReal ? "Offline time stored": "Offline time used for production" }}</div>
|
||||
</button>
|
||||
<div> Efficiency: {{ storedRealEfficiencyDesc }} </div>
|
||||
<div> Maximum stored real time: {{ storedRealCapDesc }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="canAdjustStoredTime" class="l-enslaved-top-container__half">
|
||||
Black Hole charging rate: {{ storedTimeRate }}
|
||||
<br>
|
||||
<br>
|
||||
<ad-slider-component
|
||||
v-bind="sliderProps"
|
||||
:value="storedFraction"
|
||||
@input="adjustSlider($event)"
|
||||
/>
|
||||
</div>
|
||||
<br>
|
||||
<div class="l-enslaved-shop-container">
|
||||
<button
|
||||
v-for="unlock in unlocksInfo"
|
||||
:key="unlock.id"
|
||||
class="o-enslaved-shop-button"
|
||||
:class="unlockClassObject(unlock)"
|
||||
@click="buyUnlock(unlock)">
|
||||
{{ unlock.description() }}
|
||||
<br>
|
||||
Costs: {{ timeDisplayShort(unlock.price) }}
|
||||
<br>
|
||||
<span v-if="isStoringBlackHole && !hasUnlock(unlock)">
|
||||
Time to obtain: {{ timeDisplayShort(timeUntilBuy(unlock.price)) }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<p>Glyph levels will be boosted to a minimum of 5000</p>
|
||||
<p>Infinity, time, and 8th dimension purchases are limited to 1 each.</p>
|
||||
<p>Normal dimension multipliers are always dilated (the glyph effect still only
|
||||
applies in actual dilation)</p>
|
||||
<p>Time study 192 (uncapped replicanti) is locked</p>
|
||||
<p>The black hole is disabled</p>
|
||||
<p>Tachyon production and dilated time production are severely reduced</p>
|
||||
<p>Time theorem generation from dilation glyphs is disabled</p>
|
||||
<p>Certain challenge goals have been increased</p>
|
||||
<p>Stored time is effectively dilated (exponent^0.5)</p>
|
||||
<b>Reward: Unlock Tesseracts, which let you increase Infinity Dimension caps (see Infinity Dimension tab)</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
@ -1,130 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("laitela-tab", {
|
||||
data() {
|
||||
return {
|
||||
matter: new Decimal(0),
|
||||
nextUnlock: "",
|
||||
matterEffectPercentage: "",
|
||||
dimMultNerf: 0,
|
||||
activeDimensions: [],
|
||||
higgs: new Decimal(0),
|
||||
higgsGain: new Decimal(0),
|
||||
showReset: false,
|
||||
darkEnergyChance: 0,
|
||||
darkEnergy: 0,
|
||||
annihilated: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.matter.copyFrom(player.celestials.laitela.matter);
|
||||
this.nextUnlock = Laitela.nextMatterDimensionThreshold;
|
||||
this.matterEffectPercentage = Laitela.matterEffectPercentage;
|
||||
this.dimMultNerf = Laitela.dimMultNerf;
|
||||
this.realityReward = Laitela.realityReward;
|
||||
this.activeDimensions = Array.range(0, 4).filter(i => MatterDimension(i + 1).amount.neq(0));
|
||||
this.higgs.copyFrom(player.celestials.laitela.higgs);
|
||||
this.higgsGain.copyFrom(Laitela.higgsGain);
|
||||
this.annihilated = player.celestials.laitela.annihilated;
|
||||
this.showReset = this.annihilated || this.higgsGain.gt(0);
|
||||
this.darkEnergyChance = Laitela.darkEnergyChance;
|
||||
this.darkEnergy = player.celestials.laitela.darkEnergy;
|
||||
this.isRunning = Laitela.isRunning;
|
||||
},
|
||||
startRun() {
|
||||
if (this.isRunning) startRealityOver();
|
||||
else Laitela.startRun();
|
||||
},
|
||||
buyUnlock(info) {
|
||||
Laitela.buyUnlock(info);
|
||||
},
|
||||
hasUnlock(info) {
|
||||
return Laitela.has(info);
|
||||
},
|
||||
canBuyUnlock(info) {
|
||||
return Laitela.canBuyUnlock(info);
|
||||
},
|
||||
runButtonClassObject() {
|
||||
return {
|
||||
"o-laitela-run-button__icon": true,
|
||||
"o-laitela-run-button__icon--running": this.isRunning,
|
||||
};
|
||||
},
|
||||
unlockClassObject(upgrade) {
|
||||
return {
|
||||
"o-laitela-shop-button--bought": upgrade.isBought,
|
||||
"o-laitela-shop-button--available": upgrade.canBeBought
|
||||
};
|
||||
},
|
||||
annihilate() {
|
||||
Laitela.annihilate();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dimensions: () => MatterDimensionState.list,
|
||||
runUnlockThresholds: () => laitelaRunUnlockThresholds,
|
||||
unlocksInfo: () => LAITELA_UNLOCKS,
|
||||
upgrades: () => AnnihilationUpgrade.all,
|
||||
darkEnergyUpgrades: () => DarkEnergyUpgrade.all
|
||||
},
|
||||
template:
|
||||
`<div class="l-laitela-celestial-tab">
|
||||
<div class="o-laitela-matter-amount">You have {{ shorten(matter, 2, 0) }} Dark Matter</div>
|
||||
<div v-if="annihilated">You have {{ shorten(higgs, 2, 0)}} Higgs {{"Boson" | pluralize(higgs)}}</div>
|
||||
<div v-if="higgs.gt(0)">Which cause you to have a {{ (darkEnergyChance * 100).toFixed(3) }}% chance of generating dark energy each dimension interval</div>
|
||||
<div v-if="darkEnergy > 0">You have {{ shorten(darkEnergy, 2, 0)}} Dark Energy</div>
|
||||
<div class="l-laitela-mechanics-container">
|
||||
<div>
|
||||
<matter-dimension-row
|
||||
v-for="i in activeDimensions"
|
||||
:key="i"
|
||||
:dimension="dimensions[i]"
|
||||
/>
|
||||
<div>{{ nextUnlock }}</div>
|
||||
</div>
|
||||
<div class="l-laitela-unlocks-container" v-if="showReset">
|
||||
<button
|
||||
v-for="upgrade in upgrades"
|
||||
:key="upgrade.id"
|
||||
class="o-laitela-shop-button"
|
||||
:class="{'o-laitela-shop-button--available': upgrade.canBeBought }"
|
||||
@click="upgrade.purchase()">
|
||||
{{ upgrade.description }} <br/> Costs: <b>{{ shorten(upgrade.cost, 2, 0) }}</b> Higgs Bosons
|
||||
<br/>Currently: {{ upgrade.formattedEffect }}, Next: {{ upgrade.formattedNextEffect }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-laitela-mechanics-lower">
|
||||
<div class="l-laitela-buttons-container">
|
||||
<button class="o-laitela-run-button" @click="startRun">
|
||||
<b>Start Lai'tela's Reality</b>
|
||||
<div v-bind:class="runButtonClassObject()"></div>
|
||||
Tickspeed is disabled and all dimension multipliers are decreased based on dark matter,
|
||||
currently <b>x^{{ shorten(dimMultNerf, 3, 4) }}</b>
|
||||
<br>
|
||||
Multiply all dark matter dimensions based on highest AM reached,
|
||||
Currently: <b>{{ shorten(realityReward, 2, 3)}}x</b>
|
||||
</button>
|
||||
<button class="c-laitela-annihilation-button" @click="annihilate()" v-if="showReset">
|
||||
<h2>Annihilation</h2>
|
||||
<p>
|
||||
Resets your dark matter dimensions and Dark Matter, but gain <b>{{ shorten(higgsGain, 2, 0) }}</b>
|
||||
Higgs {{"Boson" | pluralize(higgsGain)}}
|
||||
</p>
|
||||
</button>
|
||||
</div>
|
||||
<div class="l-laitela-dark-energy-upgrades">
|
||||
<button
|
||||
v-for="upgrade in darkEnergyUpgrades"
|
||||
:key="upgrade.id"
|
||||
class="o-laitela-shop-button--dark-energy"
|
||||
:class="unlockClassObject(upgrade)"
|
||||
@click="upgrade.purchase()">
|
||||
{{ upgrade.description }} <br/> Costs: <b>{{ shorten(upgrade.cost, 2, 0) }}</b> Dark Energy
|
||||
<br/>{{ upgrade.formattedEffect }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
467
javascripts/components/celestials/subtabs/laitela/laitela-tab.js
Normal file
@ -0,0 +1,467 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("laitela-tab", {
|
||||
data() {
|
||||
return {
|
||||
matter: new Decimal(0),
|
||||
maxMatter: new Decimal(0),
|
||||
matterExtraPurchasePercentage: 0
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.matter.copyFrom(player.celestials.laitela.matter);
|
||||
this.maxMatter.copyFrom(player.celestials.laitela.maxMatter);
|
||||
this.matterExtraPurchasePercentage = Laitela.matterExtraPurchaseFactor - 1;
|
||||
},
|
||||
maxAll() {
|
||||
Laitela.maxAllDMDimensions(4);
|
||||
},
|
||||
showLaitelaHowTo() {
|
||||
ui.view.h2pForcedTab = GameDatabase.h2p.tabs.filter(tab => tab.name === "Lai'tela")[0];
|
||||
Modal.h2p.show();
|
||||
ui.view.h2pActive = true;
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div class="l-laitela-celestial-tab">
|
||||
<div class="c-subtab-option-container">
|
||||
<primary-button
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="showLaitelaHowTo()"
|
||||
>Click for Lai'tela info</primary-button>
|
||||
<primary-button
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="maxAll"
|
||||
>Max all Dark Matter Dimensions</primary-button>
|
||||
</div>
|
||||
<div class="o-laitela-matter-amount">You have {{ format(matter.floor(), 2, 0) }} Dark Matter.</div>
|
||||
<div class="o-laitela-matter-amount">Your maximum Dark Matter ever is {{ format(maxMatter.floor(), 2, 0) }},
|
||||
giving {{ formatPercents(matterExtraPurchasePercentage, 2) }} more purchases from Continuum.</div>
|
||||
<singularity-container />
|
||||
<div class="l-laitela-mechanics-container">
|
||||
<laitela-run-button />
|
||||
<div>
|
||||
<dark-matter-dimension-group />
|
||||
<annihilation-button />
|
||||
</div>
|
||||
<singularity-milestone-pane />
|
||||
</div>
|
||||
<laitela-autobuyer-settings />
|
||||
</div>`
|
||||
});
|
||||
|
||||
Vue.component("singularity-container", {
|
||||
data() {
|
||||
return {
|
||||
darkEnergy: 0,
|
||||
darkEnergyGainPerSecond: 0,
|
||||
singularities: 0,
|
||||
singularityCapIncreases: 0,
|
||||
canPerformSingularity: false,
|
||||
singularityCap: 0,
|
||||
baseTimeToSingularity: 0,
|
||||
singularitiesGained: 0,
|
||||
autoSingularityFactor: 0,
|
||||
perStepFactor: 0,
|
||||
isAutoEnabled: false,
|
||||
hasAutoSingularity: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const laitela = player.celestials.laitela;
|
||||
this.darkEnergy = laitela.darkEnergy;
|
||||
this.darkEnergyGainPerSecond = Array.range(1, 4)
|
||||
.map(n => MatterDimension(n))
|
||||
.filter(d => d.amount.gt(0))
|
||||
.map(d => d.powerDE * 1000 / d.interval)
|
||||
.sum();
|
||||
this.singularities = laitela.singularities;
|
||||
this.singularityCapIncreases = laitela.singularityCapIncreases;
|
||||
this.canPerformSingularity = Singularity.capIsReached;
|
||||
this.singularityCap = Singularity.cap;
|
||||
this.baseTimeToSingularity = this.singularityCap / this.darkEnergyGainPerSecond;
|
||||
this.singularitiesGained = Singularity.singularitiesGained;
|
||||
this.autoSingularityFactor = SingularityMilestone.autoCondense.effectValue;
|
||||
this.perStepFactor = Singularity.gainPerCapIncrease;
|
||||
this.isAutoEnabled = laitela.automation.singularity && SingularityMilestone.autoCondense.isUnlocked;
|
||||
this.hasAutoSingularity = Number.isFinite(this.autoSingularityFactor);
|
||||
},
|
||||
doSingularity() {
|
||||
Singularity.perform();
|
||||
},
|
||||
increaseCap() {
|
||||
Singularity.increaseCap();
|
||||
},
|
||||
decreaseCap() {
|
||||
Singularity.decreaseCap();
|
||||
},
|
||||
formatRate(rate) {
|
||||
if (rate < 1 / 60) return `${format(3600 * rate, 2, 3)} per hour`;
|
||||
if (rate < 1) return `${format(60 * rate, 2, 3)} per minute`;
|
||||
return `${format(rate, 2, 3)} per second`;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
singularityFormText() {
|
||||
const formText = this.singularitiesGained === 1 ? "condense all Dark Energy into a Singularity"
|
||||
: `condense all Dark Energy into ${format(this.singularitiesGained, 2, 0)} Singularities`;
|
||||
if (this.canPerformSingularity) {
|
||||
// Capitalize the string
|
||||
return `${formText.charAt(0).toUpperCase()}${formText.slice(1)}`;
|
||||
}
|
||||
return `Reach ${format(this.singularityCap)} Dark Energy to ${formText}`;
|
||||
},
|
||||
singularityWaitText() {
|
||||
let singularityTime = (this.singularityCap - this.darkEnergy) / this.darkEnergyGainPerSecond;
|
||||
if (this.canPerformSingularity) {
|
||||
singularityTime += this.singularityCap * (this.autoSingularityFactor - 1) / this.darkEnergyGainPerSecond;
|
||||
return this.isAutoEnabled
|
||||
? `(auto-condensing in ${TimeSpan.fromSeconds(singularityTime).toStringShort(false)})`
|
||||
: "";
|
||||
}
|
||||
return `(enough Dark Energy in ${TimeSpan.fromSeconds(singularityTime).toStringShort(false)})`;
|
||||
},
|
||||
baseSingularityTime() {
|
||||
return TimeSpan.fromSeconds(this.baseTimeToSingularity).toStringShort(false);
|
||||
},
|
||||
additionalSingularityTime() {
|
||||
return TimeSpan.fromSeconds(this.baseTimeToSingularity * (this.autoSingularityFactor - 1))
|
||||
.toStringShort(false);
|
||||
},
|
||||
manualSingularityRate() {
|
||||
const totalTime = this.singularityCap / this.darkEnergyGainPerSecond;
|
||||
return this.formatRate(this.singularitiesGained / totalTime);
|
||||
},
|
||||
autoSingularityRate() {
|
||||
const totalTime = this.singularityCap / this.darkEnergyGainPerSecond * this.autoSingularityFactor;
|
||||
return this.formatRate(this.singularitiesGained / totalTime);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="c-laitela-singularity-container">
|
||||
<div>
|
||||
<h2>
|
||||
You have {{ format(singularities, 2, 0) }} {{ "Singularity" | pluralize(singularities, "Singularities")}}
|
||||
</h2>
|
||||
<button
|
||||
class="c-laitela-singularity"
|
||||
:class="{ 'c-laitela-singularity--active' : canPerformSingularity }"
|
||||
@click="doSingularity">
|
||||
<h2>{{ singularityFormText }}</h2>
|
||||
<br v-if="singularityWaitText !== ''">
|
||||
<h2>{{ singularityWaitText }}</h2>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="o-laitela-matter-amount">
|
||||
You have {{ format(darkEnergy, 2, 4) }} Dark Energy. (+{{ format(darkEnergyGainPerSecond, 2, 4) }}/s)
|
||||
</div>
|
||||
<button class="c-laitela-singularity__cap-control" @click="decreaseCap">
|
||||
Decrease Singularity cap.
|
||||
</button>
|
||||
<button class="c-laitela-singularity__cap-control" @click="increaseCap">
|
||||
Increase Singularity cap.
|
||||
</button>
|
||||
<br>
|
||||
Each step increases the required Dark Energy by {{ formatX(10) }},
|
||||
<br>
|
||||
but also increases gained Singularities by {{ formatX(perStepFactor) }}.
|
||||
<br>
|
||||
<br>
|
||||
Total time to <span v-if="hasAutoSingularity">(auto-)</span>condense:
|
||||
{{ baseSingularityTime }}
|
||||
<span v-if="hasAutoSingularity && autoSingularityFactor !== 1">
|
||||
(+{{ additionalSingularityTime }})
|
||||
</span>
|
||||
<br>
|
||||
<span v-if="hasAutoSingularity && autoSingularityFactor !== 1">Manual </span>
|
||||
Singularity gain rate: {{ manualSingularityRate }}
|
||||
<br>
|
||||
<span v-if="hasAutoSingularity && autoSingularityFactor !== 1">
|
||||
Automatic Singularity gain rate: {{ autoSingularityRate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
||||
|
||||
Vue.component("laitela-run-button", {
|
||||
data() {
|
||||
return {
|
||||
realityTime: 0,
|
||||
maxDimTier: 0,
|
||||
isRunning: false,
|
||||
realityReward: 1,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.realityTime = player.celestials.laitela.fastestCompletion;
|
||||
this.maxDimTier = Laitela.maxAllowedDimension;
|
||||
this.realityReward = Laitela.realityReward;
|
||||
this.isRunning = Laitela.isRunning;
|
||||
},
|
||||
startRun() {
|
||||
if (!resetReality()) return;
|
||||
Laitela.initializeRun();
|
||||
},
|
||||
runButtonClassObject() {
|
||||
return {
|
||||
"o-laitela-run-button__icon": true,
|
||||
"o-laitela-run-button__icon--running": this.isRunning,
|
||||
};
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
completionTime() {
|
||||
return TimeSpan.fromSeconds(this.realityTime).toStringShort();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<button class="o-laitela-run-button">
|
||||
<b>Start Lai'tela's Reality</b>
|
||||
<div :class="runButtonClassObject()" @click="startRun"></div>
|
||||
<div v-if="realityReward > 1">
|
||||
<b>All DM multipliers are {{ formatX(realityReward, 2, 2) }} higher</b>
|
||||
<br>
|
||||
<br>
|
||||
Fastest Completion: {{ completionTime }}
|
||||
<br>
|
||||
<br>
|
||||
<span v-if="maxDimTier <= 7">
|
||||
Highest active dimension: {{ formatInt(maxDimTier) }}
|
||||
</span>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
Infinity Point and Eternity Point gain are Dilated. Game speed is reduced to {{ formatInt(1) }}
|
||||
and gradually comes back over {{ formatInt(10) }} minutes, and Black Hole discharging and pulsing
|
||||
is disabled.
|
||||
<br>
|
||||
<br>
|
||||
Antimatter generates entropy inside of this Reality. At {{ formatPercents(1) }} entropy, the Reality
|
||||
becomes destabilized and you gain a reward based on how quickly you reached {{ formatPercents(1) }}.
|
||||
If you can destabilize in less than {{ formatInt(30) }} seconds, the Reality becomes more difficult
|
||||
but also gives a stronger reward.
|
||||
</button>`
|
||||
});
|
||||
|
||||
Vue.component("dark-matter-dimension-group", {
|
||||
data() {
|
||||
return {
|
||||
activeDimensions: [],
|
||||
nextDimensionThreshold: 0,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.activeDimensions = Array.range(0, 4).filter(i => MatterDimension(i + 1).amount.neq(0));
|
||||
this.nextDimensionThreshold = Array.range(0, 4)
|
||||
.filter(i => MatterDimension(i + 1).amount.eq(0))
|
||||
.map(i => MatterDimension(i + 1).adjustedStartingCost)
|
||||
.min();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
dimensions: () => MatterDimensionState.list,
|
||||
},
|
||||
template: `
|
||||
<span>
|
||||
<matter-dimension-row
|
||||
v-for="i in activeDimensions"
|
||||
:key="i"
|
||||
:dimension="dimensions[i]"
|
||||
/>
|
||||
<div v-if="nextDimensionThreshold !== 0">
|
||||
<b>Next dimension unlocks at {{ format(nextDimensionThreshold) }} Dark Matter.</b>
|
||||
<br><br>
|
||||
</div>
|
||||
</span>`
|
||||
});
|
||||
|
||||
Vue.component("annihilation-button", {
|
||||
data() {
|
||||
return {
|
||||
matter: new Decimal(0),
|
||||
darkMatterMult: 0,
|
||||
darkMatterMultGain: 0,
|
||||
hasAnnihilated: false,
|
||||
showAnnihilation: false,
|
||||
matterRequirement: 0,
|
||||
darkMatterMultRatio: 0,
|
||||
autoAnnihilationInput: player.celestials.laitela.autoAnnihilationSetting,
|
||||
isEnabled: true,
|
||||
isMouseoverDisabled: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.matter.copyFrom(player.celestials.laitela.matter);
|
||||
this.darkMatterMult = Laitela.darkMatterMult;
|
||||
this.darkMatterMultGain = Laitela.darkMatterMultGain;
|
||||
this.hasAnnihilated = Laitela.darkMatterMult > 1;
|
||||
this.showAnnihilation = this.hasAnnihilated || !MatterDimensionState.list.some(d => d.amount.eq(0));
|
||||
this.matterRequirement = Laitela.annihilationDMRequirement;
|
||||
this.darkMatterMultRatio = Laitela.darkMatterMultRatio;
|
||||
this.isEnabled = player.celestials.laitela.automation.annihilation;
|
||||
},
|
||||
annihilate() {
|
||||
if (this.isMouseoverDisabled) return;
|
||||
Laitela.annihilate();
|
||||
},
|
||||
handleAutoAnnihilationInputChange() {
|
||||
const float = parseFloat(this.autoAnnihilationInput);
|
||||
if (isNaN(float)) {
|
||||
this.autoAnnihilationInput = player.celestials.laitela.autoAnnihilationSetting;
|
||||
} else {
|
||||
player.celestials.laitela.autoAnnihilationSetting = float;
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
annihilationInputStyle() {
|
||||
return {
|
||||
width: "6rem",
|
||||
"background-color": this.isEnabled ? "" : "var(--color-disabled)",
|
||||
};
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<button class="c-laitela-annihilation-button"
|
||||
@click="annihilate()"
|
||||
v-if="showAnnihilation">
|
||||
<h2>Annihilation</h2>
|
||||
<span v-if="hasAnnihilated">
|
||||
Current multiplier to all DM multipliers: <b>{{ formatX(darkMatterMult, 2, 2) }}</b>
|
||||
<br><br>
|
||||
</span>
|
||||
Resets your Dark Matter, Dark Matter Dimensions, and Dark Energy,
|
||||
<span v-if="!hasAnnihilated">
|
||||
unlocking Auto-Annihilation, and
|
||||
</span>
|
||||
<span v-if="hasAnnihilated && matter.gte(matterRequirement)">
|
||||
but adds <b>{{ format(darkMatterMultGain, 2, 2) }}</b> to your Annihilation multiplier.
|
||||
(<b>{{ formatX(darkMatterMultRatio, 2, 2) }}</b> from previous multiplier)
|
||||
</span>
|
||||
<span v-else-if="hasAnnihilated">
|
||||
adding to your current Annihilation multiplier (requires {{ format(matterRequirement) }} Dark Matter).
|
||||
</span>
|
||||
<span v-else-if="matter.gte(matterRequirement)">
|
||||
multiplying DM multipliers by <b>{{ formatX(1 + darkMatterMultGain, 2, 2) }}</b>.
|
||||
</span>
|
||||
<span v-else>
|
||||
giving a multiplier to all DM multipliers (requires {{ format(matterRequirement) }} Dark Matter).
|
||||
</span>
|
||||
<div v-if="hasAnnihilated">
|
||||
<br>
|
||||
Auto-Annihilate when adding
|
||||
<input type="text"
|
||||
v-model="autoAnnihilationInput"
|
||||
@change="handleAutoAnnihilationInputChange()"
|
||||
@mouseover="isMouseoverDisabled = true"
|
||||
@mouseleave="isMouseoverDisabled = false"
|
||||
:style="annihilationInputStyle"/>
|
||||
to the multiplier.
|
||||
</div>
|
||||
</button>`
|
||||
});
|
||||
|
||||
Vue.component("singularity-milestone-pane", {
|
||||
data() {
|
||||
return {
|
||||
milestones: [],
|
||||
hasNew: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.milestones = SingularityMilestones.nextMilestoneGroup;
|
||||
this.hasNew = SingularityMilestones.unseenMilestones.length !== 0;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
glowStyle() {
|
||||
if (this.hasNew) return { "box-shadow": "inset 0 0 1rem 0.5rem var(--color-celestials)" };
|
||||
return {};
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="c-laitela-next-milestones">
|
||||
<div class="o-laitela-singularity-modal-button"
|
||||
onclick="Modal.singularityMilestones.show()"
|
||||
:style="glowStyle">
|
||||
Show all milestones
|
||||
</div>
|
||||
<singularity-milestone
|
||||
v-for="milestone in milestones"
|
||||
:key="milestone.id"
|
||||
:milestone="milestone"
|
||||
:suppressGlow="true"/>
|
||||
</div>`
|
||||
});
|
||||
|
||||
Vue.component("laitela-autobuyer-settings", {
|
||||
data() {
|
||||
return {
|
||||
hasDimension: false,
|
||||
hasAscension: false,
|
||||
hasSingularity: false,
|
||||
hasAnnihilated: false,
|
||||
dimension: false,
|
||||
ascension: false,
|
||||
singularity: false,
|
||||
annihilation: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.hasDimension = SingularityMilestone.darkDimensionAutobuyers.isUnlocked;
|
||||
this.hasAscension = SingularityMilestone.darkDimensionAutobuyers.isUnlocked;
|
||||
this.hasSingularity = SingularityMilestone.autoCondense.isUnlocked;
|
||||
this.hasAnnihilated = Laitela.darkMatterMult > 1;
|
||||
const auto = player.celestials.laitela.automation;
|
||||
this.dimension = auto.dimensions;
|
||||
this.ascension = auto.ascension;
|
||||
this.singularity = auto.singularity;
|
||||
this.annihilation = auto.annihilation;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
dimension(newValue) {
|
||||
player.celestials.laitela.automation.dimensions = newValue;
|
||||
},
|
||||
ascension(newValue) {
|
||||
player.celestials.laitela.automation.ascension = newValue;
|
||||
},
|
||||
singularity(newValue) {
|
||||
player.celestials.laitela.automation.singularity = newValue;
|
||||
},
|
||||
annihilation(newValue) {
|
||||
player.celestials.laitela.automation.annihilation = newValue;
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div class="c-laitela-singularity-container">
|
||||
<primary-button-on-off
|
||||
v-if="hasDimension"
|
||||
v-model="dimension"
|
||||
class="c-laitela-automation-toggle"
|
||||
text="Auto-buy DM Dimensions:" />
|
||||
<primary-button-on-off
|
||||
v-if="hasAscension"
|
||||
v-model="ascension"
|
||||
class="c-laitela-automation-toggle"
|
||||
text="Auto-Ascend:" />
|
||||
<primary-button-on-off
|
||||
v-if="hasSingularity"
|
||||
v-model="singularity"
|
||||
class="c-laitela-automation-toggle"
|
||||
text="Auto-Singularity:" />
|
||||
<primary-button-on-off
|
||||
v-if="hasAnnihilated"
|
||||
v-model="annihilation"
|
||||
class="c-laitela-automation-toggle"
|
||||
text="Auto-Annihilation:" />
|
||||
</div>`
|
||||
});
|
@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("singularity-milestone", {
|
||||
props: ["milestone", "suppressGlow"],
|
||||
data: () => ({
|
||||
isMaxed: false,
|
||||
progressToNext: "",
|
||||
remainingSingularities: 0,
|
||||
description: "",
|
||||
effectDisplay: "",
|
||||
isUnique: false,
|
||||
nextEffectDisplay: "",
|
||||
start: 0,
|
||||
completions: 0,
|
||||
limit: 0
|
||||
}),
|
||||
methods: {
|
||||
update() {
|
||||
this.isMaxed = this.milestone.isMaxed;
|
||||
this.progressToNext = this.milestone.progressToNext;
|
||||
this.remainingSingularities = this.milestone.remainingSingularities;
|
||||
this.description = this.milestone.description;
|
||||
this.effectDisplay = this.milestone.effectDisplay;
|
||||
this.isUnique = this.milestone.isUnique;
|
||||
if (!this.isUnique && !this.isMaxed) this.nextEffectDisplay = this.milestone.nextEffectDisplay;
|
||||
this.completions = this.milestone.completions;
|
||||
this.limit = this.milestone.limit;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
barProgressStyle() {
|
||||
let color;
|
||||
if (this.isMaxed) color = "";
|
||||
else if (this.isUnique) color = "var(--color-accent)";
|
||||
else if (this.limit > 1) color = "var(--color-good-dark)";
|
||||
else color = "var(--color-good)";
|
||||
return {
|
||||
background: color,
|
||||
width: this.progressToNext
|
||||
};
|
||||
},
|
||||
backgroundStyle() {
|
||||
let color;
|
||||
if (this.isUnique && this.isMaxed) color = "var(--color-accent)";
|
||||
else if (this.limit > 1 && this.completions >= 1) {
|
||||
if (this.isMaxed) color = "var(--color-good-dark)";
|
||||
else color = "var(--color-good)";
|
||||
} else {
|
||||
color = "";
|
||||
}
|
||||
return {
|
||||
"background-color": color
|
||||
};
|
||||
},
|
||||
newGlowStyle() {
|
||||
if (this.suppressGlow) return {};
|
||||
const newMilestones = SingularityMilestones.unseenMilestones;
|
||||
for (let rep = 0; this.completions === 0 || rep < this.completions; rep++) {
|
||||
const thisLevel = this.milestone.start * Math.pow(this.milestone.repeat, rep);
|
||||
if (newMilestones.includes(thisLevel)) return { "box-shadow": "0 0 0.3rem 0.3rem var(--color-celestials)" };
|
||||
if (thisLevel > player.celestials.laitela.singularities) break;
|
||||
}
|
||||
return {};
|
||||
},
|
||||
upgradeDirectionIcon() {
|
||||
switch (this.milestone.config.upgradeDirection) {
|
||||
case LAITELA_UPGRADE_DIRECTION.SELF_BOOST:
|
||||
return `<b>ᛝ</b>`;
|
||||
case LAITELA_UPGRADE_DIRECTION.BOOSTS_MAIN:
|
||||
return `<i class="fas fa-arrows-alt"></i>`;
|
||||
case LAITELA_UPGRADE_DIRECTION.BOOSTS_LAITELA:
|
||||
return `<i class="fas fa-compress-arrows-alt"></i>`;
|
||||
default:
|
||||
throw new Error("Unspecified Lai'tela upgrade direction in singularity milestone");
|
||||
}
|
||||
},
|
||||
completionsDisplay() {
|
||||
if (this.limit === 0) return `${this.completions} ${pluralize("completion", this.completions)}`;
|
||||
if (this.isUnique) return this.isMaxed ? "Completed" : "Not completed";
|
||||
return `${this.completions}/${this.limit} ${pluralize("completion", this.completions)}`;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="c-laitela-milestone"
|
||||
:class="{ 'c-laitela-milestone--completed': isUnique && isMaxed }"
|
||||
:style="[backgroundStyle, newGlowStyle]">
|
||||
<div class="c-laitela-milestone__progress" :style="barProgressStyle"/>
|
||||
<b v-if="!isMaxed">
|
||||
In {{ format(remainingSingularities, 2, 0) }}
|
||||
{{ "Singularity" | pluralize(remainingSingularities, "Singularities")}}
|
||||
</b>
|
||||
<p> <span v-html="upgradeDirectionIcon"/> {{ description }}</p>
|
||||
<br>
|
||||
<b>
|
||||
{{ effectDisplay }}
|
||||
<span v-if="!isUnique && !isMaxed">➜ {{ nextEffectDisplay }}</span>
|
||||
</b>
|
||||
<div class="c-laitela-milestone__completions">
|
||||
{{ completionsDisplay }}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("singularity-milestones-modal", {
|
||||
data: () => ({
|
||||
milestones: []
|
||||
}),
|
||||
methods: {
|
||||
update() {
|
||||
this.milestones = SingularityMilestones.sortedForCompletions;
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
player.celestials.laitela.lastCheckedMilestones = player.celestials.laitela.singularities;
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<modal-close-button @click="emitClose"/>
|
||||
<div class="l-singularity-milestone-modal-container-outer">
|
||||
<div class="l-singularity-milestone-modal-container-inner">
|
||||
<singularity-milestone v-for="milestone in milestones" :key="milestone.id" :milestone="milestone"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
@ -6,56 +6,116 @@ Vue.component("matter-dimension-row", {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chance: 0,
|
||||
interval: new Decimal(0),
|
||||
power: new Decimal(0),
|
||||
chanceCost: 0,
|
||||
tier: 0,
|
||||
ascension: 0,
|
||||
interval: 0,
|
||||
powerDM: new Decimal(0),
|
||||
powerDE: 0,
|
||||
intervalCost: 0,
|
||||
powerCost: 0,
|
||||
powerDMCost: 0,
|
||||
powerDECost: 0,
|
||||
amount: new Decimal(0),
|
||||
canBuyChance: false,
|
||||
canBuyInterval: false,
|
||||
canBuyPower: false
|
||||
canBuyPowerDM: false,
|
||||
canBuyPowerDE: false,
|
||||
isIntervalCapped: false,
|
||||
timer: 0,
|
||||
timerPecent: 0,
|
||||
intervalAscensionBump: 10000,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
const suffix = " Dark Matter Dimension";
|
||||
switch (this.tier) {
|
||||
case 0:
|
||||
return `First ${suffix}`;
|
||||
case 1:
|
||||
return `Second ${suffix}`;
|
||||
case 2:
|
||||
return `Third ${suffix}`;
|
||||
case 3:
|
||||
return `Fourth ${suffix}`;
|
||||
default:
|
||||
throw new Error("Invalid Dark Matter Dimension index");
|
||||
}
|
||||
},
|
||||
ascensionText() {
|
||||
if (this.ascension === 0) return "";
|
||||
return `(⯅${formatInt(this.ascension)})`;
|
||||
},
|
||||
intervalClassObject() {
|
||||
return {
|
||||
"o-matter-dimension-button--available": this.canBuyInterval,
|
||||
"o-matter-dimension-button--ascend": this.isIntervalCapped
|
||||
};
|
||||
},
|
||||
intervalText() {
|
||||
if (this.interval > 1000) return `${format(this.interval / 1000, 2, 2)}s`;
|
||||
return `${format(this.interval, 2, 2)}ms`;
|
||||
},
|
||||
ascensionTooltip() {
|
||||
return `Multiply interval by ${formatInt(this.intervalAscensionBump)}
|
||||
and both multipliers by ${formatInt(1000)}, but gain the ability to upgrade interval even further`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.chance = this.dimension.chance;
|
||||
this.interval.copyFrom(this.dimension.interval);
|
||||
this.power.copyFrom(this.dimension.power);
|
||||
this.chanceCost = this.dimension.chanceCost;
|
||||
this.tier = this.dimension._tier;
|
||||
this.ascension = this.dimension.ascensions;
|
||||
this.interval = this.dimension.interval;
|
||||
this.powerDM.copyFrom(this.dimension.powerDM);
|
||||
this.powerDE = this.dimension.powerDE;
|
||||
this.intervalCost = this.dimension.intervalCost;
|
||||
this.powerCost = this.dimension.powerCost;
|
||||
this.powerDMCost = this.dimension.powerDMCost;
|
||||
this.powerDECost = this.dimension.powerDECost;
|
||||
this.amount.copyFrom(this.dimension.amount);
|
||||
this.canBuyChance = this.dimension.canBuyChance;
|
||||
this.canBuyInterval = this.dimension.canBuyInterval;
|
||||
this.canBuyPower = this.dimension.canBuyPower;
|
||||
this.canBuyPowerDM = this.dimension.canBuyPowerDM;
|
||||
this.canBuyPowerDE = this.dimension.canBuyPowerDE;
|
||||
this.isIntervalCapped = this.dimension.interval <= this.dimension.intervalPurchaseCap;
|
||||
this.timer = this.dimension.timeSinceLastUpdate;
|
||||
this.timerPercent = this.timer / this.interval;
|
||||
this.intervalAscensionBump = SingularityMilestone.ascensionIntervalScaling.effectValue;
|
||||
},
|
||||
handleIntervalClick() {
|
||||
if (this.isIntervalCapped) this.dimension.ascend();
|
||||
else this.dimension.buyInterval();
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="c-matter-dimension-container">
|
||||
<div class="o-matter-dimension-amount"> {{ shorten(amount, 2, 0) }}</div>
|
||||
<div class="o-matter-dimension-amount"> {{ name }} {{ ascensionText }}: {{ format(amount, 2, 0) }}</div>
|
||||
<div class="c-matter-dimension-buttons">
|
||||
<button
|
||||
@click="dimension.buyChance()"
|
||||
@click="handleIntervalClick()"
|
||||
class="o-matter-dimension-button"
|
||||
:class="{ 'o-matter-dimension-button--available': canBuyChance }">
|
||||
{{ chance }}% <span v-if="chance !== 100"><br>Cost: {{ shorten(chanceCost, 2, 0) }}</span>
|
||||
:class="intervalClassObject">
|
||||
{{ intervalText }}
|
||||
<span v-if="isIntervalCapped">
|
||||
<br>Ascend!
|
||||
<span :ach-tooltip="ascensionTooltip">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span v-else><br>Cost: {{ format(intervalCost, 2, 0) }}</span>
|
||||
</button>
|
||||
<button
|
||||
@click="dimension.buyInterval()"
|
||||
class="o-matter-dimension-button"
|
||||
:class="{ 'o-matter-dimension-button--available': canBuyInterval }">
|
||||
{{ interval.toFixed(2) }}ms <span v-if="!interval.eq(50)"><br>Cost: {{ shorten(intervalCost, 2, 0) }}</span>
|
||||
<button
|
||||
@click="dimension.buyPowerDM()"
|
||||
class="o-matter-dimension-button"
|
||||
:class="{ 'o-matter-dimension-button--available': canBuyPowerDM }">
|
||||
DM {{ formatX(powerDM, 2, 2) }}<br>Cost: {{ format(powerDMCost, 2, 0) }}
|
||||
</button>
|
||||
<button
|
||||
@click="dimension.buyPower()"
|
||||
class="o-matter-dimension-button"
|
||||
:class="{ 'o-matter-dimension-button--available': canBuyPower }">
|
||||
{{ shorten(power, 2, 2) }}x <br>Cost: {{ shorten(powerCost, 2, 0) }}
|
||||
<button
|
||||
@click="dimension.buyPowerDE()"
|
||||
class="o-matter-dimension-button"
|
||||
:class="{ 'o-matter-dimension-button--available': canBuyPowerDE }">
|
||||
DE +{{ format(powerDE, 2, 4) }}<br>Cost: {{ format(powerDECost, 2, 0) }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="interval > 200">Tick: {{ formatInt(timer) }} ms ({{ formatPercents(timerPercent, 1) }})</div>
|
||||
<div>DE: {{ format(powerDE * 1000 / interval, 2, 4) }}/s</div>
|
||||
</div>
|
||||
|
||||
|
||||
`
|
||||
})
|
||||
|
@ -10,7 +10,7 @@ Vue.component("alchemy-circle-node", {
|
||||
isReactionActive: false,
|
||||
amount: 0,
|
||||
flow: 0,
|
||||
alwaysShowResource: false
|
||||
isUnlocked: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -21,7 +21,7 @@ Vue.component("alchemy-circle-node", {
|
||||
return this.resource.isBaseResource;
|
||||
},
|
||||
layoutStyle() {
|
||||
const scaledFlow = Math.clamp(0.4 * Math.sqrt(Math.abs(this.flow)), 0, 1);
|
||||
const scaledFlow = Math.clamp(0.7 * Math.sqrt(Math.abs(this.flow)), 0, 1);
|
||||
return {
|
||||
left: `${this.node.x}%`,
|
||||
top: `${this.node.y}%`,
|
||||
@ -34,6 +34,7 @@ Vue.component("alchemy-circle-node", {
|
||||
"o-alchemy-node--base": this.isBaseResource,
|
||||
"o-alchemy-node--active": this.isReactionActive,
|
||||
"o-alchemy-node--unfocused": !this.isFocused,
|
||||
"o-alchemy-node--locked": !this.isUnlocked,
|
||||
};
|
||||
},
|
||||
hintClassObject() {
|
||||
@ -45,7 +46,7 @@ Vue.component("alchemy-circle-node", {
|
||||
this.isReactionActive = !this.isBaseResource && this.node.resource.reaction.isActive;
|
||||
this.amount = this.resource.amount;
|
||||
this.flow = this.resource.flow;
|
||||
this.alwaysShowResource = player.options.showAlchemyResources;
|
||||
this.isUnlocked = this.resource.isUnlocked;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
@ -60,15 +61,13 @@ Vue.component("alchemy-circle-node", {
|
||||
:resource="resource"
|
||||
:classObject="classObject"
|
||||
/>
|
||||
<div v-if="alwaysShowResource"
|
||||
class="o-alchemy-node-resource--always-visible">
|
||||
{{ amount.toFixed(1) }}
|
||||
</div>
|
||||
<hint-text v-else
|
||||
:class="hintClassObject"
|
||||
class="o-hint-text--alchemy-node l-hint-text--alchemy-node">
|
||||
{{ amount.toFixed(1) }}
|
||||
</hint-text>
|
||||
<span v-if="isUnlocked">
|
||||
<hint-text type="alchemy"
|
||||
:class="hintClassObject"
|
||||
class="o-hint-text--alchemy-node l-hint-text--alchemy-node">
|
||||
{{ amount.toFixed(1) }}
|
||||
</hint-text>
|
||||
</span>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
@ -81,30 +80,32 @@ Vue.component("alchemy-resource-arc", {
|
||||
data() {
|
||||
return {
|
||||
amount: 0,
|
||||
fillFraction: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
spinnerTransform() {
|
||||
return {
|
||||
transform: `rotate(${this.amount / Ra.alchemyResourceCap * 360}deg)`,
|
||||
background: this.amount === Ra.alchemyResourceCap ? "#ff9800" : undefined
|
||||
transform: `rotate(${this.fillFraction * 360}deg)`,
|
||||
background: this.fillFraction === 1 ? "#ff9800" : undefined
|
||||
};
|
||||
},
|
||||
fillerTransform() {
|
||||
return {
|
||||
opacity: this.amount / Ra.alchemyResourceCap > 0.5 ? 1 : 0,
|
||||
background: this.amount === Ra.alchemyResourceCap ? "#ff9800" : undefined
|
||||
opacity: this.fillFraction > 0.5 ? 1 : 0,
|
||||
background: this.fillFraction === 1 ? "#ff9800" : undefined
|
||||
};
|
||||
},
|
||||
maskTransform() {
|
||||
return {
|
||||
opacity: this.amount / Ra.alchemyResourceCap > 0.5 ? 0 : 1
|
||||
opacity: this.fillFraction > 0.5 ? 0 : 1
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.amount = this.resource.amount;
|
||||
this.fillFraction = Math.clamp(this.amount / estimatedAlchemyCap(), 0, 1);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
|
@ -8,7 +8,9 @@ Vue.component("alchemy-resource-info", {
|
||||
return {
|
||||
amount: 0,
|
||||
isReactionActive: false,
|
||||
reactionProduction: 0
|
||||
reactionProduction: 0,
|
||||
isUnlocked: false,
|
||||
unlockRequirement: ""
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -21,9 +23,9 @@ Vue.component("alchemy-resource-info", {
|
||||
reactionText() {
|
||||
if (this.resource === AlchemyResource.reality) return this.realityReactionText;
|
||||
const reagents = this.reaction.reagents
|
||||
.map(r => `${shorten(r.cost)}${r.resource.symbol}`)
|
||||
.map(r => `${format(r.cost)}${r.resource.symbol}`)
|
||||
.join(" + ");
|
||||
return `${reagents} ➜ ${shorten(this.reaction.reactionProduction, 2, 2)}${this.resource.symbol}`;
|
||||
return `${reagents} ➜ ${format(this.reaction.reactionProduction, 2, 2)}${this.resource.symbol}`;
|
||||
},
|
||||
realityReactionText() {
|
||||
const reagents = this.reaction.reagents
|
||||
@ -37,11 +39,16 @@ Vue.component("alchemy-resource-info", {
|
||||
effect: () => resource.config.effect(resource.amount),
|
||||
formatEffect: resource.config.formatEffect
|
||||
};
|
||||
},
|
||||
resourceAmount() {
|
||||
return formatFloat(this.amount, 1);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.amount = this.resource.amount;
|
||||
this.isUnlocked = this.resource.isUnlocked;
|
||||
this.unlockRequirement = this.resource.config.lockText;
|
||||
if (!this.isBaseResource) {
|
||||
this.isReactionActive = this.reaction.isActive;
|
||||
this.reactionProduction = this.reaction.production;
|
||||
@ -50,11 +57,12 @@ Vue.component("alchemy-resource-info", {
|
||||
},
|
||||
template: `
|
||||
<div class="c-alchemy-resource-info">
|
||||
<span>{{resource.symbol}} {{resource.name}}</span>
|
||||
<span>Current: {{ shorten(amount, 2, 2) }}</span>
|
||||
<span>{{isUnlocked ? resource.symbol : "?"}} {{resource.name}}</span>
|
||||
<span>Current: {{ isUnlocked ? resourceAmount : "Locked!" }}</span>
|
||||
<span v-if="isBaseResource">Base Resource</span>
|
||||
<span v-else>Reaction: {{isReactionActive ? "Active" : "Inactive"}} ({{reactionText}})</span>
|
||||
<effect-display title="Effect" :config="effectConfig" />
|
||||
<span v-else>Reaction: {{isReactionActive ? "Active" : "Inactive"}} ({{isUnlocked ? reactionText : "???"}})</span>
|
||||
<span v-if="isUnlocked"><effect-display title="Effect" :config="effectConfig" /></span>
|
||||
<span v-else>Unlock requirement: {{unlockRequirement}}</span>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
@ -75,9 +75,10 @@ Vue.component("alchemy-tab", {
|
||||
return {
|
||||
infoResourceId: 0,
|
||||
focusedResourceId: -1,
|
||||
reactionsAvailable: false,
|
||||
realityCreationAvailable: false,
|
||||
alwaysShowResource: false,
|
||||
reactionProgress: 0,
|
||||
estimatedCap: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -100,10 +101,11 @@ Vue.component("alchemy-tab", {
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.reactionsAvailable = AlchemyResources.all.filter(res => !res.isBaseResource && res.isUnlocked).length !== 0;
|
||||
this.realityCreationAvailable = AlchemyResource.reality.amount !== 0;
|
||||
this.alwaysShowResource = player.options.showAlchemyResources;
|
||||
const animationTime = 800;
|
||||
this.reactionProgress = (player.realTimePlayed % animationTime) / animationTime;
|
||||
this.estimatedCap = estimatedAlchemyCap();
|
||||
},
|
||||
orbitSize(orbit) {
|
||||
const maxRadius = this.layout.orbits.map(o => o.radius).max();
|
||||
@ -118,6 +120,7 @@ Vue.component("alchemy-tab", {
|
||||
},
|
||||
handleClick(node) {
|
||||
const resource = node.resource;
|
||||
if (!resource.isUnlocked) return;
|
||||
if (this.infoResourceId !== resource.id) {
|
||||
this.infoResourceId = resource.id;
|
||||
this.focusedResourceId = resource.id;
|
||||
@ -127,17 +130,22 @@ Vue.component("alchemy-tab", {
|
||||
resource.reaction.isActive = !resource.reaction.isActive;
|
||||
GameUI.update();
|
||||
},
|
||||
isUnlocked(reactionArrow) {
|
||||
return reactionArrow.product.resource.isUnlocked && reactionArrow.reagent.resource.isUnlocked;
|
||||
},
|
||||
isCapped(reactionArrow) {
|
||||
return reactionArrow.product.resource.amount >= reactionArrow.reagent.resource.amount;
|
||||
return reactionArrow.product.resource.amount > 0 &&
|
||||
reactionArrow.product.resource.amount >= reactionArrow.reagent.resource.amount;
|
||||
},
|
||||
isActiveReaction(reactionArrow) {
|
||||
return reactionArrow.reaction.isActive;
|
||||
},
|
||||
isFocusedReaction(reactionArrow) {
|
||||
return reactionArrow.reaction.product.id === this.focusedResourceId;
|
||||
return this.isUnlocked(reactionArrow) && reactionArrow.reaction.product.id === this.focusedResourceId;
|
||||
},
|
||||
isDisplayed(reactionArrow) {
|
||||
return this.isActiveReaction(reactionArrow) || this.isFocusedReaction(reactionArrow);
|
||||
return this.isUnlocked(reactionArrow) &&
|
||||
(this.isActiveReaction(reactionArrow) || this.isFocusedReaction(reactionArrow));
|
||||
},
|
||||
isFocusedNode(node) {
|
||||
if (this.focusedResourceId === -1) return true;
|
||||
@ -173,7 +181,7 @@ Vue.component("alchemy-tab", {
|
||||
},
|
||||
reactionPathClass(reactionArrow) {
|
||||
return {
|
||||
"o-alchemy-reaction-path": true,
|
||||
"o-alchemy-reaction-path": this.isUnlocked(reactionArrow),
|
||||
"o-alchemy-reaction-path--limited": this.isCapped(reactionArrow) && this.isDisplayed(reactionArrow),
|
||||
"o-alchemy-reaction-path--focused": !this.isCapped(reactionArrow) && this.isFocusedReaction(reactionArrow),
|
||||
};
|
||||
@ -184,36 +192,47 @@ Vue.component("alchemy-tab", {
|
||||
"o-alchemy-reaction-arrow--focused": this.isFocusedReaction(reactionArrow),
|
||||
};
|
||||
},
|
||||
toggleResourceVisibility() {
|
||||
player.options.showAlchemyResources = !player.options.showAlchemyResources;
|
||||
},
|
||||
showAlchemyHowTo() {
|
||||
Modal.message.show("You can now refine glyphs using \"Alchemy Mode\" in the glyph auto-sacrifice settings. " +
|
||||
"Refined glyphs will give 1% of their level in alchemy resources. Alchemy reactions can be toggled on " +
|
||||
"and off by clicking the respective nodes, and each resource gives its own boost to various resources " +
|
||||
"in the game. Basic resource totals are limited to the level of the refined glyph, and compound resource " +
|
||||
"totals are limited to the amount of the reactants. All active alchemy reactions are applied once per " +
|
||||
"reality, unaffected by amplification. Toggle reactions on or off by clicking the nodes. You can show the " +
|
||||
"current totals of all alchemy resources by holding shift.");
|
||||
ui.view.h2pForcedTab = GameDatabase.h2p.tabs.filter(tab => tab.name === "Glyph Alchemy")[0];
|
||||
Modal.h2p.show();
|
||||
ui.view.h2pActive = true;
|
||||
},
|
||||
setAllReactions(value) {
|
||||
for (const reaction of AlchemyReactions.all.compact()) {
|
||||
reaction.isActive = value;
|
||||
toggleAllReactions() {
|
||||
const reactions = AlchemyReactions.all.compact().filter(r => r._product.isUnlocked);
|
||||
const allReactionsDisabled = reactions.every(reaction => !reaction.isActive);
|
||||
if (allReactionsDisabled) {
|
||||
for (const reaction of reactions) {
|
||||
reaction.isActive = true;
|
||||
}
|
||||
} else {
|
||||
for (const reaction of reactions) {
|
||||
reaction.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-ra-alchemy-tab">
|
||||
<div @click="showAlchemyHowTo()" class="o-primary-btn">Click for alchemy info</div>
|
||||
<alchemy-resource-info :key="infoResourceId" :resource="infoResource" />
|
||||
<div>
|
||||
<input type="checkbox"
|
||||
id="alwaysShowResourceBox"
|
||||
v-model="alwaysShowResource"
|
||||
:value="alwaysShowResource"
|
||||
@input="toggleResourceVisibility()">
|
||||
<label for="alwaysShowResourceBox">Always show resource totals</label>
|
||||
template: `
|
||||
<div class="l-ra-alchemy-tab">
|
||||
<div class="c-subtab-option-container">
|
||||
<primary-button class="o-primary-btn--subtab-option" @click="showAlchemyHowTo()">
|
||||
Click for alchemy info
|
||||
</primary-button>
|
||||
<primary-button class="o-primary-btn--subtab-option" @click="toggleAllReactions()">
|
||||
Toggle all reactions
|
||||
</primary-button>
|
||||
<primary-button
|
||||
v-if="realityCreationAvailable"
|
||||
class="o-primary-btn--subtab-option"
|
||||
onclick="Modal.realityGlyph.show()"
|
||||
>
|
||||
Create a Reality glyph
|
||||
</primary-button>
|
||||
</div>
|
||||
<alchemy-resource-info :key="infoResourceId" :resource="infoResource" />
|
||||
Resource cap, based on glyph level in last 10 realities: {{ format(estimatedCap, 3, 2) }}.
|
||||
<span v-if="reactionsAvailable">
|
||||
Reactions trigger once every time you reality.
|
||||
</span>
|
||||
<div class="l-alchemy-circle" :style="circleStyle">
|
||||
<svg class="l-alchemy-orbit-canvas">
|
||||
<circle
|
||||
@ -224,8 +243,8 @@ Vue.component("alchemy-tab", {
|
||||
:r="orbitSize(orbit)"
|
||||
:class="orbitClass"
|
||||
/>
|
||||
</svg>
|
||||
<alchemy-circle-node
|
||||
</svg>
|
||||
<alchemy-circle-node
|
||||
v-for="(node, i) in layout.nodes"
|
||||
:key="i"
|
||||
:node="node"
|
||||
@ -245,13 +264,7 @@ Vue.component("alchemy-tab", {
|
||||
v-bind="reactionArrowPositions(reactionArrow)"
|
||||
:class="reactionArrowClass(reactionArrow)"
|
||||
/>
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
<button class="o-primary-btn" @click="setAllReactions(true)">Turn on all reactions</button>
|
||||
<button class="o-primary-btn" @click="setAllReactions(false)">Turn off all reactions</button>
|
||||
<primary-button
|
||||
v-if="realityCreationAvailable"
|
||||
class="o-primary-btn"
|
||||
onclick="Modal.realityGlyph.show()">Create a Reality glyph</primary-button>
|
||||
</div>`
|
||||
});
|
||||
|
@ -1,58 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("compression-button", {
|
||||
data() {
|
||||
return {
|
||||
timeShards: new Decimal(0),
|
||||
isRunning: false,
|
||||
requiredForGain: new Decimal(0),
|
||||
entanglementGain: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
shardRequirement: () => TimeCompression.timeShardRequirement,
|
||||
canCompress() {
|
||||
return this.timeShards.gte(this.shardRequirement);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.timeShards.copyFrom(player.timeShards);
|
||||
this.isRunning = player.celestials.ra.compression.active;
|
||||
if (!this.isRunning) return;
|
||||
this.entanglementGain = this.gainedEntanglement();
|
||||
if (this.entanglementGain <= 0) {
|
||||
this.requiredForGain.copyFrom(this.minAntimatterForEntanglement());
|
||||
}
|
||||
},
|
||||
minAntimatterForEntanglement() {
|
||||
if (TimeCompression.totalEntanglement === 308) {
|
||||
return Decimal.pow10(9e15);
|
||||
}
|
||||
const entanglementMult = Effects.max(1, CompressionUpgrade.moreEntanglement);
|
||||
return Decimal.pow10(1.8e5 * Math.pow(1 + TimeCompression.totalEntanglement / (30.8 * entanglementMult), 2.5));
|
||||
},
|
||||
gainedEntanglement() {
|
||||
return Math.max(0, TimeCompression.entanglementThisRun - TimeCompression.totalEntanglement);
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<button class="o-compression-btn" onclick="TimeCompression.toggle()">
|
||||
<span v-if="!canCompress && !isRunning">
|
||||
Time compression requires {{ shorten(shardRequirement) }} time shards to activate.
|
||||
<br>
|
||||
Currently: {{ shorten(timeShards) }} time shards
|
||||
</span>
|
||||
<span v-else-if="!isRunning">Compress time.</span>
|
||||
<span v-else-if="entanglementGain > 0">
|
||||
Disable compression.
|
||||
<br>
|
||||
Gain {{shorten(entanglementGain, 0, 2)}} Entanglement.
|
||||
</span>
|
||||
<span v-else>
|
||||
Disable compression.
|
||||
<br>
|
||||
Reach {{shorten(requiredForGain, 2, 2)}} antimatter to gain more Entanglement.
|
||||
</span>
|
||||
</button>`
|
||||
});
|
@ -1,60 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("compression-upgrade", {
|
||||
props: {
|
||||
upgrade: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isBought: false,
|
||||
isActive: false,
|
||||
isAffordable: false,
|
||||
currentDisplay: ""
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
classObject() {
|
||||
return {
|
||||
"o-compression-upgrade": true,
|
||||
"o-compression-upgrade--active": this.isBought && this.isActive,
|
||||
"o-compression-upgrade--inactive": this.isBought && !this.isActive,
|
||||
"o-compression-upgrade--available": !this.isBought && this.isAffordable,
|
||||
"o-compression-upgrade--unavailable": !this.isBought && !this.isAffordable
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isBought = this.upgrade.isBought;
|
||||
this.isActive = this.upgrade.canBeApplied;
|
||||
this.isAffordable = this.upgrade.isAffordable;
|
||||
this.currentDisplay = this.upgrade.config.currentDisplay();
|
||||
this.effectDisplay = this.upgrade.effectDisplay;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-spoon-btn-group">
|
||||
<button :class="classObject" @click="upgrade.purchase()">
|
||||
<description-display
|
||||
:config="upgrade.config"
|
||||
:length="70"
|
||||
name="o-compression-upgrade__description"
|
||||
/>
|
||||
<span v-if="isBought && effectDisplay !== undefined"><br><br>Currently: {{ effectDisplay }}</span>
|
||||
<br><br>
|
||||
<span>To activate: {{ upgrade.config.secondary() }}</span>
|
||||
<br>
|
||||
<span>(Currently {{ currentDisplay }})</span>
|
||||
<br><br>
|
||||
<effect-display :config="upgrade.config" />
|
||||
<cost-display
|
||||
v-if="!isBought"
|
||||
:config="upgrade.config"
|
||||
singular="Entanglement"
|
||||
plural="Entanglement"
|
||||
/>
|
||||
<div v-else-if="isActive">Active! (Cost: {{ shortenSmallInteger(upgrade.config.cost) }})</div>
|
||||
<div v-else>Inactive (Cost: {{ shortenSmallInteger(upgrade.config.cost) }})</div>
|
||||
</button>
|
||||
</div>`
|
||||
});
|
@ -2,33 +2,27 @@
|
||||
|
||||
Vue.component("ra-level-chevron", {
|
||||
props: {
|
||||
minLevel: Number,
|
||||
level: Number,
|
||||
goal: Number,
|
||||
unlock: Object,
|
||||
singleLevel: {
|
||||
type: Boolean,
|
||||
defualt: false
|
||||
},
|
||||
isImportantLevel: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mouseOverInterval: 0,
|
||||
isMouseOver: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
percentPerLevel() {
|
||||
return this.singleLevel ? 0 : 100 / (this.goal - 1);
|
||||
levelPercent() {
|
||||
const startScl = Math.sqrt(Ra.totalExpForLevel(this.minLevel));
|
||||
const endScl = Math.sqrt(Ra.totalExpForLevel(this.goal));
|
||||
const currentScl = Math.sqrt(Ra.totalExpForLevel(this.level));
|
||||
const expFraction = (currentScl - startScl) / (endScl - startScl);
|
||||
return 100 * expFraction;
|
||||
},
|
||||
levelPosition() {
|
||||
if (this.level === this.goal)
|
||||
return {
|
||||
right: "0%",
|
||||
};
|
||||
return {
|
||||
left: `${this.percentPerLevel * (this.level - 1)}%`,
|
||||
};
|
||||
if (this.level === this.goal) return { right: "0%" };
|
||||
if (this.singleLevel) return { left: "0%" };
|
||||
return { left: `${this.levelPercent}%` };
|
||||
},
|
||||
classList() {
|
||||
return [
|
||||
@ -37,29 +31,13 @@ Vue.component("ra-level-chevron", {
|
||||
];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onMouseEnter() {
|
||||
if (this.$viewModel.shiftDown) return;
|
||||
clearTimeout(this.mouseOverInterval);
|
||||
this.isMouseOver = true;
|
||||
},
|
||||
onMouseLeave() {
|
||||
this.mouseOverInterval = setTimeout(() => this.isMouseOver = false, 500);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
<div v-if="level >= minLevel || singleLevel"
|
||||
class="l-ra-lvl-chevron"
|
||||
:style="levelPosition"
|
||||
:class="classList"
|
||||
@mouseenter="onMouseEnter"
|
||||
@click="onMouseEnter"
|
||||
@mouseleave="onMouseLeave">
|
||||
<div v-if="isMouseOver && isImportantLevel" class="o-ra-unlock-hover-text">
|
||||
{{unlock.reward}}
|
||||
</div>
|
||||
<span>
|
||||
{{level}}
|
||||
:class="classList">
|
||||
<span v-if="isImportantLevel || level === goal">
|
||||
{{formatInt(level)}}
|
||||
</span>
|
||||
</div>
|
||||
`
|
||||
|
@ -16,24 +16,26 @@ Vue.component("ra-pet-level-bar", {
|
||||
shiftDown() {
|
||||
return ui.view.shiftDown;
|
||||
},
|
||||
importantLevels: () => [2, 3, 5, 10, 15, 25],
|
||||
unlocks() {
|
||||
return Object.values(RA_UNLOCKS).filter(unlock => unlock.pet === this.pet);
|
||||
},
|
||||
percentPerLevel() {
|
||||
return 100 / (this.currentLevelGoal - 1);
|
||||
},
|
||||
percentToNextLevel() {
|
||||
return this.exp / this.requiredExp;
|
||||
importantLevels() {
|
||||
return this.unlocks.map(u => u.level);
|
||||
},
|
||||
multiLevelStyle() {
|
||||
if (Notations.current.name === "Blind") return { width: "0%" };
|
||||
const startScl = Math.sqrt(Ra.totalExpForLevel(this.prevGoal));
|
||||
const endScl = Math.sqrt(Ra.totalExpForLevel(this.nextGoal));
|
||||
const currentScl = Math.sqrt(Ra.totalExpForLevel(this.level) + this.exp);
|
||||
const expFraction = (currentScl - startScl) / (endScl - startScl);
|
||||
return {
|
||||
width: `${Math.min((this.level - 1 + this.percentToNextLevel) * this.percentPerLevel, 100)}%`
|
||||
width: `${100 * Math.clampMax(expFraction, 1)}%`
|
||||
};
|
||||
},
|
||||
singleLevelStyle() {
|
||||
if (Notations.current.name === "Blind") return { width: "0%" };
|
||||
return {
|
||||
width: `${this.percentToNextLevel * 100}%`
|
||||
width: `${100 * (this.exp / this.requiredExp)}%`
|
||||
};
|
||||
},
|
||||
petStyle() {
|
||||
@ -41,16 +43,18 @@ Vue.component("ra-pet-level-bar", {
|
||||
"background-color": this.pet.color
|
||||
};
|
||||
},
|
||||
importantGoal() {
|
||||
return this.importantLevels.find(goal => goal > this.level || goal === 25);
|
||||
prevGoal() {
|
||||
const currentUpgrades = this.importantLevels.filter(goal => goal <= this.level);
|
||||
return Math.clampMax(currentUpgrades.max(), 15);
|
||||
},
|
||||
nextGoal() {
|
||||
const missingUpgrades = this.importantLevels.filter(goal => goal > this.level);
|
||||
return missingUpgrades.length === 0 ? 25 : missingUpgrades.min();
|
||||
},
|
||||
currentLevelGoal() {
|
||||
if (this.shiftDown) return this.level + 1;
|
||||
return this.importantGoal;
|
||||
return this.nextGoal;
|
||||
},
|
||||
activeUnlock() {
|
||||
return this.unlocks.find(unlock => unlock.level === this.importantGoal);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
@ -61,9 +65,6 @@ Vue.component("ra-pet-level-bar", {
|
||||
this.level = pet.level;
|
||||
this.requiredExp = pet.requiredExp;
|
||||
},
|
||||
findUnlockByLevel(level) {
|
||||
return this.unlocks.find(unlock => unlock.level === level);
|
||||
},
|
||||
isImportant(level) {
|
||||
return this.importantLevels.includes(level);
|
||||
}
|
||||
@ -74,29 +75,23 @@ Vue.component("ra-pet-level-bar", {
|
||||
<div v-if="shiftDown">
|
||||
<ra-level-chevron v-for="lvl in 2"
|
||||
:key="currentLevelGoal - 2 + lvl"
|
||||
:level ="currentLevelGoal - 2 + lvl"
|
||||
:level="currentLevelGoal - 2 + lvl"
|
||||
:goal="currentLevelGoal"
|
||||
:singleLevel="true"
|
||||
:isImportantLevel="isImportant(lvl)"
|
||||
/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<ra-level-chevron v-for="lvl in (currentLevelGoal - 1)"
|
||||
<ra-level-chevron v-for="lvl in currentLevelGoal"
|
||||
:key="lvl"
|
||||
:minLevel="prevGoal"
|
||||
:level="lvl"
|
||||
:goal="currentLevelGoal"
|
||||
:unlock="findUnlockByLevel(lvl)"
|
||||
:isImportantLevel="isImportant(lvl)"
|
||||
/>
|
||||
</div>
|
||||
<div class="l-ra-exp-bar-inner" :style="[shiftDown ? singleLevelStyle : multiLevelStyle, petStyle]" />
|
||||
</div>
|
||||
<div class="l-ra-unlock" :style="petStyle">
|
||||
<div class="l-ra-unlock-inner">
|
||||
<b>{{ activeUnlock.description }}</b>
|
||||
<p>{{ activeUnlock.reward }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("ra-pet-recollection-button", {
|
||||
props: {
|
||||
petConfig: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
name: "",
|
||||
hasRecollection: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
petStyle() {
|
||||
return {
|
||||
backgroundColor: this.hasRecollection ? this.petConfig.pet.color : "#555",
|
||||
cursor: this.hasRecollection ? "" : "pointer",
|
||||
"pointer-events": this.hasRecollection ? "none" : "",
|
||||
"box-shadow": this.hasRecollection ? "0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.7)" : "",
|
||||
"border-color": this.hasRecollection ? "black" : ""
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const pet = this.petConfig.pet;
|
||||
this.isUnlocked = pet.isUnlocked;
|
||||
if (!this.isUnlocked) return;
|
||||
this.name = pet.name;
|
||||
this.hasRecollection = pet.hasRecollection;
|
||||
},
|
||||
turnOnRecollection() {
|
||||
Ra.petWithRecollection = this.petConfig.pet.name;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="l-ra-pet-recollection-button-container">
|
||||
<button
|
||||
class="c-ra-pet-recollection-button"
|
||||
v-if="isUnlocked"
|
||||
:style="petStyle"
|
||||
@click="turnOnRecollection">
|
||||
<span v-if="hasRecollection">
|
||||
Recollection given to {{ name }}
|
||||
</span>
|
||||
<span v-else>
|
||||
Give Recollection to {{ name }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
});
|
@ -7,59 +7,166 @@ Vue.component("ra-pet", {
|
||||
data() {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
name: "",
|
||||
level: 0,
|
||||
exp: 0,
|
||||
requiredExp: 0,
|
||||
expBoost: 0,
|
||||
lastTenGlyphLevels: [],
|
||||
lastTenRunTimers: [],
|
||||
nextLevelEstimate: "",
|
||||
upgradeEstimate: "",
|
||||
memoryChunks: 0,
|
||||
memoryChunksPerSecond: 0,
|
||||
memoriesPerSecond: 0,
|
||||
memoryMultiplier: 1,
|
||||
canGetMemoryChunks: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pet() {
|
||||
return this.petConfig.pet;
|
||||
showScalingUpgrade() {
|
||||
return this.petConfig.scalingUpgradeVisible(this.level);
|
||||
},
|
||||
scalingUpgradeText() {
|
||||
return this.petConfig.scalingUpgradeText(this.level);
|
||||
},
|
||||
petStyle() {
|
||||
return {
|
||||
color: this.pet.color
|
||||
color: this.petConfig.pet.color
|
||||
};
|
||||
},
|
||||
expPerMin() {
|
||||
const expGain = this.lastTenGlyphLevels.reduce((acc, value) =>
|
||||
acc + Math.pow(2, value / 500 - 10), 0
|
||||
) * this.expBoost / 10;
|
||||
const avgTimeMs = this.lastTenRunTimers.reduce((acc, value) => acc + value, 0) / 10;
|
||||
return Math.round(expGain / (avgTimeMs / 60000));
|
||||
unlocks() {
|
||||
return Object.values(RA_UNLOCKS)
|
||||
.filter(unlock => unlock.pet === this.petConfig.pet)
|
||||
.sort((a, b) => a.level - b.level);
|
||||
},
|
||||
chunkTooltip() {
|
||||
switch (this.petConfig.pet.name) {
|
||||
case "Teresa":
|
||||
return "Based on EP";
|
||||
case "Effarig":
|
||||
return "Based on Relic Shards gained";
|
||||
case "Enslaved":
|
||||
return "Based on Time Shards";
|
||||
case "V":
|
||||
return "Based on Infinity Power";
|
||||
default:
|
||||
throw new Error(`Unrecognized celestial ${this.petConfig.pet.name} in Ra UI`);
|
||||
}
|
||||
},
|
||||
memoryGainTooltip() {
|
||||
switch (this.petConfig.pet.name) {
|
||||
case "Teresa":
|
||||
return "Based on current RM";
|
||||
case "Effarig":
|
||||
return "Based on best glyph level";
|
||||
case "Enslaved":
|
||||
return "Based on total time played";
|
||||
case "V":
|
||||
return "Based on total Celestial Memory levels";
|
||||
default:
|
||||
throw new Error(`Unrecognized celestial ${this.petConfig.pet.name} in Ra UI`);
|
||||
}
|
||||
},
|
||||
experienceInformation() {
|
||||
return `${shorten(this.exp, 2)}/${shorten(this.requiredExp, 2)}
|
||||
memories - ${shorten(this.expPerMin, 2)} memories/min`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const pet = this.pet;
|
||||
const pet = this.petConfig.pet;
|
||||
this.isUnlocked = pet.isUnlocked;
|
||||
if (!this.isUnlocked) return;
|
||||
this.name = pet.name;
|
||||
this.level = pet.level;
|
||||
this.expBoost = pet.expBoost;
|
||||
this.exp = pet.exp;
|
||||
this.requiredExp = pet.requiredExp;
|
||||
this.lastTenGlyphLevels = player.lastTenRealities.map(([, , , lvl]) => lvl);
|
||||
this.lastTenRunTimers = player.lastTenRealities.map(([, , time]) => time);
|
||||
this.memoryChunks = pet.memoryChunks;
|
||||
this.memoryChunksPerSecond = pet.memoryChunksPerSecond;
|
||||
this.memoriesPerSecond = pet.memoryChunks * Ra.productionPerMemoryChunk();
|
||||
this.canGetMemoryChunks = pet.canGetMemoryChunks;
|
||||
this.memoryMultiplier = pet.memoryProductionMultiplier;
|
||||
|
||||
const leftThisLevel = this.requiredExp - this.exp;
|
||||
const toUnlock = Ra.totalExpForLevel(this.nextUnlockLevel()) - Ra.totalExpForLevel(this.level + 1);
|
||||
this.nextLevelEstimate = this.timeToGoalString(leftThisLevel);
|
||||
this.upgradeEstimate = this.timeToGoalString(leftThisLevel + toUnlock);
|
||||
},
|
||||
timeToGoalString(expToGain) {
|
||||
const pet = this.petConfig.pet;
|
||||
// Quadratic formula for growth (uses constant growth for a = 0)
|
||||
const a = Ra.productionPerMemoryChunk() * pet.memoryChunksPerSecond / 2;
|
||||
const b = Ra.productionPerMemoryChunk() * pet.memoryChunks;
|
||||
const c = -expToGain;
|
||||
const estimate = a === 0
|
||||
? -c / b
|
||||
: (Math.sqrt(Math.pow(b, 2) - 4 * a * c) - b) / (2 * a);
|
||||
if (Number.isFinite(estimate)) {
|
||||
return TimeSpan.fromSeconds(estimate).toStringShort();
|
||||
}
|
||||
return "never";
|
||||
},
|
||||
nextUnlockLevel() {
|
||||
const missingUpgrades = Object.values(RA_UNLOCKS)
|
||||
.filter(unlock => unlock.pet === this.petConfig.pet)
|
||||
.map(u => u.level)
|
||||
.filter(goal => goal > this.level);
|
||||
return missingUpgrades.length === 0 ? 25 : missingUpgrades.min();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="l-ra-pet-container" v-if="isUnlocked">
|
||||
<div class="c-ra-pet-header" :style="petStyle">
|
||||
<div class="c-ra-pet-title">{{ pet.name }} Lvl. {{ shortenSmallInteger(level) }}</div>
|
||||
<div v-if="level >= 2">{{ scalingUpgradeText }}</div>
|
||||
<div>{{ experienceInformation }}</div>
|
||||
<div class="c-ra-pet-title">{{ name }} Level {{ formatInt(level) }}</div>
|
||||
<div v-if="showScalingUpgrade"
|
||||
:key="level">
|
||||
{{ scalingUpgradeText }}
|
||||
</div>
|
||||
<div v-else>
|
||||
<br>
|
||||
</div>
|
||||
<div v-if="level < 25">
|
||||
<div>
|
||||
{{ format(exp, 2) }} / {{ format(requiredExp, 2) }} {{ name }} memories
|
||||
</div>
|
||||
<div>
|
||||
(next level in {{ nextLevelEstimate }})
|
||||
</div>
|
||||
<div>
|
||||
(next upgrade in {{ upgradeEstimate }})
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<br>
|
||||
</div>
|
||||
<ra-pet-level-bar :pet="petConfig.pet" />
|
||||
<div v-if="level < 25">
|
||||
<div>
|
||||
{{ format(memoryChunks, 2, 2) }} memory chunks, {{ format(memoriesPerSecond, 2, 2) }} memories/sec
|
||||
</div>
|
||||
<div>
|
||||
Gaining {{ format(memoryChunksPerSecond, 2, 2) }} memory chunks/sec
|
||||
<span :ach-tooltip="chunkTooltip">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
Capped at Level {{ formatInt(level) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="memoryMultiplier > 1">
|
||||
Multiplying all memory production by {{ format(memoryMultiplier, 2, 3) }}
|
||||
<span :ach-tooltip="memoryGainTooltip">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<br>
|
||||
</div>
|
||||
<br>
|
||||
<div style="display: flex; justify-content: center;">
|
||||
<!-- This choice of key forces a UI update every level up -->
|
||||
<ra-upgrade-icon v-for="(unlock, i) in unlocks"
|
||||
:key="25 * level + i"
|
||||
:unlock="unlock" />
|
||||
</div>
|
||||
</div>
|
||||
<ra-pet-level-bar :pet="pet" />
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
@ -3,94 +3,144 @@
|
||||
Vue.component("ra-tab", {
|
||||
data() {
|
||||
return {
|
||||
expMults: [0, 0, 0, 0],
|
||||
currentExpGain: 0,
|
||||
memoriesPerChunk: 0,
|
||||
showReality: false,
|
||||
showLaitela: false
|
||||
totalLevels: 0,
|
||||
hasRecollection: false,
|
||||
recollectionReq: 0,
|
||||
recollectionMult: 1,
|
||||
showLaitela: false,
|
||||
laitelaReq: 0,
|
||||
petWithRecollection: "",
|
||||
isRunning: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.expMults = this.pets.map(obj => obj.pet.expBoost);
|
||||
this.currentExpGain = Ra.pets.teresa.baseExp;
|
||||
this.showReality = Ra.pets.teresa.level > 2;
|
||||
this.memoriesPerChunk = Ra.productionPerMemoryChunk();
|
||||
this.totalLevels = Ra.totalPetLevel;
|
||||
this.hasRecollection = Ra.has(RA_UNLOCKS.RA_RECOLLECTION_UNLOCK);
|
||||
this.recollectionReq = RA_UNLOCKS.RA_RECOLLECTION_UNLOCK.totalLevels;
|
||||
this.recollectionMult = RA_UNLOCKS.RA_RECOLLECTION_UNLOCK.effect;
|
||||
this.showLaitela = Ra.pets.v.isUnlocked;
|
||||
this.laitelaReq = RA_UNLOCKS.RA_LAITELA_UNLOCK.totalLevels;
|
||||
this.petWithRecollection = Ra.petWithRecollection;
|
||||
this.isRunning = Ra.isRunning;
|
||||
},
|
||||
startRun() {
|
||||
Ra.startRun();
|
||||
if (!resetReality()) return;
|
||||
Ra.initializeRun();
|
||||
},
|
||||
toggleMode() {
|
||||
Ra.toggleMode();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
laitelaUnlock: () => RA_LAITELA_UNLOCK,
|
||||
laitelaUnlock: () => RA_UNLOCKS.RA_LAITELA_UNLOCK,
|
||||
pets: () => [
|
||||
{
|
||||
pet: Ra.pets.teresa,
|
||||
scalingUpgradeText: () => `You can charge ${shortenSmallInteger(Ra.totalCharges)} Infinity Upgrades.`,
|
||||
scalingUpgradeVisible: () => Ra.totalCharges > 0,
|
||||
scalingUpgradeText: () => `You can charge ${formatInt(Ra.totalCharges)}
|
||||
Infinity ${pluralize("Upgrade", Ra.totalCharges)}.`,
|
||||
},
|
||||
{
|
||||
pet: Ra.pets.effarig,
|
||||
scalingUpgradeText: level => `Glyph rarity +${level}% and +${shortenSmallInteger(Math.floor(level / 5))}
|
||||
additional choices.`,
|
||||
scalingUpgradeVisible: () => AlchemyResources.all.filter(r => r.isUnlocked).length > 0,
|
||||
scalingUpgradeText: () => {
|
||||
const resources = AlchemyResources.all.filter(r => r.isUnlocked).length;
|
||||
return `You have unlocked ${formatInt(resources)} alchemy ${pluralize("resource", resources)}.`;
|
||||
},
|
||||
},
|
||||
{
|
||||
pet: Ra.pets.enslaved,
|
||||
scalingUpgradeText: () => `Stored game time ^
|
||||
${shorten(RA_UNLOCKS.IMPROVED_STORED_TIME.effect.gameTimeAmplification(), 0, 2)}, stored real time efficiency
|
||||
+${formatPercents(RA_UNLOCKS.IMPROVED_STORED_TIME.effect.realTimeEfficiency(), 0, 2)} and
|
||||
+${shorten(RA_UNLOCKS.IMPROVED_STORED_TIME.effect.realTimeCap() / 1000 / 3600, 0, 1)} hours maximum.`,
|
||||
scalingUpgradeVisible: () => Ra.has(RA_UNLOCKS.IMPROVED_STORED_TIME),
|
||||
scalingUpgradeText: () => `Stored game time
|
||||
${formatPow(RA_UNLOCKS.IMPROVED_STORED_TIME.effect.gameTimeAmplification(), 0, 2)} and real time
|
||||
+${formatInt(RA_UNLOCKS.IMPROVED_STORED_TIME.effect.realTimeCap() / (1000 * 3600))} hours`,
|
||||
},
|
||||
{
|
||||
pet: Ra.pets.v,
|
||||
scalingUpgradeText: level => `+${shortenSmallInteger(level)} free achievements.`,
|
||||
scalingUpgradeVisible: () => Math.clampMax(Math.floor(Ra.pets.v.level / 5), 4) > 0,
|
||||
scalingUpgradeText: level => {
|
||||
const triadCount = Math.clampMax(Math.floor(level / 5), 4);
|
||||
return `You have unlocked ${formatInt(triadCount)} triad ${pluralize("study", triadCount, "studies")}.`;
|
||||
},
|
||||
}
|
||||
]
|
||||
],
|
||||
petStyle() {
|
||||
return {
|
||||
color: (this.petWithRecollection === "")
|
||||
? "white"
|
||||
: this.pets.find(pet => pet.pet.name === this.petWithRecollection).pet.color,
|
||||
};
|
||||
},
|
||||
runButtonClassObject() {
|
||||
return {
|
||||
"c-ra-run-button__icon": true,
|
||||
"c-ra-run-button__icon--running": this.isRunning,
|
||||
};
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-ra-celestial-tab">
|
||||
template: `
|
||||
<div class="l-ra-celestial-tab">
|
||||
<div class="c-ra-memory-header">
|
||||
You will gain {{ shorten(this.currentExpGain, 2, 2) }}{{ showReality ? " base" : ""}}
|
||||
memories on Reality, based on glyph level.
|
||||
Each memory chunk generates
|
||||
{{ format(memoriesPerChunk, 2, 3) }} {{ "memory" | pluralize(memoriesPerChunk, "memories") }}
|
||||
per second.
|
||||
</div>
|
||||
<div>
|
||||
Mouse-over bolded numbers to see descriptions of upgrades you have already unlocked.
|
||||
Hold shift to see progress on your current level.
|
||||
</div>
|
||||
<div>
|
||||
Mouse-over the icons below the bar to see descriptions of upgrades,
|
||||
<br>
|
||||
and mouse-over <i class="fas fa-question-circle"></i> icons for specific resource information.
|
||||
</div>
|
||||
<div class="l-ra-all-pets-container">
|
||||
<ra-pet v-for="(pet, i) in pets" :key="i" :petConfig="pet" />
|
||||
</div>
|
||||
<div class="l-ra-non-pets">
|
||||
<button @click="startRun" class="l-ra-reality-container" v-if="showReality">
|
||||
<div class="l-ra-reality-inner">
|
||||
<h1> Start Ra's Reality</h1>
|
||||
<p> Rules: You can't dimension boost and tick reduction is forced to be 11%. </p>
|
||||
<br>
|
||||
<br>
|
||||
<h2> Memory multipliers: </h2>
|
||||
<div class="c-ra-rewards">
|
||||
<span class="c-ra-rewards-inner"> Teresa: {{formatX(expMults[0], 2, 2)}} </span>
|
||||
<span
|
||||
class="c-ra-rewards-inner"
|
||||
v-if="pets[1].pet.isUnlocked"> Effarig: {{formatX(expMults[1], 2, 2)}} </span>
|
||||
</div>
|
||||
<div class="c-ra-rewards">
|
||||
<span
|
||||
class="c-ra-rewards-inner"
|
||||
v-if="pets[2].pet.isUnlocked"> Enslaved: {{formatX(expMults[2], 2, 2)}} </span>
|
||||
<span
|
||||
class="c-ra-rewards-inner"
|
||||
v-if="pets[3].pet.isUnlocked"> V: {{formatX(expMults[3], 2, 2)}} </span>
|
||||
</div>
|
||||
<button class="c-ra-run-button">
|
||||
<h2> Start Ra's Reality </h2>
|
||||
<div :class="runButtonClassObject" @click="startRun">
|
||||
<span class="c-ra-run-button__icon__sigil fas fa-sun"></span>
|
||||
</div>
|
||||
You can't Dimension Boost, and the Tickspeed purchase multiplier is fixed at {{ formatX(1.1245, 0, 3) }}.
|
||||
<br>
|
||||
<br>
|
||||
Inside of Ra's reality, some resources will generate memory chunks based on their amount.
|
||||
</button>
|
||||
<div class="l-ra-recollection-unlock">
|
||||
<br>
|
||||
<h1 :style="petStyle">Recollection</h1>
|
||||
<span :style="petStyle">
|
||||
Whichever celestial has recollection will get {{formatX(recollectionMult)}} memory chunk gain.
|
||||
</span>
|
||||
<div class="l-ra-recollection-unlock-inner" v-if="hasRecollection">
|
||||
<ra-pet-recollection-button
|
||||
v-for="(pet, i) in pets"
|
||||
:key="i"
|
||||
:petConfig="pet" />
|
||||
</div>
|
||||
<div v-else class="l-ra-recollection-unlock-inner">
|
||||
Unlocked by getting {{ formatInt(recollectionReq) }} total Celestial Memory levels
|
||||
(you need {{formatInt(recollectionReq - totalLevels)}} more)
|
||||
</div>
|
||||
</div>
|
||||
<button class="l-ra-laitela-unlock" v-if="showLaitela">
|
||||
<div class="l-ra-laitela-unlock-inner">
|
||||
<h1> Lai'tela: </h1>
|
||||
<h2> The Celestial of Matter </h2>
|
||||
<p> Unlocked getting all four celestials to level {{ shortenSmallInteger(20) }} </p>
|
||||
<h2> The Celestial of Dimensions </h2>
|
||||
<p>
|
||||
Unlocked by getting {{ formatInt(laitelaReq) }} total Celestial Memory levels
|
||||
<span v-if="totalLevels < laitelaReq">
|
||||
(you need {{formatInt(laitelaReq - totalLevels)}} more)
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>`
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("ra-upgrade-icon", {
|
||||
props: {
|
||||
unlock: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
level: 0,
|
||||
icon: "",
|
||||
description: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
update() {
|
||||
this.isUnlocked = Ra.has(this.unlock);
|
||||
this.level = this.unlock.level;
|
||||
this.icon = this.unlock.displayIcon;
|
||||
const rewardText = typeof this.unlock.reward === "function"
|
||||
? this.unlock.reward()
|
||||
: this.unlock.reward;
|
||||
this.description = `Level ${this.level}: ${rewardText}`;
|
||||
},
|
||||
classObject() {
|
||||
return {
|
||||
"c-ra-upgrade-icon": true,
|
||||
"c-ra-upgrade-icon--inactive": !this.isUnlocked,
|
||||
};
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
v-html="icon"
|
||||
:ach-tooltip="description"
|
||||
:class="classObject">
|
||||
</div>
|
||||
`
|
||||
});
|
@ -4,110 +4,53 @@ Vue.component("modal-reality-glyph-creation", {
|
||||
data() {
|
||||
return {
|
||||
realityGlyphLevel: 0,
|
||||
// This contains an array where each entry is an array looking like [4000, "realitygalaxies"]
|
||||
possibleEffects: [],
|
||||
selectedEffects: [],
|
||||
maxEffects: 0,
|
||||
effectCriteria: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.realityGlyphLevel = AlchemyResource.reality.effectValue;
|
||||
this.possibleEffects = orderedEffectList.filter(effect => !effect.match("effarig*"));
|
||||
this.maxEffects = this.calculateMaxEffects();
|
||||
this.effectCriteria = this.effectCriteriaList();
|
||||
},
|
||||
calculateMaxEffects() {
|
||||
return this.effectCriteriaList().filter(c => c.value).length;
|
||||
},
|
||||
effectCriteriaList() {
|
||||
const sumOfOtherAlchemyResources = AlchemyResources.all
|
||||
.filter(r => r !== AlchemyResource.reality)
|
||||
.map(r => r.amount)
|
||||
.sum();
|
||||
const highestLevelGlyph = player.reality.glyphs.active
|
||||
.concat(player.reality.glyphs.inventory)
|
||||
.map(glyph => glyph.level)
|
||||
.max();
|
||||
return [
|
||||
{
|
||||
desc: `At least ${shortenSmallInteger(5000)} Reality consumed for this glyph (Currently ` +
|
||||
`${shortenSmallInteger(AlchemyResource.reality.amount)})`,
|
||||
value: AlchemyResource.reality.amount >= 5000
|
||||
},
|
||||
{
|
||||
desc: `${shortenSmallInteger(150000)} total of all other alchemy resources (Currently ` +
|
||||
`${shortenSmallInteger(sumOfOtherAlchemyResources)})`,
|
||||
value: sumOfOtherAlchemyResources >= 150000
|
||||
},
|
||||
{
|
||||
desc: `${shorten(1e60, 0, 0)} relic shards (Currently ` +
|
||||
`${shorten(player.celestials.effarig.relicShards, 2, 2)})`,
|
||||
value: player.celestials.effarig.relicShards >= 1e60
|
||||
},
|
||||
{
|
||||
desc: `A glyph with a level of at least ${shortenSmallInteger(12000)}, which is not consumed (highest: ` +
|
||||
`${shortenSmallInteger(highestLevelGlyph)})`,
|
||||
value: highestLevelGlyph >= 12000
|
||||
}
|
||||
];
|
||||
const realityEffectConfigs = Object.values(GameDatabase.reality.glyphEffects)
|
||||
.filter(eff => eff.id.match("reality*"))
|
||||
.sort((a, b) => a.bitmaskIndex - b.bitmaskIndex);
|
||||
const minRealityEffectIndex = realityEffectConfigs.map(cfg => cfg.bitmaskIndex).min();
|
||||
this.possibleEffects = realityEffectConfigs
|
||||
.map(cfg => [realityGlyphEffectLevelThresholds[cfg.bitmaskIndex - minRealityEffectIndex], cfg.id]);
|
||||
},
|
||||
createRealityGlyph() {
|
||||
if (Glyphs.freeInventorySpace === 0) {
|
||||
Modal.message.show("Inventory cannot hold new glyphs. Delete/sacrifice (shift-click) some glyphs.");
|
||||
return;
|
||||
}
|
||||
Glyphs.addToInventory(GlyphGenerator.realityGlyph(
|
||||
{ actualLevel: this.realityGlyphLevel, rawLevel: this.realityGlyphLevel }, this.selectedEffects));
|
||||
AlchemyResources.resetAmount();
|
||||
// If the player leaves a choice open, don't spend shards
|
||||
if (player.celestials.effarig.relicShards >= 1e60 && (this.selectedEffects === this.calculateMaxEffects())) {
|
||||
player.celestials.effarig.relicShards -= 1e60;
|
||||
}
|
||||
for (const reaction of AlchemyReactions.all.compact()) {
|
||||
reaction.isActive = false;
|
||||
}
|
||||
Glyphs.addToInventory(GlyphGenerator.realityGlyph(this.realityGlyphLevel));
|
||||
AlchemyResource.reality.amount = 0;
|
||||
this.emitClose();
|
||||
},
|
||||
formatGlyphEffect(effect) {
|
||||
const config = GameDatabase.reality.glyphEffects[effect];
|
||||
if (this.realityGlyphLevel < effect[0]) return `(Requires glyph level ${formatInt(effect[0])})`;
|
||||
const config = GameDatabase.reality.glyphEffects[effect[1]];
|
||||
const value = config.effect(this.realityGlyphLevel, rarityToStrength(100));
|
||||
const effectTemplate = typeof config.singleDesc === "function"
|
||||
? config.singleDesc()
|
||||
: config.singleDesc;
|
||||
const effectText = effectTemplate
|
||||
.replace("{value}", config.formatEffect(value))
|
||||
.replace("[", "")
|
||||
.replace("]", "");
|
||||
if (config.conversion === undefined) return effectText;
|
||||
return effectText.replace("{value2}", config.formatEffect(config.conversion(value)));
|
||||
return effectTemplate.replace("{value}", config.formatEffect(value));
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="c-reality-glyph-creation">
|
||||
<modal-close-button @click="emitClose"/>
|
||||
<div>
|
||||
Create a level {{ shortenSmallInteger(realityGlyphLevel) }} reality glyph. Rarity will always be 100% and level
|
||||
is unaffected by the glyph level cap. This will reset all alchemy resources.
|
||||
<div>
|
||||
Create a level {{ formatInt(realityGlyphLevel) }} reality glyph. Rarity will always be 100% and level
|
||||
scales on your current reality resource amount (which is all consumed). All other alchemy resources will be
|
||||
unaffected. Reality glyphs have unique effects, some of which are only available with higher level glyphs.
|
||||
Reality glyphs can also be sacrificed to increase the yield from alchemy reactions. Like Effarig glyphs,
|
||||
you cannot equip more than one at the same time.
|
||||
</div><br>
|
||||
<div>
|
||||
Reality glyphs always have {{ shortenSmallInteger(4) }} effects picked from any of the
|
||||
{{ shortenSmallInteger(5) }} basic glyph types; you can choose up to {{ shortenSmallInteger(maxEffects) }},
|
||||
based on how many of the below requirements you meet. The rest of the effects, if any, are chosen randomly.
|
||||
<div v-for="criterion in effectCriteria">
|
||||
<span v-if="criterion.value">+</span>
|
||||
<span v-else>-</span>
|
||||
{{ criterion.desc }}
|
||||
</div><br>
|
||||
</div>
|
||||
<div>
|
||||
Possible Effects:
|
||||
Available Effects:
|
||||
</div>
|
||||
<div v-for="effect in possibleEffects">
|
||||
<input type="checkbox"
|
||||
:value="effect"
|
||||
:disabled="selectedEffects.length >= maxEffects && !selectedEffects.includes(effect)"
|
||||
v-model="selectedEffects">
|
||||
{{ formatGlyphEffect(effect) }}
|
||||
</div><br>
|
||||
<button class="o-primary-btn" v-on:click="createRealityGlyph()">Create a Reality glyph!</button>
|
||||
|
@ -1,80 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("time-compression-tab", {
|
||||
data() {
|
||||
return {
|
||||
entanglement: 0,
|
||||
totalEntanglement: 0,
|
||||
respec: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
respec(newValue) {
|
||||
player.celestials.ra.compression.respec = newValue;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
upgrades() {
|
||||
return [
|
||||
[
|
||||
CompressionUpgrade.freeBoost,
|
||||
CompressionUpgrade.improvedDTMult,
|
||||
CompressionUpgrade.replicantiSpeedFromDB
|
||||
],
|
||||
[
|
||||
CompressionUpgrade.strongerDilationGalaxies,
|
||||
CompressionUpgrade.freeGalaxySoftcap,
|
||||
CompressionUpgrade.freeGalaxyScaling
|
||||
],
|
||||
[
|
||||
CompressionUpgrade.infDimSoftcap,
|
||||
CompressionUpgrade.moreEntanglement,
|
||||
CompressionUpgrade.matterBoost
|
||||
],
|
||||
];
|
||||
},
|
||||
respecClassObject() {
|
||||
return {
|
||||
"o-primary-btn--respec-options": true,
|
||||
"o-primary-btn--respec-active": this.respec
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.entanglement = TimeCompression.entanglement;
|
||||
this.totalEntanglement = TimeCompression.totalEntanglement;
|
||||
this.respec = player.celestials.ra.compression.respec;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-dilation-tab">
|
||||
<span>
|
||||
You have
|
||||
<span class="c-dilation-tab__tachyons">{{shorten(entanglement, 2, 2)}}</span>
|
||||
Entanglement.
|
||||
</span>
|
||||
<span>
|
||||
Your total entanglement is {{shorten(totalEntanglement, 2, 2)}}.
|
||||
</span>
|
||||
<compression-button />
|
||||
<span>
|
||||
Time compression is a stronger type of dilation which dilates values twice, <br>
|
||||
disables time dimensions, and causes the game to run {{ shorten(1e100) }} times slower.
|
||||
</span>
|
||||
<div class="l-dilation-upgrades-grid">
|
||||
<div v-for="row in upgrades" class="l-dilation-upgrades-grid__row">
|
||||
<compression-upgrade
|
||||
v-for="upgrade in row"
|
||||
:key="upgrade.id"
|
||||
:upgrade="upgrade"
|
||||
class="l-dilation-upgrades-grid__cell"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<primary-button
|
||||
:class="respecClassObject"
|
||||
@click="respec = !respec"
|
||||
>Respec compression upgrades on Reality</primary-button>
|
||||
</div>`
|
||||
});
|
@ -6,7 +6,7 @@ Vue.component("perk-shop-upgrade", {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isAvailable: false,
|
||||
isAvailableForPurchase: false,
|
||||
isCapped: false,
|
||||
};
|
||||
},
|
||||
@ -14,24 +14,23 @@ Vue.component("perk-shop-upgrade", {
|
||||
classObject() {
|
||||
return {
|
||||
"o-teresa-shop-button": true,
|
||||
"o-teresa-shop-button--disabled": !this.isAvailable && !this.isCapped,
|
||||
"o-teresa-shop-button--available": this.isAvailableForPurchase && !this.isCapped,
|
||||
"o-teresa-shop-button--capped": this.isCapped
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isAvailable = this.upgrade.isAvailable;
|
||||
this.isAvailableForPurchase = this.upgrade.isAvailableForPurchase;
|
||||
this.isCapped = this.upgrade.isCapped;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-spoon-btn-group">
|
||||
<button :class="classObject" @click="upgrade.purchase()">
|
||||
<description-display
|
||||
<description-display
|
||||
:config="upgrade.config"
|
||||
:length="70"
|
||||
name="o-compression-upgrade__description"
|
||||
/>
|
||||
<br>
|
||||
<effect-display :config="upgrade.config" />
|
||||
@ -44,4 +43,4 @@ Vue.component("perk-shop-upgrade", {
|
||||
/>
|
||||
</button>
|
||||
</div>`
|
||||
});
|
||||
});
|
||||
|
@ -10,11 +10,14 @@ Vue.component("teresa-tab", {
|
||||
percentage: "",
|
||||
rmMult: 0,
|
||||
bestAM: new Decimal(0),
|
||||
lastRM: new Decimal(0),
|
||||
runReward: 0,
|
||||
pp: 0,
|
||||
hasReality: false,
|
||||
hasEPGen: false,
|
||||
hasPerkShop: false,
|
||||
isRunning: false,
|
||||
canUnlockNextPour: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -28,6 +31,20 @@ Vue.component("teresa-tab", {
|
||||
PerkShopUpgrade.autoSpeed,
|
||||
PerkShopUpgrade.musicGlyph,
|
||||
];
|
||||
},
|
||||
runButtonClassObject() {
|
||||
return {
|
||||
"c-teresa-run-button__icon": true,
|
||||
"c-teresa-run-button__icon--running": this.isRunning,
|
||||
};
|
||||
},
|
||||
pourButtonClassObject() {
|
||||
return {
|
||||
"o-teresa-shop-button": true,
|
||||
"o-teresa-shop-button--available": true,
|
||||
"c-teresa-pour": true,
|
||||
"c-teresa-pour--unlock-available": this.canUnlockNextPour
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -39,18 +56,23 @@ Vue.component("teresa-tab", {
|
||||
}
|
||||
this.time = now;
|
||||
this.rmStore = player.celestials.teresa.rmStore;
|
||||
this.percentage = formatPercents(Teresa.fill, 2);
|
||||
this.percentage = Notations.current.name === "Blind" ? "0%" : `${(Teresa.fill * 100).toFixed(2)}%`;
|
||||
this.rmMult = Teresa.rmMultiplier;
|
||||
this.hasReality = Teresa.has(TERESA_UNLOCKS.RUN);
|
||||
this.hasEPGen = Teresa.has(TERESA_UNLOCKS.EPGEN);
|
||||
this.hasPerkShop = Teresa.has(TERESA_UNLOCKS.SHOP);
|
||||
this.bestAM.copyFrom(player.celestials.teresa.bestRunAM);
|
||||
this.lastRM.copyFrom(player.celestials.teresa.lastRepeatedRM);
|
||||
this.runReward = Teresa.runRewardMultiplier;
|
||||
this.pp = player.reality.pp;
|
||||
this.rm.copyFrom(player.reality.realityMachines);
|
||||
this.isRunning = Teresa.isRunning;
|
||||
this.canUnlockNextPour = Object.values(TERESA_UNLOCKS)
|
||||
.filter(unlock => this.rm.plus(this.rmStore).gte(unlock.price) && !Teresa.has(unlock)).length > 0;
|
||||
},
|
||||
startRun() {
|
||||
Teresa.startRun();
|
||||
if (!resetReality()) return;
|
||||
Teresa.initializeRun();
|
||||
},
|
||||
unlockDescriptionStyle(unlockInfo) {
|
||||
const maxPrice = Teresa.unlockInfo[Teresa.lastUnlock].price;
|
||||
@ -60,33 +82,35 @@ Vue.component("teresa-tab", {
|
||||
};
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<div class="l-teresa-celestial-tab">
|
||||
template: `
|
||||
<div class="l-teresa-celestial-tab">
|
||||
<celestial-quote-history celestial="teresa"/>
|
||||
<div>You have {{shorten(rm, 2, 2)}} {{"Reality Machine" | pluralize(rm)}}.</div>
|
||||
<div>You have {{format(rm, 2, 2)}} {{"Reality Machine" | pluralize(rm)}}.</div>
|
||||
<div class="l-mechanics-container">
|
||||
<div class="l-teresa-unlocks l-teresa-mechanic-container">
|
||||
<div class="c-teresa-unlock c-teresa-run-button" v-if="hasReality" @click="startRun()">
|
||||
<div class="l-teresa-mechanic-container" v-if="hasReality">
|
||||
<div class="c-teresa-unlock c-teresa-run-button">
|
||||
<div :class="runButtonClassObject" @click="startRun()">Ϟ</div>
|
||||
Start Teresa's Reality. Glyph TT generation is disabled and
|
||||
you gain less IP and EP (x^{{shorten(0.55, 2, 2)}}).
|
||||
you gain less IP and EP (x^{{format(0.55, 2, 2)}}).
|
||||
<br><br>
|
||||
Highest antimatter in Teresa's Reality: {{ shorten(bestAM, 2, 0) }}
|
||||
<div v-if="bestAM.gt(0)">
|
||||
Highest antimatter in Teresa's Reality: {{ format(bestAM, 2) }}
|
||||
<br><br>
|
||||
You last did Teresa's Reality at {{ format(lastRM, 2) }} RM.
|
||||
</div>
|
||||
<div v-else>
|
||||
You have not completed Teresa's Reality yet.
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-teresa-unlock" v-if="hasReality">
|
||||
<div class="c-teresa-unlock">
|
||||
Teresa Reality reward: Glyph sacrifice power {{ formatX(runReward, 2, 2) }}
|
||||
</div>
|
||||
<div class="c-teresa-unlock" v-if="hasEPGen">You gain 1% of your peaked EP/min every second.</div>
|
||||
<div class="c-teresa-shop" v-if="hasPerkShop">
|
||||
<span class="o-teresa-pp"> You have {{ shorten(pp, 2, 0) }} {{"Perk Point" | pluralize(pp)}}.</span>
|
||||
<perk-shop-upgrade
|
||||
v-for="upgrade in upgrades"
|
||||
:key="upgrade.id"
|
||||
:upgrade="upgrade"
|
||||
/>
|
||||
<div class="c-teresa-unlock" v-if="hasEPGen">
|
||||
You gain {{ formatPercents(0.01) }} of your peaked EP/min every second.
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-rm-container l-teresa-mechanic-container">
|
||||
<button class="o-primary-btn c-teresa-pour"
|
||||
<button :class="pourButtonClassObject"
|
||||
@mousedown="pour = true"
|
||||
@touchstart="pour = true"
|
||||
@mouseup="pour = false"
|
||||
@ -95,19 +119,27 @@ Vue.component("teresa-tab", {
|
||||
>Pour RM</button>
|
||||
<div class="c-rm-store">
|
||||
<div class="c-rm-store-inner" :style="{ height: percentage}">
|
||||
<div class="c-rm-store-label"> {{ shorten(rmMult, 2, 2) }}x RM gain
|
||||
<br>{{ shorten(rmStore, 2, 2) }}/{{ shorten(rmStoreMax, 2, 2) }}
|
||||
<div class="c-rm-store-label"> {{ formatX(rmMult, 2, 2) }} RM gain
|
||||
<br>{{ format(rmStore, 2, 2) }}/{{ format(rmStoreMax, 2, 2) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="unlockInfo in unlockInfo"
|
||||
class="c-teresa-unlock-description"
|
||||
:style="unlockDescriptionStyle(unlockInfo)"
|
||||
:id="unlockInfo.id">
|
||||
{{ shorten(unlockInfo.price, 2, 2) }}: {{ unlockInfo.description }}
|
||||
{{ format(unlockInfo.price, 2, 2) }}: {{ unlockInfo.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-unlock-descriptions l-teresa-mechanic-container"></div>
|
||||
<div class="l-rm-container-labels l-teresa-mechanic-container"/>
|
||||
<div class="c-teresa-shop" v-if="hasPerkShop">
|
||||
<span class="o-teresa-pp"> You have {{ format(pp, 2, 0) }} {{"Perk Point" | pluralize(pp)}}.</span>
|
||||
<perk-shop-upgrade
|
||||
v-for="upgrade in upgrades"
|
||||
:key="upgrade.id"
|
||||
:upgrade="upgrade"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
||||
|
@ -5,105 +5,193 @@ Vue.component("v-tab", {
|
||||
return {
|
||||
mainUnlock: false,
|
||||
totalUnlocks: 0,
|
||||
totalAdditionalStudies: 0,
|
||||
achievementsPerAdditionalStudy: 0,
|
||||
realities: 0,
|
||||
infinities: new Decimal(0),
|
||||
eternities: new Decimal(0),
|
||||
dilatedTime: new Decimal(0),
|
||||
replicanti: new Decimal(0),
|
||||
rm: new Decimal(0),
|
||||
runRecords: Array.from(player.celestials.v.runRecords),
|
||||
runGlyphs: player.celestials.v.runGlyphs.map(g => this.copyGlyphs(g)),
|
||||
pp: 0,
|
||||
showReduction: false,
|
||||
runRecords: [],
|
||||
runGlyphs: [],
|
||||
isFlipped: false,
|
||||
isRunning: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.mainUnlock = V.has(V_UNLOCKS.MAIN_UNLOCK);
|
||||
this.totalUnlocks = V.totalRunUnlocks;
|
||||
this.totalAdditionalStudies = V.totalAdditionalStudies;
|
||||
this.achievementsPerAdditionalStudy = V.achievementsPerAdditionalStudy;
|
||||
this.mainUnlock = V.has(V_UNLOCKS.V_ACHIEVEMENT_UNLOCK);
|
||||
this.totalUnlocks = V.spaceTheorems;
|
||||
this.realities = player.realities;
|
||||
this.infinities.copyFrom(player.infinitied);
|
||||
this.eternities.copyFrom(player.eternities);
|
||||
this.dilatedTime.copyFrom(player.dilation.dilatedTime);
|
||||
this.replicanti.copyFrom(player.replicanti.amount);
|
||||
this.rm.copyFrom(player.reality.realityMachines);
|
||||
this.pp = player.reality.pp;
|
||||
this.showReduction = V.has(V_UNLOCKS.SHARD_REDUCTION);
|
||||
this.runRecords = Array.from(player.celestials.v.runRecords);
|
||||
this.runGlyphs = player.celestials.v.runGlyphs.map(g => this.copyGlyphs(g));
|
||||
},
|
||||
copyGlyphs(glyphList) {
|
||||
return glyphList.map(g => ({
|
||||
type: g.type,
|
||||
level: g.level,
|
||||
strength: g.strength,
|
||||
effects: g.effects,
|
||||
}));
|
||||
this.runGlyphs = player.celestials.v.runGlyphs.map(gList => Glyphs.copyForRecords(gList));
|
||||
this.isFlipped = V.isFlipped;
|
||||
this.isRunning = V.isRunning;
|
||||
},
|
||||
startRun() {
|
||||
V.startRun();
|
||||
if (!resetReality()) return;
|
||||
V.initializeRun();
|
||||
},
|
||||
has(info) {
|
||||
return V.has(info);
|
||||
},
|
||||
mode(hex) {
|
||||
return hex.config.mode === V_REDUCTION_MODE.SUBTRACTION ? "reduced" : "divided";
|
||||
},
|
||||
reductionValue(hex) {
|
||||
return hex.config.mode === V_REDUCTION_MODE.SUBTRACTION
|
||||
? formatInt(hex.reduction)
|
||||
: format(Decimal.pow10(hex.reduction));
|
||||
},
|
||||
showRecord(hex) {
|
||||
return this.runRecords[hex.id] > 0 || hex.completions > 0;
|
||||
},
|
||||
rewardText(milestone) {
|
||||
return typeof milestone.reward === "function"
|
||||
? milestone.reward()
|
||||
: milestone.reward;
|
||||
},
|
||||
reduceGoals(hex) {
|
||||
if (player.reality.pp < hex.reductionCost) return;
|
||||
player.reality.pp -= hex.reductionCost;
|
||||
const steps = hex.config.reductionStepSize ? hex.config.reductionStepSize : 1;
|
||||
player.celestials.v.goalReductionSteps[hex.id] += steps;
|
||||
},
|
||||
reductionTooltip(hex) {
|
||||
return `Spend ${format(hex.reductionCost, 2, 0)} PP to reduce goal by ${format(hex.config.perReductionStep)}`;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hexGrid: () => [
|
||||
VRunUnlocks.all[0],
|
||||
VRunUnlocks.all[1],
|
||||
{},
|
||||
VRunUnlocks.all[2],
|
||||
{ isRunButton: true },
|
||||
VRunUnlocks.all[3],
|
||||
VRunUnlocks.all[4],
|
||||
VRunUnlocks.all[5],
|
||||
{}
|
||||
],
|
||||
runMilestones: () => V_UNLOCKS.RUN_UNLOCK_THRESHOLDS,
|
||||
// If V is flipped, change the layout of the grid
|
||||
hexGrid() {
|
||||
return this.isFlipped ? [
|
||||
VRunUnlocks.all[6],
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{ isRunButton: true },
|
||||
VRunUnlocks.all[7],
|
||||
VRunUnlocks.all[8],
|
||||
{},
|
||||
{}
|
||||
]
|
||||
: [
|
||||
VRunUnlocks.all[0],
|
||||
VRunUnlocks.all[1],
|
||||
{},
|
||||
VRunUnlocks.all[2],
|
||||
{ isRunButton: true },
|
||||
VRunUnlocks.all[3],
|
||||
VRunUnlocks.all[4],
|
||||
VRunUnlocks.all[5],
|
||||
{}
|
||||
];
|
||||
},
|
||||
vUnlock: () => V_UNLOCKS.V_ACHIEVEMENT_UNLOCK,
|
||||
runMilestones() {
|
||||
return [
|
||||
[
|
||||
V_UNLOCKS.SHARD_REDUCTION,
|
||||
V_UNLOCKS.ND_POW,
|
||||
V_UNLOCKS.FAST_AUTO_EC
|
||||
],
|
||||
[
|
||||
V_UNLOCKS.AUTO_AUTOCLEAN,
|
||||
V_UNLOCKS.ACHIEVEMENT_BH,
|
||||
V_UNLOCKS.RA_UNLOCK
|
||||
],
|
||||
];
|
||||
},
|
||||
db: () => GameDatabase.celestials.v,
|
||||
runButtonClassObject() {
|
||||
return {
|
||||
"l-v-hexagon": true,
|
||||
"c-v-run-button": true,
|
||||
"c-v-run-button--running": this.isRunning,
|
||||
};
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-v-celestial-tab">
|
||||
template: `
|
||||
<div class="l-v-celestial-tab">
|
||||
<div v-if="!mainUnlock">
|
||||
You need {{ shorten(db.mainUnlock.realities, 2, 0) }} realities (currently {{ shorten(realities, 2, 0) }}),<br>
|
||||
{{ shorten(db.mainUnlock.eternities, 2, 0) }} eternities (currently {{ shorten(eternities, 2, 0) }}),<br>
|
||||
{{ shorten(db.mainUnlock.infinities, 2, 0) }} infinities (currently {{ shorten(infinities, 2, 0) }}),<br>
|
||||
{{ shorten(db.mainUnlock.dilatedTime, 2, 0) }} dilated time (currently {{ shorten(dilatedTime, 2, 0) }}),<br>
|
||||
{{ shorten(db.mainUnlock.replicanti, 2, 0) }} replicanti (currently {{ shorten(replicanti, 2, 0) }}),<br>
|
||||
and {{ shorten(db.mainUnlock.rm, 2, 0) }} RM (currently {{ shorten(rm, 2, 0) }})
|
||||
to unlock V, The Celestial of Achievements
|
||||
{{ format(rm, 2, 0) }} / {{ format(db.mainUnlock.rm, 2, 0) }} RM
|
||||
<br>
|
||||
{{ format(realities, 2, 0) }} / {{ format(db.mainUnlock.realities, 2, 0) }} realities
|
||||
<br>
|
||||
{{ format(eternities, 2, 0) }} / {{ format(db.mainUnlock.eternities, 2, 0) }} eternities
|
||||
<br>
|
||||
{{ format(infinities, 2, 0) }} / {{ format(db.mainUnlock.infinities, 2, 0) }} infinities
|
||||
<br>
|
||||
{{ format(dilatedTime, 2, 0) }} / {{ format(db.mainUnlock.dilatedTime, 2, 0) }} dilated time
|
||||
<br>
|
||||
{{ format(replicanti, 2, 0) }} / {{ format(db.mainUnlock.replicanti, 2, 0) }} replicanti
|
||||
<br>
|
||||
<div class="l-v-milestones-grid__row">
|
||||
<div class="o-v-milestone">
|
||||
<p>{{ vUnlock.description }}</p>
|
||||
<p>Reward: {{ rewardText(vUnlock) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="isFlipped">
|
||||
Cursed glyphs can be created in the Effarig tab, and the Black Hole can now be used to slow down time.
|
||||
<br>
|
||||
Each hard V-achievement will award {{ formatInt(2) }} Space Theorems instead of {{ formatInt(1) }}.
|
||||
<br>
|
||||
Goal reduction is significantly more expensive for hard V-achievements.
|
||||
</div>
|
||||
<div v-if="showReduction">
|
||||
You have {{ format(pp, 2, 0) }} {{ "Perk Point" | pluralize(pp) }}.
|
||||
</div>
|
||||
<div class="l-v-unlocks-container">
|
||||
<li v-for="hex in hexGrid">
|
||||
<li v-for="hex in hexGrid" :style= "[hex.isRunButton ? {} : {zIndex: -1}]">
|
||||
<div v-if="hex.config"
|
||||
class="l-v-hexagon c-v-unlock"
|
||||
:class="{ 'c-v-unlock-completed': hex.completions == 6 }">
|
||||
<p class="o-v-unlock-name">{{ hex.config.name }}</p>
|
||||
<p class="o-v-unlock-desc">{{ hex.formattedDescription }}</p>
|
||||
:class="{ 'c-v-unlock-completed': hex.completions === hex.config.values.length }">
|
||||
<p class="o-v-unlock-name"><br v-if="hex.canBeReduced && showReduction">{{ hex.config.name }}</p>
|
||||
<p class="o-v-unlock-desc" v-html="hex.formattedDescription"></p>
|
||||
<p class="o-v-unlock-goal-reduction" v-if="has(runMilestones[0]) && hex.isReduced">
|
||||
Goal has been {{ mode(hex) }} by {{ reductionValue(hex) }}
|
||||
</p>
|
||||
<p class="o-v-unlock-amount">{{ hex.completions }}/{{hex.config.values.length}} done</p>
|
||||
<p class="o-v-unlock-record">
|
||||
Best: {{ hex.config.formatRecord(runRecords[hex.id]) }}
|
||||
</p>
|
||||
<p v-if="runRecords[hex.id] > 0">
|
||||
<glyph-component v-for="(g, idx) in runGlyphs[hex.id]"
|
||||
:key="idx"
|
||||
style="margin: 0.2rem;"
|
||||
:glyph="g"
|
||||
:showSacrifice="false"
|
||||
:draggable="false"
|
||||
:circular="true"
|
||||
size="2.8rem"
|
||||
:textProportion="0.6"
|
||||
glowBlur="0.2rem"
|
||||
glowSpread="0.1rem" />
|
||||
</p>
|
||||
<div v-if="showRecord(hex)">
|
||||
<p class="o-v-unlock-record">
|
||||
Best: {{ hex.config.formatRecord(runRecords[hex.id]) }}
|
||||
</p>
|
||||
<p>
|
||||
<glyph-set-preview
|
||||
:show=true
|
||||
:glyphs="runGlyphs[hex.id]" />
|
||||
</p>
|
||||
<div v-if="hex.canBeReduced && showReduction">
|
||||
<div style="height:0.8rem;"/>
|
||||
<button
|
||||
class="o-primary-btn l-v-reduction"
|
||||
:class="{ 'o-primary-btn--disabled': !hex.canBeReduced || pp < hex.reductionCost }"
|
||||
:ach-tooltip="reductionTooltip(hex)"
|
||||
@click="reduceGoals(hex)">
|
||||
<i class="fas fa-angle-double-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="hex.isRunButton" @click="startRun()" class="l-v-hexagon o-v-run-button">
|
||||
<p>
|
||||
Start V's Reality.<br/>All dimension multipliers, EP gain, IP gain, and dilated time gain per second
|
||||
<div v-else-if="hex.isRunButton" @click="startRun()" :class="runButtonClassObject">
|
||||
<b style="font-size: 1.5rem">Start V's Reality.</b>
|
||||
<br/>
|
||||
All dimension multipliers, EP gain, IP gain, and Dilated Time gain per second
|
||||
are square-rooted, and Replicanti interval is squared.
|
||||
</p>
|
||||
<div class="c-v-run-button__line c-v-run-button__line--1"></div>
|
||||
<div class="c-v-run-button__line c-v-run-button__line--2"></div>
|
||||
<div class="c-v-run-button__line c-v-run-button__line--3"></div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div style="opacity: 0" class="l-v-hexagon"></div>
|
||||
@ -111,27 +199,24 @@ Vue.component("v-tab", {
|
||||
</li>
|
||||
</div>
|
||||
<div>
|
||||
V-achievements can only be completed within V's reality, but are permanent and do not reset upon leaving
|
||||
and re-entering the reality.
|
||||
V-achievements can only be completed within V's Reality, but are permanent and do not reset upon leaving
|
||||
and re-entering the Reality.
|
||||
</div>
|
||||
<div>
|
||||
You have {{ shortenSmallInteger(totalUnlocks) }} V-achievements done. You can pick
|
||||
{{ shortenSmallInteger(totalAdditionalStudies) }}
|
||||
{{ "study" | pluralize(totalAdditionalStudies, "studies") }} on other paths you normally can't buy.
|
||||
</div>
|
||||
<div>
|
||||
(You get one additional study per {{ shortenSmallInteger(achievementsPerAdditionalStudy) }}
|
||||
V-achievements, rounded down.)
|
||||
You have {{ formatInt(totalUnlocks) }} V-achievements done. You gain 1 Space Theorem for each completion,
|
||||
allowing you to purchase Time Studies which are normally locked.
|
||||
</div>
|
||||
<br>
|
||||
<div class="l-v-milestones-container">
|
||||
<div class="o-v-milestone"
|
||||
v-for="milestone in runMilestones"
|
||||
:class="{'o-v-milestone-unlocked':
|
||||
has(milestone)}">
|
||||
<p>{{ milestone.description }}</p>
|
||||
<p>Reward: {{ milestone.reward }}</p>
|
||||
<p v-if="milestone.effect">Currently: <b>{{ milestone.format(milestone.effect()) }}</b></p>
|
||||
<div class="l-v-milestones-grid">
|
||||
<div v-for="row in runMilestones" class="l-v-milestones-grid__row">
|
||||
<div class="o-v-milestone"
|
||||
v-for="milestone in row"
|
||||
:class="{'o-v-milestone--unlocked':
|
||||
has(milestone)}">
|
||||
<p>{{ milestone.description }}</p>
|
||||
<p>Reward: {{ rewardText(milestone) }}</p>
|
||||
<p v-if="milestone.effect">Currently: <b>{{ milestone.format(milestone.effect()) }}</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,33 +11,53 @@ Vue.component("challenge-box", {
|
||||
default: "",
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEC: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
update() {
|
||||
this.isEC = this.name.startsWith("EC");
|
||||
this.inC1 = this.name === "C1" && !this.isCompleted && NormalChallenge.current === undefined &&
|
||||
InfinityChallenge.current === undefined;
|
||||
},
|
||||
buttonClassObject() {
|
||||
const classObject = {
|
||||
"o-challenge-btn": true
|
||||
};
|
||||
if (this.isRunning) {
|
||||
if (this.isRunning || this.inC1) {
|
||||
classObject["o-challenge-btn--running"] = true;
|
||||
} else if (this.isCompleted) {
|
||||
} else if (this.isCompleted && ((this.isUnlocked && !this.isEC) || (!this.isUnlocked && this.isEC))) {
|
||||
classObject["o-challenge-btn--completed"] = true;
|
||||
} else if (this.isCompleted && this.isUnlocked && this.isEC) {
|
||||
classObject["o-challenge-btn--redo"] = true;
|
||||
} else if (this.isUnlocked) {
|
||||
classObject["o-challenge-btn--unlocked"] = true;
|
||||
} else {
|
||||
classObject["o-challenge-btn--locked"] = true;
|
||||
}
|
||||
// ECs can be not unlocked and also not locked, because they're fully completed,
|
||||
// but in that case you can't enter them and so it's important to give them a property
|
||||
// that disables cursor on hover. The same thing happens with challenges that are running,
|
||||
// of any type, and with Challenge 1.
|
||||
classObject["o-challenge-btn--unenterable"] = !this.isUnlocked || this.isRunning || this.name === "C1";
|
||||
return classObject;
|
||||
},
|
||||
buttonText() {
|
||||
if (this.overrideLabel.length) return this.overrideLabel;
|
||||
if (this.isRunning) return "Running";
|
||||
if (this.isCompleted) return "Completed";
|
||||
if (this.isRunning || this.inC1) return "Running";
|
||||
if (this.isCompleted) {
|
||||
if (this.isEC && this.isUnlocked) return "Redo";
|
||||
return "Completed";
|
||||
}
|
||||
if (this.isUnlocked) return "Start";
|
||||
return "Locked";
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="c-challenge-box l-challenge-box">
|
||||
<hint-text class="l-hint-text--challenge">{{name}}</hint-text>
|
||||
<hint-text type="challenges" class="l-hint-text--challenge">{{name}}</hint-text>
|
||||
<slot name="top" />
|
||||
<div class="l-challenge-box__fill" />
|
||||
<button
|
||||
|
@ -13,7 +13,6 @@ Vue.component("challenges-header", {
|
||||
remainingECTiers: 0,
|
||||
untilNextEC: TimeSpan.zero,
|
||||
untilAllEC: TimeSpan.zero,
|
||||
newEC10: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -23,9 +22,6 @@ Vue.component("challenges-header", {
|
||||
showAllChallenges(newValue) {
|
||||
player.options.showAllChallenges = newValue;
|
||||
},
|
||||
newEC10(newValue) {
|
||||
player.newEC10Test = newValue;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
@ -34,7 +30,7 @@ Vue.component("challenges-header", {
|
||||
Object.keys(player.eternityChalls).length > 0;
|
||||
this.isECTabUnlocked = isECTabUnlocked;
|
||||
const isICTabUnlocked = isECTabUnlocked ||
|
||||
player.antimatter.gte(new Decimal("1e2000")) ||
|
||||
Currency.antimatter.exponent >= 2000 ||
|
||||
player.postChallUnlocked > 0;
|
||||
this.isICTabUnlocked = isICTabUnlocked;
|
||||
this.isInChallenge = NormalChallenge.isRunning || InfinityChallenge.isRunning || EternityChallenge.isRunning;
|
||||
@ -49,7 +45,15 @@ Vue.component("challenges-header", {
|
||||
this.untilNextEC.setFrom(untilNextEC);
|
||||
this.untilAllEC.setFrom(untilNextEC + (autoECInterval * (remainingCompletions - 1)));
|
||||
}
|
||||
this.newEC10 = player.newEC10Test;
|
||||
},
|
||||
restartChallenge() {
|
||||
const current = NormalChallenge.current ||
|
||||
InfinityChallenge.current ||
|
||||
EternityChallenge.current;
|
||||
if (current !== undefined) {
|
||||
current.exit();
|
||||
current.start();
|
||||
}
|
||||
},
|
||||
exitChallenge() {
|
||||
const current = NormalChallenge.current ||
|
||||
@ -59,41 +63,32 @@ Vue.component("challenges-header", {
|
||||
current.exit();
|
||||
}
|
||||
},
|
||||
toggleShowAll() {
|
||||
this.showAllChallenges = !this.showAllChallenges;
|
||||
},
|
||||
toggleAutoEC() {
|
||||
this.autoEC = !this.autoEC;
|
||||
},
|
||||
toggleNewEC10() {
|
||||
this.newEC10 = !this.newEC10;
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<div class="l-challenges-tab__header">
|
||||
<primary-button v-if="isInChallenge"
|
||||
class="o-primary-btn--exit-challenge l-challenges-tab__exit-btn"
|
||||
@click="exitChallenge">
|
||||
Exit Challenge
|
||||
</primary-button>
|
||||
<div>
|
||||
<div class="o-challenges-tab__header-toggle"
|
||||
@click="toggleNewEC10">
|
||||
<input :checked="newEC10" type="checkbox" class="o-big-checkbox" />
|
||||
<b>EC10 Reward Test</b>
|
||||
</div>
|
||||
<div v-if="isShowAllVisible"
|
||||
class="o-challenges-tab__header-toggle"
|
||||
@click="toggleShowAll">
|
||||
<input :checked="showAllChallenges" type="checkbox" class="o-big-checkbox" />
|
||||
<b>Show all</b>
|
||||
</div>
|
||||
<div v-if="isAutoECVisible"
|
||||
class="o-challenges-tab__header-toggle"
|
||||
@click="toggleAutoEC">
|
||||
<input :checked="autoEC" type="checkbox" class="o-big-checkbox" />
|
||||
<b>Auto EC completion</b>
|
||||
</div>
|
||||
template: `
|
||||
<div class="l-challenges-tab__header">
|
||||
<div class="c-subtab-option-container" v-if="isShowAllVisible || isAutoECVisible || isInChallenge">
|
||||
<primary-button-on-off v-if="isShowAllVisible"
|
||||
v-model="showAllChallenges"
|
||||
class="o-primary-btn--subtab-option"
|
||||
text="Show all challenges:"
|
||||
/>
|
||||
<primary-button-on-off v-if="isAutoECVisible"
|
||||
v-model="autoEC"
|
||||
class="o-primary-btn--subtab-option"
|
||||
text="Auto EC:"
|
||||
/>
|
||||
<primary-button v-if="isInChallenge"
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="restartChallenge"
|
||||
>
|
||||
Restart Challenge
|
||||
</primary-button>
|
||||
<primary-button v-if="isInChallenge"
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="exitChallenge"
|
||||
>
|
||||
Exit Challenge
|
||||
</primary-button>
|
||||
</div>
|
||||
<div v-if="autoEC && isAutoECVisible && remainingECTiers > 0"
|
||||
class="c-challenges-tab__auto-ec-info l-challenges-tab__auto-ec-info">
|
||||
@ -104,4 +99,4 @@ Vue.component("challenges-header", {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
});
|
||||
|
@ -83,10 +83,10 @@ Vue.component("eternity-challenges-tab", {
|
||||
this.enslavedSpanOverride = Enslaved.isRunning && this.challenge.id === 1;
|
||||
},
|
||||
start() {
|
||||
this.challenge.start();
|
||||
this.challenge.requestStart();
|
||||
},
|
||||
goalAtCompletions(completions) {
|
||||
return shorten(this.challenge.goalAtCompletions(completions), 2, 1);
|
||||
return format(this.challenge.goalAtCompletions(completions), 2, 1);
|
||||
}
|
||||
},
|
||||
template:
|
||||
@ -101,7 +101,7 @@ Vue.component("eternity-challenges-tab", {
|
||||
<description-display :config="config" slot="top" />
|
||||
<template slot="bottom">
|
||||
<div :style="{ visiblity: completions < 5 ? 'visible' : 'hidden' }">
|
||||
<div>Completed {{shortenSmallInteger(completions)}} {{"time" | pluralize(completions)}}</div>
|
||||
<div>Completed {{formatInt(completions)}} {{"time" | pluralize(completions)}}</div>
|
||||
<div v-if="!isCompleted">{{goalDisplay}}</div>
|
||||
</div>
|
||||
<span v-if="showGoalSpan">Goal Span: {{firstGoal}} IP - {{lastGoal}} IP</span>
|
||||
@ -141,10 +141,10 @@ Vue.component("eternity-challenges-tab", {
|
||||
template:
|
||||
`<div class="l-challenges-tab">
|
||||
<challenges-header/>
|
||||
<div>Complete Eternity Challenges again for a bigger reward, maximum of {{shortenSmallInteger(5)}} times.</div>
|
||||
<div>Complete Eternity Challenges again for a bigger reward, maximum of {{formatInt(5)}} times.</div>
|
||||
<div>
|
||||
(You have unlocked {{shortenSmallInteger(unlockedCount)}}
|
||||
out of {{shortenSmallInteger(12)}} Eternity Challenges)
|
||||
(You have unlocked {{formatInt(unlockedCount)}}
|
||||
out of {{formatInt(12)}} Eternity Challenges)
|
||||
</div>
|
||||
<challenge-grid :count="12" :isChallengeVisible="isChallengeVisible">
|
||||
<eternity-challenge-box slot-scope="slotProps" :challengeId="slotProps.challengeId" />
|
||||
|
@ -39,14 +39,14 @@ Vue.component("infinity-challenges-tab", {
|
||||
:isRunning="isRunning"
|
||||
:isCompleted="isCompleted"
|
||||
class="c-challenge-box--infinity"
|
||||
@start="challenge.start()"
|
||||
@start="challenge.requestStart()"
|
||||
>
|
||||
<template slot="top">
|
||||
<description-display :config="config" />
|
||||
<effect-display v-if="isRunning" :config="config" />
|
||||
</template>
|
||||
<div slot="bottom" class="l-challenge-box__bottom--infinity">
|
||||
<span>Goal: {{shorten(config.goal, 0, 0)}} antimatter</span>
|
||||
<span>Goal: {{format(config.goal, 0, 0)}} antimatter</span>
|
||||
<description-display :config="config.reward" title="Reward:"/>
|
||||
<effect-display v-if="isCompleted" :config="config.reward" />
|
||||
</div>
|
||||
@ -65,7 +65,7 @@ Vue.component("infinity-challenges-tab", {
|
||||
: undefined;
|
||||
return next === undefined
|
||||
? "All Infinity Challenges unlocked"
|
||||
: `Next challenge unlocks at ${this.shorten(next, 0, 0)} antimatter.`;
|
||||
: `Next challenge unlocks at ${format(next, 0, 0)} antimatter.`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -17,18 +17,20 @@ Vue.component("normal-challenges-tab", {
|
||||
challenge() {
|
||||
return NormalChallenge(this.challengeId);
|
||||
},
|
||||
config() {
|
||||
return this.challenge.config;
|
||||
},
|
||||
name() {
|
||||
return `C${this.challengeId}`;
|
||||
},
|
||||
overrideLabel() {
|
||||
return this.isBroken ? "Broken" : "";
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isRunning = this.challenge.isRunning;
|
||||
this.isBroken = Enslaved.isRunning &&
|
||||
!Enslaved.BROKEN_CHALLENGE_EXEMPTIONS.includes(this.challengeId);
|
||||
this.isBroken = Enslaved.isRunning && Enslaved.BROKEN_CHALLENGES.includes(this.challengeId);
|
||||
this.isCompleted = this.challenge.isCompleted && !this.isBroken;
|
||||
}
|
||||
},
|
||||
@ -40,9 +42,9 @@ Vue.component("normal-challenges-tab", {
|
||||
:isCompleted="isCompleted"
|
||||
:overrideLabel="overrideLabel"
|
||||
class="c-challenge-box--normal"
|
||||
@start="challenge.start()"
|
||||
@start="challenge.requestStart()"
|
||||
>
|
||||
<span slot="top">{{challenge.config.description}}</span>
|
||||
<description-display :config="config" slot="top" />
|
||||
<span slot="bottom">Reward: {{challenge.config.reward}}</span>
|
||||
</challenge-box>`
|
||||
}
|
||||
|
@ -982,7 +982,9 @@ Vue.component("ad-slider-component", {
|
||||
}
|
||||
},
|
||||
dotContents() {
|
||||
return this.valueInDot ? '' + this.getValue() : '';
|
||||
// Doesn't work if the slider needs to show more precision than integers,
|
||||
// but I don't think we have any such sliders.
|
||||
return this.valueInDot ? Math.round(this.getValue()) : '';
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
@ -42,7 +42,7 @@ Vue.component("cost-display", {
|
||||
},
|
||||
computed: {
|
||||
costDisplay() {
|
||||
return this.formatCost ? this.formatCost(this.cost) : this.shorten(this.cost, 0, 0);
|
||||
return this.formatCost ? this.formatCost(this.cost) : format(this.cost);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -37,7 +37,7 @@ Vue.component("description-display", {
|
||||
const classObject = {};
|
||||
classObject[name] = true;
|
||||
if (this.length !== undefined && this.description.length >= this.length) {
|
||||
classObject[name + "--small-text"] = true;
|
||||
classObject[`${name}--small-text`] = true;
|
||||
}
|
||||
return classObject;
|
||||
}
|
||||
|
@ -40,11 +40,17 @@ Vue.component("effect-display", {
|
||||
this.updateFn = isNumber
|
||||
? () => this.effectValue = effect()
|
||||
: () => this.effectValue.copyFrom(effect());
|
||||
const cap = config.cap;
|
||||
// If the config has a reachedCapFn, we assume its effect value calculation
|
||||
// takes account of the cap itself, so we don't have to.
|
||||
const cap = config.reachedCapFn === undefined ? config.cap : () => this.effectValue;
|
||||
if (cap === undefined) return;
|
||||
if (config.reachedCapFn) {
|
||||
this.reachedCapFn = config.reachedCapFn;
|
||||
} else {
|
||||
this.reachedCapFn = isNumber
|
||||
? () => this.effectValue >= this.cap
|
||||
: () => this.effectValue.gte(this.cap);
|
||||
}
|
||||
if (typeof cap !== "function") {
|
||||
this.hasCap = true;
|
||||
this.cap = isNumber ? cap : Decimal.fromDecimal(cap);
|
||||
@ -68,7 +74,7 @@ Vue.component("effect-display", {
|
||||
return this.reachedCapFn();
|
||||
},
|
||||
titleDisplay() {
|
||||
if (this.config.staticEffect) return undefined;
|
||||
if (this.config.noTitle) return "";
|
||||
return `${this.hasCap && this.reachedCap ? "Capped" : this.title}: `;
|
||||
},
|
||||
effectDisplay() {
|
||||
|
@ -81,16 +81,16 @@ Vue.component("expanding-control-box", {
|
||||
},
|
||||
updateBaseWidth() {
|
||||
if (this.widthSource === "content") {
|
||||
this.$refs.container.style.width = this.$refs.dropdown.offsetWidth + "px";
|
||||
this.$refs.root.style.width = this.$refs.dropdown.offsetWidth + "px";
|
||||
this.$refs.container.style.width = `${this.$refs.dropdown.offsetWidth}px`;
|
||||
this.$refs.root.style.width = `${this.$refs.dropdown.offsetWidth}px`;
|
||||
} else if (this.widthSource === "header") {
|
||||
this.$refs.root.style.width = this.$refs.container.offsetWidth + "px";
|
||||
this.$refs.root.style.width = `${this.$refs.container.offsetWidth}px`;
|
||||
}
|
||||
},
|
||||
updateHeightInfo() {
|
||||
const headerHeight = this.$refs.expandButton.offsetHeight;
|
||||
this.closedHeight = headerHeight + "px";
|
||||
this.openHeight = (headerHeight + this.$refs.dropdown.offsetHeight) + "px";
|
||||
this.closedHeight = `${headerHeight}px`;
|
||||
this.openHeight = `${headerHeight + this.$refs.dropdown.offsetHeight}px`;
|
||||
},
|
||||
transitionEnd(event) {
|
||||
if (event.propertyName !== "max-height") return;
|
||||
|
@ -7,7 +7,7 @@ Vue.component("footer-links", {
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.on$(GameEvent.TAB_CHANGED, () => this.isVisible = !Tab.eternity.studies.isOpen);
|
||||
this.on$(GAME_EVENT.TAB_CHANGED, () => this.isVisible = !Tab.eternity.studies.isOpen);
|
||||
},
|
||||
template:
|
||||
`<div v-if="isVisible" class="o-footer">
|
||||
|
@ -1,6 +1,16 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("hint-text", {
|
||||
props: {
|
||||
type: String
|
||||
},
|
||||
computed: {
|
||||
showThisHintText() {
|
||||
// Accessing the player object in this computed is intentional for the sake of performance.
|
||||
// Always access the player object in update method and store required stuff in component data.
|
||||
return player.options.showHintText[this.type];
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div v-show="$viewModel.shiftDown" class="o-hint-text l-hint-text"><slot /></div>`
|
||||
`<div v-show="$viewModel.shiftDown || showThisHintText" class="o-hint-text l-hint-text"><slot /></div>`
|
||||
});
|
||||
|
@ -1,6 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("news-ticker", {
|
||||
data() {
|
||||
return {
|
||||
recentTickers: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
isHidden() {
|
||||
this.restart();
|
||||
@ -36,20 +41,34 @@ Vue.component("news-ticker", {
|
||||
prepareNextMessage() {
|
||||
const line = this.$refs.line;
|
||||
if (line === undefined) return;
|
||||
|
||||
const isUnlocked = news => news.unlocked || news.unlocked === undefined;
|
||||
|
||||
if (this.currentNews && this.currentNews.id === "a236") {
|
||||
this.currentNews = GameDatabase.news.find(message => message.id === "a216");
|
||||
if (nextNewsMessageId && GameDatabase.news.find(message => message.id === nextNewsMessageId)) {
|
||||
this.currentNews = GameDatabase.news.find(message => message.id === nextNewsMessageId);
|
||||
nextNewsMessageId = undefined;
|
||||
} else if (this.currentNews && this.currentNews.id === "a236") {
|
||||
this.currentNews = GameDatabase.news
|
||||
.filter(message => message.isAdvertising && isUnlocked(message))
|
||||
.randomElement();
|
||||
} else {
|
||||
const isUnlocked = news => news.unlocked || news.unlocked === undefined;
|
||||
do {
|
||||
this.currentNews = GameDatabase.news.randomElement();
|
||||
} while (!isUnlocked(this.currentNews));
|
||||
const isAI = Math.random() < player.options.news.AIChance;
|
||||
this.currentNews = GameDatabase.news
|
||||
.filter(message => message.id.includes("ai") === isAI)
|
||||
.filter(message => !this.recentTickers.includes(message) && isUnlocked(message))
|
||||
.randomElement();
|
||||
// Prevent tickers from repeating if they were seen recently
|
||||
this.recentTickers.push(this.currentNews.id);
|
||||
while (this.recentTickers.length > player.options.news.repeatBuffer) this.recentTickers.shift();
|
||||
}
|
||||
if (this.currentNews.reset) {
|
||||
this.currentNews.reset();
|
||||
}
|
||||
|
||||
line.innerHTML = this.currentNews.text;
|
||||
|
||||
line.style["transition-duration"] = "0ms";
|
||||
if (this.currentNews && this.currentNews.id === "a244") {
|
||||
if (this?.currentNews.id === "a244" || this?.currentNews.id === "ai63" ) {
|
||||
line.style.transform = "translateX(-100%)";
|
||||
} else {
|
||||
line.style.transform = "translateX(0)";
|
||||
@ -62,7 +81,7 @@ Vue.component("news-ticker", {
|
||||
const line = this.$refs.line;
|
||||
|
||||
// SCROLL_SPEED is in pixels per second
|
||||
const SCROLL_SPEED = 100;
|
||||
const SCROLL_SPEED = player.options.news.speed * 100;
|
||||
const scrollDuration = (this.$refs.ticker.clientWidth + line.clientWidth) / SCROLL_SPEED;
|
||||
|
||||
line.style["transition-duration"] = `${scrollDuration}s`;
|
||||
@ -78,39 +97,13 @@ Vue.component("news-ticker", {
|
||||
this.scrollTimeout = setTimeout(this.prepareNextMessage.bind(this), scrollDuration * 1000);
|
||||
},
|
||||
onLineClick() {
|
||||
if (this.currentNews.id === "a130") {
|
||||
if (this.currentNews.onClick !== undefined) {
|
||||
SecretAchievement(24).unlock();
|
||||
}
|
||||
if (this.currentNews.id === "a196") {
|
||||
let random = Math.random();
|
||||
// Golden ratio
|
||||
random += 0.618033988749895;
|
||||
random %= 1;
|
||||
random *= 255;
|
||||
const color = `hsl(${random}, 90%, 60%)`;
|
||||
this.$refs.line.innerHTML =
|
||||
`<span style='color: ${color}; text-shadow: 0 0 0.5rem ${color}; animation: text-grow 0.4s infinite;'>
|
||||
Disco Time!</span>`;
|
||||
}
|
||||
if (this.currentNews.id === "a210") {
|
||||
player.secretUnlocks.uselessNewsClicks++;
|
||||
this.$refs.line.innerHTML = this.currentNews.text;
|
||||
}
|
||||
if (this.currentNews.id === "a247") {
|
||||
if (this.$refs.line.innerHTML.includes("This")) {
|
||||
this.$refs.line.innerHTML =
|
||||
"¡uʍop ǝpᴉsdn ɯǝɥʇ dᴉlɟ oʇ sǝƃɐssǝɯ sʍǝu uo ʞɔᴉlɔ oʇ ʎʇᴉlᴉqɐ ǝɥʇ ǝʞᴉl sƃuᴉɥʇ ǝɹnʇɐǝɟ llᴉʍ 0˙ᄅ sʍǝN " +
|
||||
"˙,,0˙ᄅ sʍǝN,, ɟo ʇsǝʇ ɐ sᴉ ǝƃɐssǝɯ sʍǝu sᴉɥ┴";
|
||||
} else {
|
||||
this.$refs.line.innerHTML =
|
||||
"This news message is a test of \"News 2.0\". News 2.0 will feature things like the ability to click " +
|
||||
"on news messages to flip them upside down!";
|
||||
const updatedText = this.currentNews.onClick();
|
||||
if (updatedText !== undefined) {
|
||||
this.$refs.line.innerHTML = updatedText;
|
||||
}
|
||||
}
|
||||
if (this.currentNews.id === "a289") {
|
||||
player.secretUnlocks.paperclips++;
|
||||
GameOptions.toggleNews();
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `
|
||||
|
@ -22,7 +22,7 @@ Vue.component("plus-minus-button", {
|
||||
height: this.size,
|
||||
position: "relative !important",
|
||||
"border-radius": "50% !important",
|
||||
border: "1px solid " + this.color + " !important",
|
||||
border: `0.1rem solid ${this.color} !important`,
|
||||
};
|
||||
},
|
||||
horizStyle() {
|
||||
|
@ -40,9 +40,22 @@ Vue.component("primary-button-on-off", {
|
||||
'<primary-button v-bind="$attrs" @click="emitInput(!value)">{{displayText}}</primary-button>',
|
||||
computed: {
|
||||
displayText() {
|
||||
let text = this.text;
|
||||
text = text && text.length > 0 ? text + " " : "";
|
||||
return this.value ? text + "ON" : text + "OFF";
|
||||
return `${this.text} ${this.value ? "ON" : "OFF"}`.trim();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component("primary-button-cycle", {
|
||||
props: {
|
||||
text: String,
|
||||
labels: Array,
|
||||
value: Number
|
||||
},
|
||||
template:
|
||||
'<primary-button v-bind="$attrs" @click="emitInput((value + 1) % labels.length)">{{displayText}}</primary-button>',
|
||||
computed: {
|
||||
displayText() {
|
||||
return `${this.text} ${this.labels[this.value]}`.trim();
|
||||
}
|
||||
}
|
||||
});
|
@ -0,0 +1,99 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("antimatter-dim-galaxy-row", {
|
||||
data() {
|
||||
return {
|
||||
type: GALAXY_TYPE.NORMAL,
|
||||
galaxies: {
|
||||
normal: 0,
|
||||
replicanti: 0,
|
||||
dilation: 0
|
||||
},
|
||||
requirement: {
|
||||
tier: 1,
|
||||
amount: 0
|
||||
},
|
||||
canBeBought: false,
|
||||
distantStart: 0,
|
||||
lockText: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dimName() {
|
||||
return AntimatterDimension(this.requirement.tier).displayName;
|
||||
},
|
||||
buttonText() {
|
||||
return this.lockText === null
|
||||
? "Reset your Dimensions and Dimension Boosts for a tickspeed boost"
|
||||
: this.lockText;
|
||||
},
|
||||
sumText() {
|
||||
const parts = [this.galaxies.normal];
|
||||
if (this.galaxies.replicanti > 0) parts.push(this.galaxies.replicanti);
|
||||
if (this.galaxies.dilation > 0) parts.push(this.galaxies.dilation);
|
||||
const sum = parts.map(formatInt).join(" + ");
|
||||
if (parts.length >= 2) {
|
||||
return `${sum} = ${formatInt(parts.sum())}`;
|
||||
}
|
||||
return sum;
|
||||
},
|
||||
typeName() {
|
||||
switch (this.type) {
|
||||
case GALAXY_TYPE.NORMAL: return "Antimatter Galaxies";
|
||||
case GALAXY_TYPE.DISTANT: return "Distant Antimatter Galaxies";
|
||||
case GALAXY_TYPE.REMOTE: return "Remote Antimatter Galaxies";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
hasIncreasedScaling() {
|
||||
return this.type !== GALAXY_TYPE.NORMAL;
|
||||
},
|
||||
costScalingText() {
|
||||
switch (this.type) {
|
||||
case GALAXY_TYPE.DISTANT:
|
||||
return `Each galaxy is more expensive past ${formatInt(this.distantStart)} galaxies`;
|
||||
case GALAXY_TYPE.REMOTE:
|
||||
return "Increased galaxy cost scaling: " +
|
||||
`Quadratic past ${formatInt(this.distantStart)} (distant),
|
||||
exponential past ${formatInt(800)} (remote)`;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
tutorialClass() {
|
||||
return Tutorial.glowingClass(TUTORIAL_STATE.GALAXY, this.canBeBought);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.type = Galaxy.type;
|
||||
this.galaxies.normal = player.galaxies;
|
||||
this.galaxies.replicanti = Replicanti.galaxies.total;
|
||||
this.galaxies.dilation = player.dilation.freeGalaxies;
|
||||
const requirement = Galaxy.requirement;
|
||||
this.requirement.amount = requirement.amount;
|
||||
this.requirement.tier = requirement.tier;
|
||||
this.canBeBought = requirement.isSatisfied && Galaxy.canBeBought;
|
||||
this.distantStart = EternityChallenge(5).isRunning ? 0 : Galaxy.costScalingStart;
|
||||
this.lockText = Galaxy.lockText;
|
||||
},
|
||||
buyGalaxy(bulk) {
|
||||
requestGalaxyReset(bulk);
|
||||
Tutorial.turnOffEffect(TUTORIAL_STATE.GALAXY);
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<div class="c-antimatter-dim-row">
|
||||
<div class="c-dim-row__label c-dim-row__label--growable" style="height: 6rem;">
|
||||
{{typeName}} ({{sumText}}):
|
||||
requires {{formatInt(requirement.amount)}} {{dimName}} Dimensions
|
||||
<div style="height: 2rem;">{{ hasIncreasedScaling ? costScalingText : "" }}</div>
|
||||
</div>
|
||||
<primary-button
|
||||
:enabled="canBeBought"
|
||||
class="o-primary-btn--galaxy l-dim-row__button l-dim-row__button--right-offset"
|
||||
:class="tutorialClass"
|
||||
@click.exact="buyGalaxy(true)"
|
||||
@click.shift.exact="buyGalaxy(false)"
|
||||
>{{buttonText}}</primary-button>
|
||||
</div>`
|
||||
});
|
@ -0,0 +1,134 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("antimatter-dim-row", {
|
||||
props: {
|
||||
floatingText: Array,
|
||||
tier: Number
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
isCapped: false,
|
||||
multiplier: new Decimal(0),
|
||||
amount: new Decimal(0),
|
||||
boughtBefore10: 0,
|
||||
rateOfChange: new Decimal(0),
|
||||
singleCost: new Decimal(0),
|
||||
until10Cost: new Decimal(0),
|
||||
isAffordable: false,
|
||||
isAffordableUntil10: false,
|
||||
isContinuumActive: false,
|
||||
continuumValue: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return AntimatterDimension(this.tier).shortDisplayName;
|
||||
},
|
||||
amountDisplay() {
|
||||
return this.tier < 8 ? format(this.amount, 2, 0) : formatInt(this.amount);
|
||||
},
|
||||
rateOfChangeDisplay() {
|
||||
return this.tier < 8
|
||||
? ` (+${format(this.rateOfChange, 2, 2)}%/s)`
|
||||
: "";
|
||||
},
|
||||
cappedTooltip() {
|
||||
return this.isCapped
|
||||
? "Further eighth dimension purchases are prohibited, as they are the only way to acquire galaxies"
|
||||
: null;
|
||||
},
|
||||
continuumString() {
|
||||
return formatFloat(this.continuumValue, 2);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const tier = this.tier;
|
||||
const isUnlocked = AntimatterDimension(tier).isAvailableForPurchase;
|
||||
this.isUnlocked = isUnlocked;
|
||||
if (!isUnlocked) return;
|
||||
const dimension = AntimatterDimension(tier);
|
||||
this.isCapped = tier === 8 && Enslaved.isRunning && dimension.bought >= 1;
|
||||
this.multiplier.copyFrom(AntimatterDimension(tier).multiplier);
|
||||
this.amount.copyFrom(dimension.totalAmount);
|
||||
this.boughtBefore10 = dimension.boughtBefore10;
|
||||
this.singleCost.copyFrom(dimension.cost);
|
||||
this.until10Cost.copyFrom(dimension.costUntil10);
|
||||
if (tier < 8) {
|
||||
this.rateOfChange.copyFrom(dimension.rateOfChange);
|
||||
}
|
||||
this.isAffordable = dimension.isAffordable;
|
||||
this.isAffordableUntil10 = dimension.isAffordableUntil10;
|
||||
this.isContinuumActive = Laitela.continuumActive;
|
||||
if (this.isContinuumActive) this.continuumValue = dimension.continuumValue;
|
||||
},
|
||||
buySingle() {
|
||||
if (this.isContinuumActive) return;
|
||||
buyOneDimension(this.tier);
|
||||
if (this.tier === 2) {
|
||||
Tutorial.turnOffEffect(TUTORIAL_STATE.DIM2);
|
||||
}
|
||||
},
|
||||
buyUntil10() {
|
||||
if (this.isContinuumActive) return;
|
||||
buyManyDimension(this.tier);
|
||||
if (this.tier === 2) {
|
||||
Tutorial.turnOffEffect(TUTORIAL_STATE.DIM2);
|
||||
}
|
||||
},
|
||||
showCostTitle(value) {
|
||||
return value.exponent < 1000000;
|
||||
},
|
||||
tutorialClass() {
|
||||
if (this.tier === 1) {
|
||||
return Tutorial.glowingClass(TUTORIAL_STATE.DIM1, this.isAffordable);
|
||||
}
|
||||
|
||||
if (this.tier === 2) {
|
||||
return Tutorial.glowingClass(TUTORIAL_STATE.DIM2, this.isAffordable);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div v-show="isUnlocked" class="c-antimatter-dim-row">
|
||||
<div class="c-dim-row__label c-dim-row__name">
|
||||
{{name}} Antimatter Dimension {{formatX(multiplier, 1, 1)}}
|
||||
</div>
|
||||
<div class="c-dim-row__label c-dim-row__label--growable">
|
||||
{{amountDisplay}} ({{formatInt(boughtBefore10)}})
|
||||
<span class="c-dim-row__label--small" v-if="rateOfChange.neq(0)">{{rateOfChangeDisplay}}</span>
|
||||
</div>
|
||||
<primary-button
|
||||
v-if="!isContinuumActive"
|
||||
:enabled="isAffordable && !isCapped"
|
||||
class="o-primary-btn--buy-ad o-primary-btn--buy-single-ad l-dim-row__button"
|
||||
:class="tutorialClass()"
|
||||
:ach-tooltip="cappedTooltip"
|
||||
@click="buySingle">
|
||||
<span v-if="isCapped">Capped</span>
|
||||
<template v-else>
|
||||
<span v-if="showCostTitle(singleCost)">Cost: </span>{{format(singleCost)}}
|
||||
</template>
|
||||
</primary-button>
|
||||
<primary-button
|
||||
:enabled="(isAffordableUntil10 || isContinuumActive) && !isCapped"
|
||||
class="o-primary-btn--buy-ad o-primary-btn--buy-10-ad l-dim-row__button"
|
||||
:ach-tooltip="cappedTooltip"
|
||||
@click="buyUntil10">
|
||||
<span v-if="isCapped">Capped</span>
|
||||
<span v-else-if="isContinuumActive">Continuum: {{continuumString}}</span>
|
||||
<template v-else>
|
||||
Until {{formatInt(10)}}, <span v-if="showCostTitle(until10Cost)">
|
||||
Cost: </span>{{format(until10Cost)}}
|
||||
</template>
|
||||
</primary-button>
|
||||
<div
|
||||
v-for="text in floatingText"
|
||||
:key="text.key"
|
||||
class='c-antimatter-dim-row__floating-text'
|
||||
>{{text.text}}</div>
|
||||
</div>`,
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("normal-dim-shift-row", {
|
||||
Vue.component("antimatter-dim-shift-row", {
|
||||
data() {
|
||||
return {
|
||||
requirement: {
|
||||
@ -10,7 +10,8 @@ Vue.component("normal-dim-shift-row", {
|
||||
isShift: false,
|
||||
isBuyable: false,
|
||||
purchasedBoosts: 0,
|
||||
freeBoosts: 0
|
||||
freeBoosts: 0,
|
||||
lockText: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -18,21 +19,26 @@ Vue.component("normal-dim-shift-row", {
|
||||
return this.isShift ? "Shift" : "Boost";
|
||||
},
|
||||
dimName() {
|
||||
return DISPLAY_NAMES[this.requirement.tier];
|
||||
return AntimatterDimension(this.requirement.tier).displayName;
|
||||
},
|
||||
buttonText() {
|
||||
return `Reset the game for a ${this.isShift ? "new Dimension" : "boost"}`;
|
||||
return this.lockText === null
|
||||
? `Reset your Dimensions for a ${this.isShift ? "new Dimension" : "boost"}`
|
||||
: this.lockText;
|
||||
},
|
||||
boostCountText() {
|
||||
const parts = [this.purchasedBoosts];
|
||||
if (this.freeBoosts !== 0) {
|
||||
parts.push(this.freeBoosts);
|
||||
}
|
||||
const sum = parts.map(shortenSmallInteger).join(" + ");
|
||||
const sum = parts.map(formatInt).join(" + ");
|
||||
if (parts.length >= 2) {
|
||||
return `${sum} = ${shortenSmallInteger(parts.sum())}`;
|
||||
return `${sum} = ${formatInt(parts.sum())}`;
|
||||
}
|
||||
return sum;
|
||||
},
|
||||
tutorialClass() {
|
||||
return Tutorial.glowingClass(TUTORIAL_STATE.DIMSHIFT, this.isBuyable);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -40,27 +46,30 @@ Vue.component("normal-dim-shift-row", {
|
||||
const requirement = DimBoost.requirement;
|
||||
this.requirement.tier = requirement.tier;
|
||||
this.requirement.amount = requirement.amount;
|
||||
this.isBuyable = requirement.isSatisfied;
|
||||
this.isBuyable = requirement.isSatisfied && DimBoost.canBeBought;
|
||||
this.isShift = DimBoost.isShift;
|
||||
this.purchasedBoosts = DimBoost.purchasedBoosts;
|
||||
this.freeBoosts = DimBoost.freeBoosts;
|
||||
this.lockText = DimBoost.lockText;
|
||||
},
|
||||
softReset() {
|
||||
softResetBtnClick();
|
||||
Tutorial.turnOffEffect(TUTORIAL_STATE.DIMSHIFT);
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="c-normal-dim-row">
|
||||
<div
|
||||
class="c-normal-dim-row__label c-normal-dim-row__label--growable"
|
||||
`<div class="c-antimatter-dim-row">
|
||||
<div
|
||||
class="c-dim-row__label c-dim-row__label--growable"
|
||||
>
|
||||
Dimension {{name}} ({{boostCountText}}):
|
||||
requires {{shortenSmallInteger(requirement.amount)}} {{dimName}} Dimensions
|
||||
requires {{formatInt(requirement.amount)}} {{dimName}} Dimensions
|
||||
</div>
|
||||
<primary-button
|
||||
:enabled="isBuyable"
|
||||
class="o-primary-btn--dimboost c-normal-dim-row__buy-button c-normal-dim-row__buy-button--right-offset"
|
||||
class="o-primary-btn--dimboost l-dim-row__button l-dim-row__button--right-offset"
|
||||
:class=tutorialClass
|
||||
@click="softReset"
|
||||
>{{buttonText}}</primary-button>
|
||||
</div>`
|
||||
});
|
||||
});
|
@ -1,19 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("normal-dim-tab-header", {
|
||||
Vue.component("antimatter-dim-tab-header", {
|
||||
data() {
|
||||
return {
|
||||
isSacrificeUnlocked: false,
|
||||
isSacrificeAffordable: false,
|
||||
currentSacrifice: new Decimal(0),
|
||||
sacrificeBoost: new Decimal(0),
|
||||
disabledCondition: ""
|
||||
disabledCondition: "",
|
||||
isLarge: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
sacrificeTooltip() {
|
||||
return `Boosts 8th Dimension by ${formatX(this.sacrificeBoost, 2, 2)}`;
|
||||
return `Boosts 8th Antimatter Dimension by ${formatX(this.sacrificeBoost, 2, 2)}`;
|
||||
},
|
||||
classObject() {
|
||||
return this.isLarge ? "o-primary-btn--sacrifice--large" : "";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
@ -24,6 +28,7 @@ Vue.component("normal-dim-tab-header", {
|
||||
this.currentSacrifice.copyFrom(Sacrifice.totalBoost);
|
||||
this.sacrificeBoost.copyFrom(Sacrifice.nextBoost);
|
||||
this.disabledCondition = Sacrifice.disabledCondition;
|
||||
this.isLarge = this.disabledCondition.length > 20;
|
||||
},
|
||||
sacrifice() {
|
||||
sacrificeBtnClick();
|
||||
@ -33,12 +38,13 @@ Vue.component("normal-dim-tab-header", {
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-normal-dim-tab__header">
|
||||
`<div class="l-antimatter-dim-tab__header">
|
||||
<primary-button
|
||||
v-show="isSacrificeUnlocked"
|
||||
v-tooltip="sacrificeTooltip"
|
||||
:enabled="isSacrificeAffordable"
|
||||
class="o-primary-btn--sacrifice"
|
||||
:class="classObject"
|
||||
@click="sacrifice"
|
||||
>
|
||||
<span v-if="isSacrificeAffordable">Dimensional Sacrifice ({{ formatX(sacrificeBoost, 2, 2) }})</span>
|
@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("antimatter-dim-tab-progress-bar", {
|
||||
data() {
|
||||
return {
|
||||
fill: 0,
|
||||
tooltip: ""
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
displayPercents() {
|
||||
return formatPercents(this.fill, 2);
|
||||
},
|
||||
progressBarStyle() {
|
||||
return {
|
||||
width: Notations.current.name === 'Blind' ? '0%' : `${(this.fill * 100).toFixed(2)}%`
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const setProgress = (current, goal, tooltip) => {
|
||||
this.fill = Math.clampMax(current.pLog10() / Decimal.log10(goal), 1);
|
||||
this.tooltip = tooltip;
|
||||
};
|
||||
const challenge = NormalChallenge.current || InfinityChallenge.current;
|
||||
if (challenge) {
|
||||
setProgress(Currency.antimatter.value, challenge.goal, "Percentage to challenge goal");
|
||||
} else if (!player.break) {
|
||||
setProgress(Currency.antimatter.value, Decimal.NUMBER_MAX_VALUE, "Percentage to Infinity");
|
||||
} else if (Enslaved.isCompleted) {
|
||||
setProgress(player.infinityPoints, Enslaved.tesseractCost, "Percentage to next Tesseract");
|
||||
} else if (PlayerProgress.dilationUnlocked()) {
|
||||
setProgress(player.eternityPoints, new Decimal("1e4000"), "Percentage to Reality");
|
||||
} else if (InfinityDimension(8).isUnlocked) {
|
||||
setProgress(
|
||||
player.infinityPoints,
|
||||
Player.eternityGoal,
|
||||
EternityChallenge.isRunning ? "Percentage to Eternity Challenge goal" : "Percentage to Eternity"
|
||||
);
|
||||
} else {
|
||||
setProgress(
|
||||
Currency.antimatter.value,
|
||||
InfinityDimensions.next().requirement,
|
||||
"Percentage to next dimension unlock");
|
||||
}
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="c-progress-bar">
|
||||
<div :style="progressBarStyle" class="c-progress-bar__fill">
|
||||
<span v-tooltip="tooltip" class="c-progress-bar__percents">{{displayPercents}}</span>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("normal-dim-tab", {
|
||||
Vue.component("antimatter-dim-tab", {
|
||||
data() {
|
||||
return {
|
||||
isChallengePowerVisible: false,
|
||||
@ -21,11 +21,11 @@ Vue.component("normal-dim-tab", {
|
||||
if (isChallengePowerVisible) {
|
||||
const powerArray = [];
|
||||
if (isC2Running) powerArray.push(`Production: ${formatPercents(player.chall2Pow, 2, 2)}`);
|
||||
if (isC3Running) powerArray.push(`First dimension: ${formatX(player.chall3Pow, 2, 2)}`);
|
||||
if (isIC6Running) powerArray.push(`Matter: /
|
||||
${shorten(new Decimal(1).timesEffectOf(InfinityChallenge(6)), 2, 2)}`);
|
||||
if (isIC8Running) powerArray.push(`Production: /
|
||||
${shorten(new Decimal(1).timesEffectOf(InfinityChallenge(8)).reciprocal(), 2, 2)}`);
|
||||
if (isC3Running) powerArray.push(`First dimension: ${formatX(player.chall3Pow, 3, 4)}`);
|
||||
if (isIC6Running) powerArray.push(`Matter: /
|
||||
${format(new Decimal(1).timesEffectOf(InfinityChallenge(6)), 2, 2)}`);
|
||||
if (isIC8Running) powerArray.push(`Production: /
|
||||
${format(new Decimal(1).timesEffectOf(InfinityChallenge(8)).reciprocal(), 2, 2)}`);
|
||||
this.challengePower = powerArray.join(", ");
|
||||
}
|
||||
const challenge = NormalChallenge.current || InfinityChallenge.current;
|
||||
@ -38,19 +38,19 @@ Vue.component("normal-dim-tab", {
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-old-ui-normal-dim-tab">
|
||||
`<div class="l-old-ui-antimatter-dim-tab">
|
||||
<span v-if="isSacrificeUnlocked">Sacrifice multiplier: {{ formatX(currentSacrifice, 2, 2) }}</span>
|
||||
<normal-dim-tab-header />
|
||||
<antimatter-dim-tab-header />
|
||||
<span v-if="isChallengePowerVisible">{{challengePower}}</span>
|
||||
<div class="l-normal-dim-tab__row-container l-normal-dim-row-container">
|
||||
<normal-dim-row
|
||||
<div class="l-dimensions-container">
|
||||
<antimatter-dim-row
|
||||
v-for="tier in 8"
|
||||
:key="tier"
|
||||
:tier="tier"
|
||||
:floatingText="$viewModel.tabs.dimensions.normal.floatingText[tier]"
|
||||
:floatingText="$viewModel.tabs.dimensions.antimatter.floatingText[tier]"
|
||||
/>
|
||||
<normal-dim-shift-row />
|
||||
<normal-dim-galaxy-row />
|
||||
<antimatter-dim-shift-row />
|
||||
<antimatter-dim-galaxy-row />
|
||||
</div>
|
||||
<primary-button
|
||||
v-if="isQuickResetAvailable"
|
||||
@ -58,6 +58,6 @@ Vue.component("normal-dim-tab", {
|
||||
@click="quickReset"
|
||||
>Lose a reset, returning to the start of the reset</primary-button>
|
||||
<div style="flex: 1 0" />
|
||||
<normal-dim-tab-progress-bar class="l-normal-dim-tab__progress_bar" />
|
||||
<antimatter-dim-tab-progress-bar class="l-antimatter-dim-tab__progress_bar" />
|
||||
</div>`
|
||||
});
|
@ -1,131 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("dim-production-tab", {
|
||||
components: {
|
||||
"number-input": {
|
||||
props: {
|
||||
value: Number,
|
||||
min: Number,
|
||||
max: Number,
|
||||
default: Number
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: this.clamp(this.value)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
clamp(value) {
|
||||
return Math.clamp(value, this.min, this.max);
|
||||
},
|
||||
handleInput(event) {
|
||||
const input = parseInt(event.target.value, 10);
|
||||
const finalValue = isNaN(input) ? this.min : this.clamp(input);
|
||||
this.inputValue = finalValue;
|
||||
this.emitInput(finalValue);
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<input type="number" :value="inputValue" @input="handleInput" />`
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
duration: 0,
|
||||
updateRate: 0,
|
||||
enabled: false,
|
||||
dips: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
chartOptions() {
|
||||
return this.options.chart;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
duration(newValue) {
|
||||
player.options.chart.duration = newValue;
|
||||
},
|
||||
updateRate(newValue) {
|
||||
player.options.chart.updateRate = newValue;
|
||||
},
|
||||
enabled(newValue) {
|
||||
player.options.chart.on = newValue;
|
||||
},
|
||||
dips(newValue) {
|
||||
player.options.chart.dips = newValue;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const container = this.$refs.chartContainer;
|
||||
container.appendChild(dimChartEl);
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const options = player.options.chart;
|
||||
this.duration = options.duration;
|
||||
this.updateRate = options.updateRate;
|
||||
this.enabled = options.on;
|
||||
this.dips = options.dips;
|
||||
},
|
||||
checkOptionsWarnings() {
|
||||
const options = player.options.chart;
|
||||
const updateRate = options.updateRate;
|
||||
const duration = options.duration;
|
||||
if (updateRate <= 200 && duration >= 30 && options.warning === 0) {
|
||||
Modal.message.show("Warning: setting the duration and update rate too high can cause performance issues.");
|
||||
options.warning = 1;
|
||||
}
|
||||
if (duration / updateRate * 1000 >= 1000 && options.warning !== 2) {
|
||||
Modal.message.show("Warning: you have set the duration and update rate quite high, " +
|
||||
"make sure you know what you're doing or have a good computer");
|
||||
options.warning = 2;
|
||||
}
|
||||
},
|
||||
checkToggleWarnings() {
|
||||
const options = player.options.chart;
|
||||
if (options.on) return;
|
||||
if (options.warning < 1) {
|
||||
Modal.message.show("Warning: the chart can cause performance issues. " +
|
||||
"Please disable it if you're experiencing lag.");
|
||||
}
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div>
|
||||
<div class="c-production-header">
|
||||
<b>seconds of history:</b>
|
||||
<number-input
|
||||
v-model="duration"
|
||||
:min="1"
|
||||
:max="300"
|
||||
:default="10"
|
||||
@input="checkOptionsWarnings"
|
||||
/>
|
||||
<b>update rate (in ms):</b>
|
||||
<number-input
|
||||
v-model="updateRate"
|
||||
:min="50"
|
||||
:max="10000"
|
||||
:default="1000"
|
||||
@input="checkOptionsWarnings"
|
||||
/>
|
||||
<b>enabled:</b>
|
||||
<input
|
||||
v-model="enabled"
|
||||
class="c-production-header__checkbox"
|
||||
type="checkbox"
|
||||
@input="checkToggleWarnings"
|
||||
/>
|
||||
<b>dips:</b>
|
||||
<input
|
||||
v-model="dips"
|
||||
class="c-production-header__checkbox"
|
||||
type="checkbox"
|
||||
@input="checkToggleWarnings"
|
||||
/>
|
||||
</div>
|
||||
<div ref="chartContainer" />
|
||||
<b>Exponents of antimatter per second</b>
|
||||
</div>`
|
||||
});
|
@ -8,17 +8,21 @@ Vue.component("infinity-dim-row", {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
multiplier: new Decimal(0),
|
||||
baseAmount: 0,
|
||||
amount: new Decimal(0),
|
||||
hasRateOfChange: false,
|
||||
purchases: 0,
|
||||
rateOfChange: new Decimal(0),
|
||||
isAutobuyerUnlocked: false,
|
||||
cost: new Decimal(0),
|
||||
isAvailableForPuchase: false,
|
||||
isAvailableForPurchase: false,
|
||||
isCapped: false,
|
||||
capIP: new Decimal(0),
|
||||
isAutobuyerOn: false,
|
||||
isEC8Running: false,
|
||||
hardcap: HARDCAP_ID_PURCHASES,
|
||||
hardcap: InfinityDimensions.HARDCAP_PURCHASES,
|
||||
requirementReached: false,
|
||||
eternityReached: false,
|
||||
showCostTitle: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -28,23 +32,34 @@ Vue.component("infinity-dim-row", {
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return DISPLAY_NAMES[this.tier];
|
||||
return InfinityDimension(this.tier).shortDisplayName;
|
||||
},
|
||||
rateOfChangeDisplay() {
|
||||
return this.hasRateOfChange
|
||||
? ` (+${this.shortenRateOfChange(this.rateOfChange)}%/s)`
|
||||
: "";
|
||||
return ` (+${format(this.rateOfChange, 2, 2)}%/s)`;
|
||||
},
|
||||
costDisplay() {
|
||||
return this.isCapped ? "Capped!" : `Cost: ${this.shortenCosts(this.cost)} IP`;
|
||||
const requirement = InfinityDimension(this.tier).requirement;
|
||||
if (this.isUnlocked) {
|
||||
if (this.isCapped) return "Capped";
|
||||
return this.showCostTitle ? `Cost: ${format(this.cost)} IP` : `${format(this.cost)} IP`;
|
||||
}
|
||||
|
||||
if (this.requirementReached) {
|
||||
return "Unlock";
|
||||
}
|
||||
|
||||
return `Reach ${format(requirement)} AM`;
|
||||
},
|
||||
hardcapPurchases() {
|
||||
return this.shorten(this.hardcap, 1, 1);
|
||||
return format(this.hardcap, 1, 1);
|
||||
},
|
||||
capTooltip() {
|
||||
return this.isCapped
|
||||
? `Limited to ${this.hardcapPurchases} upgrades (${this.shortenCosts(this.capIP)} IP)`
|
||||
: undefined;
|
||||
? `Cap reached at ${format(this.capIP)} IP`
|
||||
: `Purchased ${formatInt(this.purchases)} ${pluralize("time", this.purchases)}`;
|
||||
},
|
||||
showRow() {
|
||||
return this.eternityReached || this.isUnlocked || this.requirementReached || this.amount.gt(0);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -52,16 +67,17 @@ Vue.component("infinity-dim-row", {
|
||||
const tier = this.tier;
|
||||
const dimension = InfinityDimension(tier);
|
||||
this.isUnlocked = dimension.isUnlocked;
|
||||
if (!this.isUnlocked) return;
|
||||
this.multiplier.copyFrom(dimension.multiplier);
|
||||
this.baseAmount = dimension.baseAmount;
|
||||
this.purchases = dimension.purchases;
|
||||
this.amount.copyFrom(dimension.amount);
|
||||
this.hasRateOfChange = dimension.hasRateOfChange;
|
||||
if (this.hasRateOfChange) {
|
||||
this.rateOfChange.copyFrom(dimension.rateOfChange);
|
||||
}
|
||||
this.rateOfChange.copyFrom(dimension.rateOfChange);
|
||||
this.isAutobuyerUnlocked = dimension.isAutobuyerUnlocked;
|
||||
this.cost.copyFrom(dimension.cost);
|
||||
this.isAvailableForPuchase = dimension.isAvailableForPuchase;
|
||||
this.isAvailableForPurchase = dimension.isAvailableForPurchase;
|
||||
if (!this.isUnlocked) {
|
||||
this.isAvailableForPurchase = dimension.requirementReached;
|
||||
}
|
||||
this.isCapped = dimension.isCapped;
|
||||
if (this.isCapped) {
|
||||
this.capIP.copyFrom(dimension.hardcapIPAmount);
|
||||
@ -69,30 +85,49 @@ Vue.component("infinity-dim-row", {
|
||||
}
|
||||
this.isEC8Running = EternityChallenge(8).isRunning;
|
||||
this.isAutobuyerOn = player.infDimBuyers[this.tier - 1];
|
||||
this.requirementReached = dimension.requirementReached;
|
||||
this.eternityReached = PlayerProgress.eternityUnlocked();
|
||||
this.showCostTitle = this.cost.exponent < 1000000;
|
||||
},
|
||||
buyManyInfinityDimension() {
|
||||
if (!this.isUnlocked) {
|
||||
InfinityDimension(this.tier).tryUnlock();
|
||||
return;
|
||||
}
|
||||
buyManyInfinityDimension(this.tier);
|
||||
}
|
||||
},
|
||||
buyMaxInfinityDimension() {
|
||||
if (!this.isUnlocked) return;
|
||||
buyMaxInfDims(this.tier);
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<div v-show="isUnlocked" class="c-infinity-dim-row">
|
||||
<div class="c-infinity-dim-row__label c-infinity-dim-row__name">
|
||||
{{name}} Infinity Dimension x{{shortenMoney(multiplier)}}
|
||||
`<div v-show="showRow" class="c-infinity-dim-row"
|
||||
:class="{ 'c-infinity-dim-row--not-reached': !isUnlocked && !requirementReached }">
|
||||
<div class="c-dim-row__label c-dim-row__name">
|
||||
{{name}} Infinity Dimension {{formatX(multiplier, 2, 1)}}
|
||||
</div>
|
||||
<div class="c-infinity-dim-row__label c-infinity-dim-row__label--growable">
|
||||
{{shortenDimensions(amount)}} {{rateOfChangeDisplay}}
|
||||
<div class="c-dim-row__label c-dim-row__label--growable">
|
||||
{{format(amount, 2, 0)}}
|
||||
<span class="c-dim-row__label--small" v-if="rateOfChange.neq(0)">{{rateOfChangeDisplay}}</span>
|
||||
</div>
|
||||
<primary-button
|
||||
v-tooltip="capTooltip"
|
||||
:enabled="isAvailableForPurchase && !isCapped"
|
||||
class="o-primary-btn--buy-id l-dim-row__button"
|
||||
@click="buyManyInfinityDimension"
|
||||
>{{costDisplay}}</primary-button>
|
||||
<primary-button-on-off
|
||||
v-if="isAutobuyerUnlocked && !isEC8Running"
|
||||
v-model="isAutobuyerOn"
|
||||
class="o-primary-btn--id-autobuyer l-infinity-dim-row__button"
|
||||
class="o-primary-btn--id-autobuyer l-dim-row__button"
|
||||
text="Auto:"
|
||||
/>
|
||||
<primary-button
|
||||
v-tooltip="capTooltip"
|
||||
:enabled="isAvailableForPuchase"
|
||||
class="o-primary-btn--buy-id l-infinity-dim-row__button"
|
||||
@click="buyManyInfinityDimension"
|
||||
>{{costDisplay}}</primary-button>
|
||||
v-else
|
||||
:enabled="isAvailableForPurchase && isUnlocked"
|
||||
class="o-primary-btn--buy-id-max l-dim-row__button"
|
||||
@click="buyMaxInfinityDimension"
|
||||
>Buy Max</primary-button>
|
||||
</div>`,
|
||||
});
|
||||
|
@ -8,12 +8,13 @@ Vue.component("infinity-dim-tab", {
|
||||
powerPerSecond: new Decimal(0),
|
||||
incomeType: "",
|
||||
isEC8Running: false,
|
||||
isEnslavedRunning: false,
|
||||
EC8PurchasesLeft: 0,
|
||||
isAnyAutobuyerUnlocked: false,
|
||||
conversionRate: 0,
|
||||
nextDimCapIncrease: 0,
|
||||
tesseractCost: new Decimal(0),
|
||||
totalDimCapIncrease: 0,
|
||||
totalDimCap: 0,
|
||||
canBuyTesseract: false,
|
||||
enslavedCompleted: false
|
||||
};
|
||||
@ -28,16 +29,17 @@ Vue.component("infinity-dim-tab", {
|
||||
} else {
|
||||
this.dimMultiplier.copyFrom(infinityPower.pow(this.conversionRate).max(1));
|
||||
}
|
||||
this.powerPerSecond.copyFrom(InfinityDimension(1).productionPerSecond);
|
||||
this.powerPerSecond.copyFrom(InfinityDimension(1).productionPerRealSecond);
|
||||
this.incomeType = EternityChallenge(7).isRunning ? "Seventh Dimensions" : "Infinity Power";
|
||||
this.isEC8Running = EternityChallenge(8).isRunning;
|
||||
if (this.isEC8Running) {
|
||||
this.EC8PurchasesLeft = player.eterc8ids;
|
||||
}
|
||||
this.isEnslavedRunning = Enslaved.isRunning;
|
||||
this.isAnyAutobuyerUnlocked = InfinityDimension(1).isAutobuyerUnlocked;
|
||||
this.nextDimCapIncrease = Enslaved.nextDimCapIncrease;
|
||||
this.tesseractCost.copyFrom(Enslaved.tesseractCost);
|
||||
this.totalDimCapIncrease = player.celestials.enslaved.totalDimCapIncrease;
|
||||
this.totalDimCap = InfinityDimensions.totalDimCap;
|
||||
this.canBuyTesseract = Enslaved.canBuyTesseract;
|
||||
this.enslavedCompleted = Enslaved.isCompleted;
|
||||
},
|
||||
@ -51,49 +53,57 @@ Vue.component("infinity-dim-tab", {
|
||||
Enslaved.buyTesseract();
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-infinity-dim-tab">
|
||||
<div>
|
||||
<p>
|
||||
You have
|
||||
<span class="c-infinity-dim-description__accent">{{shortenMoney(infinityPower)}}</span> infinity power,
|
||||
translated to
|
||||
<span class="c-infinity-dim-description__accent">{{shortenMoney(dimMultiplier)}}</span>x
|
||||
multiplier on all dimensions (^{{ shorten(conversionRate, 2, 3) }}).
|
||||
</p>
|
||||
</div>
|
||||
<div class="l-infinity-dim-tab__enslaved-reward-container" v-if="enslavedCompleted">
|
||||
<button
|
||||
class="c-infinity-dim-tab__tesseract-button"
|
||||
:class="{ 'c-infinity-dim-tab__tesseract-button--disabled': !canBuyTesseract }"
|
||||
@click="buyTesseract">
|
||||
<p>Buy a Tesseract</p>
|
||||
<p>Increase dimension caps by {{ shorten(nextDimCapIncrease, 2) }}</p>
|
||||
<p><b>Costs: {{ shorten(tesseractCost, 0, 0) }} IP</b></p>
|
||||
</button>
|
||||
<div>Total dimension cap increase: {{ shorten(totalDimCapIncrease, 2) }}</div>
|
||||
</div>
|
||||
<div>You are getting {{shortenDimensions(powerPerSecond)}} {{incomeType}} per second.</div>
|
||||
template: `
|
||||
<div class="l-infinity-dim-tab">
|
||||
<div class="c-subtab-option-container">
|
||||
<primary-button
|
||||
v-if="!isEC8Running"
|
||||
class="o-primary-btn--buy-max l-infinity-dim-tab__buy-max"
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="maxAll"
|
||||
>Max all</primary-button>
|
||||
<div class="l-infinity-dim-tab__row-container">
|
||||
<infinity-dim-row
|
||||
v-for="tier in 8"
|
||||
:key="tier"
|
||||
:tier="tier"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isEC8Running"
|
||||
class="l-infinity-dim-tab__ec8-purchases"
|
||||
>You have {{EC8PurchasesLeft}} {{"purchase" | pluralize(EC8PurchasesLeft)}} left.</div>
|
||||
<primary-button
|
||||
v-if="isAnyAutobuyerUnlocked && !isEC8Running"
|
||||
class="o-primary-btn--id-all-autobuyers l-infinity-dim-tab__all-autobuyers"
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="toggleAllAutobuyers"
|
||||
>Toggle all ON/OFF</primary-button>
|
||||
</div>`
|
||||
});
|
||||
>Toggle all autobuyers</primary-button>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
You have
|
||||
<span class="c-infinity-dim-description__accent">{{format(infinityPower, 2, 1)}}</span> infinity power,
|
||||
translated to a
|
||||
<span class="c-infinity-dim-description__accent">{{formatX(dimMultiplier, 2, 1)}}</span>
|
||||
multiplier on all Antimatter Dimensions (^{{ format(conversionRate, 2, 3) }}).
|
||||
</p>
|
||||
</div>
|
||||
<div class="l-infinity-dim-tab__enslaved-reward-container" v-if="enslavedCompleted">
|
||||
<button
|
||||
class="c-infinity-dim-tab__tesseract-button"
|
||||
:class="{ 'c-infinity-dim-tab__tesseract-button--disabled': !canBuyTesseract }"
|
||||
@click="buyTesseract">
|
||||
<p>Buy a Tesseract</p>
|
||||
<p>Increase dimension caps by {{ format(nextDimCapIncrease, 2) }}</p>
|
||||
<p><b>Costs: {{ format(tesseractCost) }} IP</b></p>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="isEnslavedRunning">
|
||||
All Infinity Dimensions are limited to a single purchase.
|
||||
</div>
|
||||
<div v-else>
|
||||
All Infinity Dimensions except for the 8th are limited to a maximum of {{format(totalDimCap, 2)}}
|
||||
purchases each.
|
||||
</div>
|
||||
<div>You are getting {{format(powerPerSecond, 2, 0)}} {{incomeType}} per second.</div>
|
||||
<div class="l-dimensions-container">
|
||||
<infinity-dim-row
|
||||
v-for="tier in 8"
|
||||
:key="tier"
|
||||
:tier="tier"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isEC8Running"
|
||||
class="l-infinity-dim-tab__ec8-purchases"
|
||||
>You have {{formatInt(EC8PurchasesLeft)}} {{"purchase" | pluralize(EC8PurchasesLeft)}} left.</div>
|
||||
</div>`
|
||||
});
|
||||
|
@ -1,100 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("normal-dim-galaxy-row", {
|
||||
data() {
|
||||
return {
|
||||
type: GalaxyType.NORMAL,
|
||||
galaxies: {
|
||||
normal: 0,
|
||||
replicanti: 0,
|
||||
dilation: 0
|
||||
},
|
||||
requirement: {
|
||||
tier: 1,
|
||||
amount: 0
|
||||
},
|
||||
canBeBought: false,
|
||||
distantStart: 0,
|
||||
lockText: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dimName() {
|
||||
return DISPLAY_NAMES[this.requirement.tier];
|
||||
},
|
||||
buttonText() {
|
||||
return this.lockText === null
|
||||
? "Lose all your previous progress, but get a tickspeed boost"
|
||||
: this.lockText;
|
||||
},
|
||||
sumText() {
|
||||
const parts = [this.galaxies.normal];
|
||||
if (this.galaxies.replicanti > 0) parts.push(this.galaxies.replicanti);
|
||||
if (this.galaxies.dilation > 0) parts.push(this.galaxies.dilation);
|
||||
const sum = parts.map(shortenSmallInteger).join(" + ");
|
||||
if (parts.length >= 2) {
|
||||
return `${sum} = ${shortenSmallInteger(parts.sum())}`;
|
||||
}
|
||||
return sum;
|
||||
},
|
||||
typeName() {
|
||||
switch (this.type) {
|
||||
case GalaxyType.NORMAL: return "Antimatter Galaxies";
|
||||
case GalaxyType.DISTANT: return "Distant Antimatter Galaxies";
|
||||
case GalaxyType.REMOTE: return "Remote Antimatter Galaxies";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
hasIncreasedScaling() {
|
||||
return this.type !== GalaxyType.NORMAL;
|
||||
},
|
||||
costScalingText() {
|
||||
switch (this.type) {
|
||||
case GalaxyType.DISTANT:
|
||||
return `Each galaxy is more expensive past ${shortenSmallInteger(this.distantStart)} galaxies`;
|
||||
case GalaxyType.REMOTE:
|
||||
return "Increased galaxy cost scaling: " +
|
||||
`Quadratic past ${shortenSmallInteger(this.distantStart)} (distant),
|
||||
exponential past ${shortenSmallInteger(800)} (remote)`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.type = Galaxy.type;
|
||||
this.galaxies.normal = player.galaxies;
|
||||
this.galaxies.replicanti = Replicanti.galaxies.total;
|
||||
this.galaxies.dilation = player.dilation.freeGalaxies;
|
||||
const requirement = Galaxy.requirement;
|
||||
this.requirement.amount = requirement.amount;
|
||||
this.requirement.tier = requirement.tier;
|
||||
this.canBeBought = requirement.isSatisfied && Galaxy.canBeBought;
|
||||
this.distantStart = EternityChallenge(5).isRunning ? 0 : Galaxy.costScalingStart;
|
||||
this.lockText = this.generateLockText();
|
||||
},
|
||||
generateLockText() {
|
||||
if (Galaxy.canBeBought) return null;
|
||||
if (EternityChallenge(6).isRunning) return "Locked (Eternity Challenge 6)";
|
||||
if (InfinityChallenge(7).isRunning) return "Locked (Infinity Challenge 7)";
|
||||
if (NormalChallenge(8).isRunning) return "Locked (8th Dimension Autobuyer Challenge)";
|
||||
return null;
|
||||
},
|
||||
buyGalaxy: bulk => galaxyResetBtnClick(bulk),
|
||||
},
|
||||
template:
|
||||
`<div class="c-normal-dim-row">
|
||||
<div
|
||||
class="c-normal-dim-row__label c-normal-dim-row__label--growable"
|
||||
>{{typeName}} ({{sumText}}):
|
||||
requires {{shortenSmallInteger(requirement.amount)}} {{dimName}} Dimensions
|
||||
<div v-if="hasIncreasedScaling">{{costScalingText}}</div>
|
||||
</div>
|
||||
<primary-button
|
||||
:enabled="canBeBought"
|
||||
class="o-primary-btn--galaxy c-normal-dim-row__buy-button c-normal-dim-row__buy-button--right-offset"
|
||||
@click.exact="buyGalaxy(true)"
|
||||
@click.shift.exact="buyGalaxy(false)"
|
||||
>{{buttonText}}</primary-button>
|
||||
</div>`
|
||||
});
|
@ -1,104 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("normal-dim-row", {
|
||||
props: {
|
||||
floatingText: Array,
|
||||
tier: Number
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
isCapped: false,
|
||||
multiplier: new Decimal(0),
|
||||
amount: new Decimal(0),
|
||||
boughtBefore10: 0,
|
||||
rateOfChange: new Decimal(0),
|
||||
singleCost: new Decimal(0),
|
||||
until10Cost: new Decimal(0),
|
||||
isAffordable: false,
|
||||
isAffordableUntil10: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return DISPLAY_NAMES[this.tier];
|
||||
},
|
||||
amountDisplay() {
|
||||
return this.tier < 8 ? shorten(this.amount, 2, 0) : shortenSmallInteger(this.amount);
|
||||
},
|
||||
rateOfChangeDisplay() {
|
||||
return this.tier < 8
|
||||
? ` (+${shorten(this.rateOfChange, 2, 2)}%/s)`
|
||||
: "";
|
||||
},
|
||||
cappedTooltip() {
|
||||
return this.isCapped
|
||||
? "Further eighth dimension purchases are prohibited, as they are the only way to acquire galaxies"
|
||||
: null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const tier = this.tier;
|
||||
const isUnlocked = NormalDimension(tier).isAvailable;
|
||||
this.isUnlocked = isUnlocked;
|
||||
if (!isUnlocked) return;
|
||||
const dimension = NormalDimension(tier);
|
||||
this.isCapped = tier === 8 && Enslaved.isRunning && dimension.bought >= 1;
|
||||
this.multiplier.copyFrom(getDimensionFinalMultiplier(tier));
|
||||
this.amount.copyFrom(dimension.amount);
|
||||
this.boughtBefore10 = dimension.boughtBefore10;
|
||||
this.singleCost.copyFrom(dimension.cost);
|
||||
this.until10Cost.copyFrom(dimension.costUntil10);
|
||||
if (tier < 8) {
|
||||
this.rateOfChange.copyFrom(dimension.rateOfChange);
|
||||
}
|
||||
this.isAffordable = dimension.isAffordable;
|
||||
this.isAffordableUntil10 = dimension.isAffordableUntil10;
|
||||
},
|
||||
buySingle() {
|
||||
buyOneDimensionBtnClick(this.tier);
|
||||
},
|
||||
buyUntil10() {
|
||||
buyManyDimensionsBtnClick(this.tier);
|
||||
},
|
||||
showCostTitle(value) {
|
||||
return value.exponent < 1000000;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div v-show="isUnlocked" class="c-normal-dim-row">
|
||||
<div class="c-normal-dim-row__name c-normal-dim-row__label">
|
||||
{{name}} Dimension x{{shorten(multiplier, 1, 1)}}
|
||||
</div>
|
||||
<div class="c-normal-dim-row__label c-normal-dim-row__label--growable">
|
||||
{{amountDisplay}} ({{shortenSmallInteger(boughtBefore10)}}){{rateOfChangeDisplay}}
|
||||
</div>
|
||||
<primary-button
|
||||
:enabled="isAffordable"
|
||||
class="o-primary-btn--buy-nd o-primary-btn--buy-single-nd c-normal-dim-row__buy-button"
|
||||
:ach-tooltip="cappedTooltip"
|
||||
@click="buySingle">
|
||||
<span v-if="isCapped">Capped!</span>
|
||||
<template v-else>
|
||||
<span v-if="showCostTitle(singleCost)">Cost: </span>{{shorten(singleCost)}}
|
||||
</template>
|
||||
</primary-button>
|
||||
<primary-button
|
||||
:enabled="isAffordableUntil10"
|
||||
class="o-primary-btn--buy-nd o-primary-btn--buy-10-nd c-normal-dim-row__buy-button"
|
||||
:ach-tooltip="cappedTooltip"
|
||||
@click="buyUntil10">
|
||||
<span v-if="isCapped">Capped!</span>
|
||||
<template v-else>
|
||||
Until {{shortenSmallInteger(10)}}, <span v-if="showCostTitle(until10Cost)">
|
||||
Cost: </span>{{shorten(until10Cost)}}
|
||||
</template>
|
||||
</primary-button>
|
||||
<div
|
||||
v-for="text in floatingText"
|
||||
:key="text.key"
|
||||
class='c-normal-dim-row__floating-text'
|
||||
>{{text.text}}</div>
|
||||
</div>`,
|
||||
});
|
@ -1,48 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("normal-dim-tab-progress-bar", {
|
||||
data() {
|
||||
return {
|
||||
fill: new Decimal(0),
|
||||
tooltip: ""
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
percents() {
|
||||
return `${this.fill.toFixed(2)}%`;
|
||||
},
|
||||
progressBarStyle() {
|
||||
return {
|
||||
width: this.percents
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const setProgress = (current, goal, tooltip) => {
|
||||
this.fill.copyFrom(Decimal.min(current.pLog10() / Decimal.log10(goal) * 100, 100));
|
||||
this.tooltip = tooltip;
|
||||
};
|
||||
const challenge = NormalChallenge.current || InfinityChallenge.current;
|
||||
if (challenge) {
|
||||
setProgress(player.antimatter, challenge.goal, "Percentage to challenge goal");
|
||||
} else if (!player.break) {
|
||||
setProgress(player.antimatter, Decimal.MAX_NUMBER, "Percentage to Infinity");
|
||||
} else if (InfinityDimension(8).isUnlocked) {
|
||||
setProgress(
|
||||
player.infinityPoints,
|
||||
Player.eternityGoal,
|
||||
EternityChallenge.isRunning ? "Percentage to Eternity Challenge goal" : "Percentage to Eternity"
|
||||
);
|
||||
} else {
|
||||
setProgress(player.antimatter, InfinityDimensions.next().requirement, "Percentage to next dimension unlock");
|
||||
}
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="c-progress-bar">
|
||||
<div :style="progressBarStyle" class="c-progress-bar__fill">
|
||||
<span v-tooltip="tooltip" class="c-progress-bar__percents">{{percents}}</span>
|
||||
</div>
|
||||
</div>`
|
||||
});
|
@ -19,15 +19,15 @@ Vue.component("time-dim-row", {
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return DISPLAY_NAMES[this.tier];
|
||||
return TimeDimension(this.tier).shortDisplayName;
|
||||
},
|
||||
rateOfChangeDisplay() {
|
||||
return this.tier < 8
|
||||
? ` (+${this.shortenRateOfChange(this.rateOfChange)}%/s)`
|
||||
? ` (+${format(this.rateOfChange, 2, 2)}%/s)`
|
||||
: "";
|
||||
},
|
||||
buttonContents() {
|
||||
return this.isCapped ? "Capped" : `Cost: ${this.shortenDimensions(this.cost)} EP`;
|
||||
return this.isCapped ? "Capped" : `Cost: ${format(this.cost, 2)} EP`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -53,27 +53,37 @@ Vue.component("time-dim-row", {
|
||||
this.isAutobuyerOn = player.reality.tdbuyers[this.tier - 1];
|
||||
},
|
||||
buyTimeDimension() {
|
||||
buyTimeDimension(this.tier);
|
||||
}
|
||||
buySingleTimeDimension(this.tier);
|
||||
},
|
||||
buyMaxTimeDimension() {
|
||||
buyMaxTimeDimension(this.tier);
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<div v-show="isUnlocked" class="c-time-dim-row">
|
||||
<div class="c-time-dim-row__label c-time-dim-row__name">
|
||||
{{name}} Time Dimension x{{shortenMoney(multiplier)}}
|
||||
<div class="c-dim-row__label c-dim-row__name">
|
||||
{{name}} Time Dimension {{formatX(multiplier, 2, 1)}}
|
||||
</div>
|
||||
<div class="c-time-dim-row__label c-time-dim-row__label--growable">
|
||||
{{shortenDimensions(amount)}}{{rateOfChangeDisplay}}
|
||||
<div class="c-dim-row__label c-dim-row__label--growable">
|
||||
{{format(amount, 2, 0)}}
|
||||
<span class="c-dim-row__label--small" v-if="rateOfChange.neq(0)">{{rateOfChangeDisplay}}</span>
|
||||
</div>
|
||||
<primary-button
|
||||
:enabled="isAffordable && !isCapped"
|
||||
class="o-primary-btn--buy-td l-dim-row__button"
|
||||
@click="buyTimeDimension"
|
||||
>{{buttonContents}}</primary-button>
|
||||
<primary-button-on-off
|
||||
v-if="areAutobuyersUnlocked"
|
||||
v-model="isAutobuyerOn"
|
||||
class="o-primary-btn--td-autobuyer l-time-dim-row__button"
|
||||
class="o-primary-btn--td-autobuyer l-dim-row__button"
|
||||
text="Auto:"
|
||||
/>
|
||||
<primary-button
|
||||
:enabled="isAffordable"
|
||||
class="o-primary-btn--buy-td l-time-dim-row__button"
|
||||
@click="buyTimeDimension"
|
||||
>{{buttonContents}}</primary-button>
|
||||
v-else
|
||||
:enabled="isAffordable && !isCapped"
|
||||
class="o-primary-btn--buy-td-max l-dim-row__button"
|
||||
@click="buyMaxTimeDimension"
|
||||
>Buy Max</primary-button>
|
||||
</div>`,
|
||||
});
|
||||
|
@ -4,68 +4,75 @@ Vue.component("time-dim-tab", {
|
||||
data() {
|
||||
return {
|
||||
totalUpgrades: 0,
|
||||
multPerTickspeed: 0,
|
||||
tickspeedSoftcap: 0,
|
||||
timeShards: new Decimal(0),
|
||||
upgradeThreshold: new Decimal(0),
|
||||
shardsPerSecond: new Decimal(0),
|
||||
incomeType: "",
|
||||
showCostScaleTooltip: false,
|
||||
areAutobuyersUnlocked: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
e6000Tooltip() {
|
||||
return `TD costs start increasing faster after ${shorten(new Decimal("1e6000"))}`;
|
||||
},
|
||||
costScaleTooltip() {
|
||||
return this.showCostScaleTooltip ? this.e6000Tooltip : undefined;
|
||||
}
|
||||
costIncreases: () => TimeDimension(1).costIncreaseThresholds,
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.totalUpgrades = player.totalTickGained;
|
||||
this.multPerTickspeed = FreeTickspeed.multToNext;
|
||||
this.tickspeedSoftcap = FreeTickspeed.softcap;
|
||||
this.timeShards.copyFrom(player.timeShards);
|
||||
this.upgradeThreshold.copyFrom(player.tickThreshold);
|
||||
this.shardsPerSecond.copyFrom(TimeDimension(1).productionPerSecond);
|
||||
this.upgradeThreshold.copyFrom(FreeTickspeed.fromShards(player.timeShards).nextShards);
|
||||
this.shardsPerSecond.copyFrom(TimeDimension(1).productionPerRealSecond);
|
||||
this.incomeType = EternityChallenge(7).isRunning ? "Eighth Infinity Dimensions" : "time shards";
|
||||
this.showCostScaleTooltip = player.eternityPoints.exponent > 6000;
|
||||
this.areAutobuyersUnlocked = RealityUpgrade(13).isBought;
|
||||
},
|
||||
maxAll() {
|
||||
buyMaxTimeDimensions();
|
||||
maxAllTimeDimensions();
|
||||
},
|
||||
toggleAllAutobuyers() {
|
||||
toggleAllTimeDims();
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-time-dim-tab l-centered-vertical-tab">
|
||||
<div>
|
||||
<p>You've gained {{shortenSmallInteger(totalUpgrades)}} tickspeed upgrades.</p>
|
||||
<p>
|
||||
You have
|
||||
<span class="c-time-dim-description__accent">{{shortenMoney(timeShards)}}</span> time shards.
|
||||
Next tickspeed upgrade at
|
||||
<span class="c-time-dim-description__accent">{{shortenMoney(upgradeThreshold)}}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div>You are getting {{shortenDimensions(shardsPerSecond)}} {{incomeType}} per second.</div>
|
||||
template: `
|
||||
<div class="l-time-dim-tab l-centered-vertical-tab">
|
||||
<div class="c-subtab-option-container">
|
||||
<primary-button
|
||||
v-tooltip="costScaleTooltip"
|
||||
class="o-primary-btn--buy-max l-time-dim-tab__buy-max"
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="maxAll"
|
||||
>Max all</primary-button>
|
||||
<div class="l-time-dim-tab__row-container">
|
||||
<time-dim-row
|
||||
v-for="tier in 8"
|
||||
:key="tier"
|
||||
:tier="tier"
|
||||
:areAutobuyersUnlocked="areAutobuyersUnlocked"
|
||||
/>
|
||||
</div>
|
||||
<primary-button
|
||||
v-if="areAutobuyersUnlocked"
|
||||
class="o-primary-btn--td-all-autobuyers l-time-dim-tab__all-autobuyers"
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="toggleAllAutobuyers"
|
||||
>Toggle all ON/OFF</primary-button>
|
||||
</div>`
|
||||
});
|
||||
>Toggle all autobuyers</primary-button>
|
||||
</div>
|
||||
<div>
|
||||
<p>You've gained {{formatInt(totalUpgrades)}} tickspeed upgrades.</p>
|
||||
<p>
|
||||
You have
|
||||
<span class="c-time-dim-description__accent">{{format(timeShards, 2, 1)}}</span> time shards.
|
||||
Next tickspeed upgrade at
|
||||
<span class="c-time-dim-description__accent">{{format(upgradeThreshold, 2, 1)}}.</span>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
Each additional upgrade requires {{formatX(multPerTickspeed, 2, 2)}} more time shards. This will start
|
||||
increasing above {{formatInt(tickspeedSoftcap)}} upgrades.
|
||||
</div>
|
||||
<div>You are getting {{format(shardsPerSecond, 2, 0)}} {{incomeType}} per second.</div>
|
||||
<div class="l-dimensions-container">
|
||||
<time-dim-row
|
||||
v-for="tier in 8"
|
||||
:key="tier"
|
||||
:tier="tier"
|
||||
:areAutobuyersUnlocked="areAutobuyersUnlocked"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Time Dimension costs jump at {{format(costIncreases[0], 2, 2)}} EP and {{format(costIncreases[1])}} EP,
|
||||
<br>
|
||||
and get expensive more quickly past {{format(costIncreases[2])}} EP
|
||||
</div>
|
||||
</div>`
|
||||
});
|
||||
|
@ -14,10 +14,10 @@ Vue.component("dilation-button", {
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.isUnlocked = TimeStudy.dilation.isBought;
|
||||
this.isUnlocked = PlayerProgress.dilationUnlocked();
|
||||
this.isRunning = player.dilation.active;
|
||||
if (!this.isRunning) return;
|
||||
this.canEternity = player.infinityPoints.gte(Player.eternityGoal);
|
||||
this.canEternity = Player.canEternity;
|
||||
this.hasGain = getTachyonGain().gt(0);
|
||||
if (this.canEternity && this.hasGain) {
|
||||
this.tachyonGain.copyFrom(getTachyonGain());
|
||||
@ -35,19 +35,19 @@ Vue.component("dilation-button", {
|
||||
<span v-if="!isUnlocked">Purchase the dilation time study to unlock.</span>
|
||||
<span v-else-if="!isRunning">Dilate time.</span>
|
||||
<span v-else-if="canEternity && hasGain">
|
||||
Disable dilation.
|
||||
Disable Dilation.
|
||||
<br>
|
||||
Gain {{shortenMoney(tachyonGain)}} Tachyon Particles.
|
||||
Gain {{format(tachyonGain, 2, 1)}} Tachyon Particles.
|
||||
</span>
|
||||
<span v-else-if="hasGain">
|
||||
Disable dilation.
|
||||
Disable Dilation.
|
||||
<br>
|
||||
Reach {{shorten(eternityGoal, 1, 0)}} IP to eternity and gain Tachyon Particles.
|
||||
Reach {{format(eternityGoal, 1, 0)}} IP to eternity and gain Tachyon Particles.
|
||||
</span>
|
||||
<span v-else>
|
||||
Disable dilation.
|
||||
Disable Dilation.
|
||||
<br>
|
||||
Reach {{shortenMoney(requiredForGain)}} antimatter to gain more Tachyon Particles.
|
||||
Reach {{format(requiredForGain, 2, 1)}} antimatter to gain more Tachyon Particles.
|
||||
</span>
|
||||
</button>`
|
||||
});
|
||||
|
@ -11,6 +11,7 @@ Vue.component("dilation-upgrade", {
|
||||
data() {
|
||||
return {
|
||||
isBought: false,
|
||||
isCapped: false,
|
||||
isAffordable: false,
|
||||
isAutoUnlocked: false,
|
||||
isAutobuyerOn: false,
|
||||
@ -26,9 +27,10 @@ Vue.component("dilation-upgrade", {
|
||||
return {
|
||||
"o-dilation-upgrade": true,
|
||||
"o-dilation-upgrade--rebuyable": this.isRebuyable,
|
||||
"o-dilation-upgrade--available": !this.isBought && !this.isCapped && this.isAffordable,
|
||||
"o-dilation-upgrade--unavailable": !this.isBought && !this.isCapped && !this.isAffordable,
|
||||
"o-dilation-upgrade--bought": this.isBought,
|
||||
"o-dilation-upgrade--available": !this.isBought && this.isAffordable,
|
||||
"o-dilation-upgrade--unavailable": !this.isBought && !this.isAffordable
|
||||
"o-dilation-upgrade--capped": this.isCapped,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -36,6 +38,7 @@ Vue.component("dilation-upgrade", {
|
||||
update() {
|
||||
if (this.isRebuyable) {
|
||||
this.isAffordable = this.upgrade.isAffordable;
|
||||
this.isCapped = this.upgrade.isCapped;
|
||||
} else {
|
||||
this.isBought = this.upgrade.isBought;
|
||||
if (!this.isBought) {
|
||||
@ -56,7 +59,7 @@ Vue.component("dilation-upgrade", {
|
||||
/>
|
||||
<effect-display br :config="upgrade.config" />
|
||||
<cost-display br
|
||||
v-if="!isBought"
|
||||
v-if="!isBought && !isCapped"
|
||||
:config="upgrade.config"
|
||||
singular="Dilated Time"
|
||||
plural="Dilated Time"
|
||||
|
@ -51,21 +51,21 @@ Vue.component("time-dilation-tab", {
|
||||
`<div class="l-dilation-tab">
|
||||
<span>
|
||||
You have
|
||||
<span class="c-dilation-tab__tachyons">{{shorten(tachyons, 2, 1)}}</span>
|
||||
<span class="c-dilation-tab__tachyons">{{format(tachyons, 2, 1)}}</span>
|
||||
Tachyon {{"Particle" | pluralize(tachyons)}}.
|
||||
</span>
|
||||
<dilation-button />
|
||||
<span>
|
||||
You have
|
||||
<span class="c-dilation-tab__dilated-time">{{shorten(dilatedTime, 2, 1)}}</span>
|
||||
<span class="c-dilation-tab__dilated-time">{{format(dilatedTime, 2, 1)}}</span>
|
||||
Dilated Time.
|
||||
<span class="c-dilation-tab__dilated-time-income">+{{shorten(dilatedTimeIncome, 2, 1)}}/s</span>
|
||||
<span class="c-dilation-tab__dilated-time-income">+{{format(dilatedTimeIncome, 2, 1)}}/s</span>
|
||||
</span>
|
||||
<span>
|
||||
Next free galaxy at
|
||||
<span class="c-dilation-tab__galaxy-threshold">{{shorten(galaxyThreshold, 2, 1)}}</span>
|
||||
<span class="c-dilation-tab__galaxy-threshold">{{format(galaxyThreshold, 2, 1)}}</span>
|
||||
Dilated Time, gained total of
|
||||
<span class="c-dilation-tab__galaxies">{{shortenSmallInteger(galaxies)}}</span>
|
||||
<span class="c-dilation-tab__galaxies">{{formatInt(galaxies)}}</span>
|
||||
galaxies
|
||||
</span>
|
||||
<div class="l-dilation-upgrades-grid">
|
||||
@ -95,4 +95,4 @@ Vue.component("time-dilation-tab", {
|
||||
</div>
|
||||
<tachyon-particles v-if="animateTachyons" />
|
||||
</div>`
|
||||
});
|
||||
});
|
||||
|
21
javascripts/components/eternity/eternity-points-header.js
Normal file
@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("eternity-points-header", {
|
||||
data() {
|
||||
return {
|
||||
eternityPoints: new Decimal(0)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.eternityPoints.copyFrom(player.eternityPoints.floor());
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="c-eternity-tab__header">
|
||||
You have
|
||||
<span class="c-eternity-tab__eternity-points">{{format(eternityPoints, 2, 0)}}</span>
|
||||
{{ "Eternity Point" | pluralize(eternityPoints) }}.
|
||||
</div>
|
||||
`
|
||||
});
|
@ -40,7 +40,7 @@ Vue.component("eternity-milestone", {
|
||||
template:
|
||||
`<div class="l-eternity-milestone" v-if="!this.config.invisible">
|
||||
<span class="o-eternity-milestone__goal">
|
||||
{{eternities}} {{"Eternity" | pluralize(eternities, "Eternities")}}:
|
||||
{{formatInt(eternities)}} {{"Eternity" | pluralize(eternities, "Eternities")}}:
|
||||
</span>
|
||||
<button :class="rewardClassObject">{{reward}}</button>
|
||||
</div>`
|
||||
|
@ -26,7 +26,7 @@ Vue.component("eternity-milestones-tab", {
|
||||
},
|
||||
template:
|
||||
`<div class="l-eternity-milestone-grid">
|
||||
<div>You have eternitied {{shorten(eternityCount, 3)}} {{"time" | pluralize(eternityCount)}}.</div>
|
||||
<div>You have eternitied {{format(eternityCount, 3)}} {{"time" | pluralize(eternityCount)}}.</div>
|
||||
<div v-for="row in rows" class="l-eternity-milestone-grid__row">
|
||||
<eternity-milestone
|
||||
v-for="column in 3"
|
||||
@ -36,12 +36,13 @@ Vue.component("eternity-milestones-tab", {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Offline eternities only generate when your eternity autobuyer is on and set to zero EP.
|
||||
Offline eternities only generate outside of Eternity Challenges and when
|
||||
your Eternity autobuyer is turned on and set to zero EP.
|
||||
</div>
|
||||
<div>
|
||||
Offline infinities only generate when your infinity autobuyer is on and set to time mode with
|
||||
less than 60 seconds.
|
||||
Offline infinities only generate outside of Eternity Challenges 4 and 12 and when
|
||||
your infinity autobuyer is turned on and set to time mode with less than {{formatInt(60)}} seconds.
|
||||
</div>
|
||||
|
||||
</div>`
|
||||
});
|
||||
});
|
||||
|
@ -17,20 +17,19 @@ Vue.component("dilation-time-study", {
|
||||
},
|
||||
id() {
|
||||
return this.study.id;
|
||||
},
|
||||
classObject() {
|
||||
return {
|
||||
"o-time-study--dilation": this.id !== 6,
|
||||
"o-time-study--reality": this.id === 6
|
||||
};
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.id === 1) {
|
||||
this.requirement = `Requirement: 5 EC11 and EC12 completions and ${shortenSmallInteger(13000)} total theorems`;
|
||||
this.requirement = `Requirement: ${formatInt(5)} EC11 and EC12 completions
|
||||
and ${formatInt(13000)} total Time Theorems`;
|
||||
}
|
||||
if (this.id === 6) {
|
||||
this.requirement = `Requirement: ${shorten("1e4000")} EP and ${shortenSmallInteger(13)} rows of achievements`;
|
||||
if (player.realities > 0) {
|
||||
this.requirement = `Requirement: ${format("1e4000")} EP`;
|
||||
} else {
|
||||
this.requirement = `Requirement: ${format("1e4000")} EP and ${formatInt(13)} rows of achievements`;
|
||||
}
|
||||
this.showRequirement = true;
|
||||
}
|
||||
},
|
||||
@ -44,11 +43,11 @@ Vue.component("dilation-time-study", {
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<time-study :setup="setup" :showCost="showCost" :class="classObject">
|
||||
`<time-study :setup="setup" :showCost="showCost">
|
||||
<description-display :config="study.config" />
|
||||
<template v-if="showRequirement">
|
||||
<br>
|
||||
<span>{{requirement}}</span>
|
||||
</template>
|
||||
</time-study>`
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,9 @@ Vue.component("ec-time-study", {
|
||||
requirement: {
|
||||
current: new Decimal(0),
|
||||
total: new Decimal(0)
|
||||
}
|
||||
},
|
||||
completions: 0,
|
||||
showTotalCompletions: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -28,12 +30,21 @@ Vue.component("ec-time-study", {
|
||||
},
|
||||
formatValue() {
|
||||
return this.config.requirement.formatValue;
|
||||
},
|
||||
// Linebreaks added to avoid twitching in scientific notation
|
||||
needsFirstLinebreak() {
|
||||
return this.study.id === 7;
|
||||
},
|
||||
needsSecondLinebreak() {
|
||||
return [3, 4, 7].includes(this.study.id);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const id = this.id;
|
||||
this.hasRequirement = !Perk.studyECRequirement.isBought && player.etercreq !== id;
|
||||
this.completions = EternityChallenge(id).completions;
|
||||
this.showTotalCompletions = !Enslaved.isRunning || this.id !== 1;
|
||||
if (!this.hasRequirement || id > 10) return;
|
||||
const requirement = this.requirement;
|
||||
const study = this.study;
|
||||
@ -47,15 +58,18 @@ Vue.component("ec-time-study", {
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<time-study :setup="setup" class="o-time-study--eternity-challenge">
|
||||
`<time-study :setup="setup">
|
||||
Eternity Challenge {{id}}
|
||||
({{formatInt(completions)}}<span v-if="showTotalCompletions">/{{formatInt(5)}}</span>)
|
||||
<template v-if="hasRequirement">
|
||||
<br>
|
||||
Requirement:
|
||||
<br v-if="needsFirstLinebreak">
|
||||
<span v-if="id === 12">Use only the Time Dimension path</span>
|
||||
<span v-else-if="id === 11">Use only the Normal Dimension path</span>
|
||||
<span v-else-if="id === 11">Use only the Antimatter Dimension path</span>
|
||||
<span v-else>
|
||||
{{formatValue(requirement.current)}}/{{formatValue(requirement.total)}}
|
||||
<br v-if="needsSecondLinebreak">
|
||||
{{config.requirement.resource}}
|
||||
</span>
|
||||
</template>
|
||||
|
@ -6,40 +6,23 @@ Vue.component("normal-time-study", {
|
||||
},
|
||||
data: () => ({
|
||||
showCost: true,
|
||||
showSTCost: false
|
||||
}),
|
||||
computed: {
|
||||
study() {
|
||||
return this.setup.study;
|
||||
},
|
||||
classObject() {
|
||||
const classObject = {};
|
||||
classObject[this.pathClass] = true;
|
||||
return classObject;
|
||||
},
|
||||
pathClass() {
|
||||
switch (this.setup.path) {
|
||||
case TimeStudyPath.NORMAL_DIM: return "o-time-study--normal-dim";
|
||||
case TimeStudyPath.INFINITY_DIM: return "o-time-study--infinity-dim";
|
||||
case TimeStudyPath.TIME_DIM: return "o-time-study--time-dim";
|
||||
case TimeStudyPath.ACTIVE: return "o-time-study--active";
|
||||
case TimeStudyPath.PASSIVE: return "o-time-study--passive";
|
||||
case TimeStudyPath.IDLE: return "o-time-study--idle";
|
||||
case TimeStudyPath.LIGHT: return "o-time-study--light";
|
||||
case TimeStudyPath.DARK: return "o-time-study--dark";
|
||||
default: return "o-time-study--normal";
|
||||
}
|
||||
},
|
||||
hintText() {
|
||||
const id = this.study.id;
|
||||
switch (this.setup.path) {
|
||||
case TimeStudyPath.NORMAL_DIM: return id + " Normal Dims";
|
||||
case TimeStudyPath.INFINITY_DIM: return id + " Infinity Dims";
|
||||
case TimeStudyPath.TIME_DIM: return id + " Time Dims";
|
||||
case TimeStudyPath.ACTIVE: return id + " Active";
|
||||
case TimeStudyPath.PASSIVE: return id + " Passive";
|
||||
case TimeStudyPath.IDLE: return id + " Idle";
|
||||
case TimeStudyPath.LIGHT: return id + " Light";
|
||||
case TimeStudyPath.DARK: return id + " Dark";
|
||||
case TIME_STUDY_PATH.ANTIMATTER_DIM: return `${id} Antimatter Dims`;
|
||||
case TIME_STUDY_PATH.INFINITY_DIM: return `${id} Infinity Dims`;
|
||||
case TIME_STUDY_PATH.TIME_DIM: return `${id} Time Dims`;
|
||||
case TIME_STUDY_PATH.ACTIVE: return `${id} Active`;
|
||||
case TIME_STUDY_PATH.PASSIVE: return `${id} Passive`;
|
||||
case TIME_STUDY_PATH.IDLE: return `${id} Idle`;
|
||||
case TIME_STUDY_PATH.LIGHT: return `${id} Light`;
|
||||
case TIME_STUDY_PATH.DARK: return `${id} Dark`;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@ -47,12 +30,20 @@ Vue.component("normal-time-study", {
|
||||
methods: {
|
||||
update() {
|
||||
this.showCost = this.study.id !== 192 || !Enslaved.isRunning;
|
||||
const canBeBought = typeof this.study.config.requirement === "function"
|
||||
? this.study.config.requirement()
|
||||
: TimeStudy(this.study.config.requirement).isBought;
|
||||
|
||||
this.showSTCost = !canBeBought && V.has(V_UNLOCKS.V_ACHIEVEMENT_UNLOCK) &&
|
||||
this.study.config.requirementV !== undefined &&
|
||||
this.study.config.requirementV() &&
|
||||
this.study.STCost !== undefined;
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<time-study :setup="setup" :showCost="showCost" :class="classObject"">
|
||||
<hint-text class="l-hint-text--time-study">{{hintText}}</hint-text>
|
||||
`<time-study :setup="setup" :showCost="showCost" :showSTCost="showSTCost">
|
||||
<hint-text type="studies" class="l-hint-text--time-study">{{hintText}}</hint-text>
|
||||
<description-display :config="study.config" />
|
||||
<effect-display br :config="study.config" />
|
||||
</time-study>`
|
||||
});
|
||||
});
|
||||
|
@ -36,8 +36,11 @@ Vue.component("secret-time-study", {
|
||||
"l-time-study": true,
|
||||
"o-time-study": true,
|
||||
"o-time-study--bought": true,
|
||||
"o-time-study--secret": true,
|
||||
"o-time-study--secret-unlocked": this.isVisible
|
||||
"o-time-study-normal": true,
|
||||
"o-time-study-normal--bought": true,
|
||||
"o-time-study--secret": !this.isEnslaved && !this.isVisible,
|
||||
"o-time-study--secret-enslaved": this.isEnslaved && !this.isVisible,
|
||||
"o-time-study--secret-unlocked": this.isVisible,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -67,6 +70,7 @@ Vue.component("secret-time-study", {
|
||||
}
|
||||
if (this.isEnslaved) {
|
||||
this.isVisible = true;
|
||||
EnslavedProgress.secretStudy.giveProgress();
|
||||
player.timestudy.theorem = player.timestudy.theorem.plus(this.enslavedTT);
|
||||
}
|
||||
}
|
||||
@ -74,11 +78,13 @@ Vue.component("secret-time-study", {
|
||||
},
|
||||
template:
|
||||
`<button :class="classObject" :style="styleObject" @click="handleClick" ref="study">
|
||||
{{description}}
|
||||
<br>
|
||||
{{hide}}
|
||||
<br>
|
||||
Cost: {{cost}} Time Theorems
|
||||
<span>
|
||||
{{description}}
|
||||
<br>
|
||||
{{hide}}
|
||||
<br>
|
||||
Cost: {{cost}} Time Theorems
|
||||
</span>
|
||||
</button>`
|
||||
});
|
||||
|
||||
|
@ -49,6 +49,7 @@ class TimeStudyTreeLayout {
|
||||
|
||||
const TS = id => TimeStudy(id);
|
||||
const EC = id => TimeStudy.eternityChallenge(id);
|
||||
const TrS = id => TriadStudy(id)
|
||||
|
||||
/**
|
||||
* @type {TimeStudyRow[]}
|
||||
@ -60,7 +61,8 @@ class TimeStudyTreeLayout {
|
||||
normalRow( TS(33), TS(31), TS(32), null )
|
||||
];
|
||||
|
||||
if (type === StudyTreeLayoutType.ALTERNATIVE_62 || type === StudyTreeLayoutType.ALTERNATIVE_62_181) {
|
||||
if (type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_62 || type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_62_181 ||
|
||||
type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_TRIAD_STUDIES) {
|
||||
this.rows.push(
|
||||
normalRow( null, TS(41), TS(42), EC(5) ),
|
||||
normalRow( null, TS(51), TS(62) ),
|
||||
@ -87,7 +89,8 @@ class TimeStudyTreeLayout {
|
||||
normalRow( TS(161), TS(162) )
|
||||
);
|
||||
|
||||
if (type === StudyTreeLayoutType.ALTERNATIVE_181 || type === StudyTreeLayoutType.ALTERNATIVE_62_181) {
|
||||
if (type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_181 || type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_62_181 ||
|
||||
type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_TRIAD_STUDIES) {
|
||||
this.rows.push(
|
||||
normalRow( null, TS(171), EC(2) ),
|
||||
normalRow( EC(1), TS(181), EC(3) )
|
||||
@ -105,7 +108,22 @@ class TimeStudyTreeLayout {
|
||||
normalRow( TS(191), TS(192), TS(193) ),
|
||||
normalRow( TS(201) ),
|
||||
normalRow( TS(211), TS(212), TS(213), TS(214) ),
|
||||
wideRow (TS(221), TS(222), TS(223), TS(224), TS(225), TS(226), TS(227), TS(228)),
|
||||
wideRow (TS(221), TS(222), TS(223), TS(224), TS(225), TS(226), TS(227), TS(228))
|
||||
);
|
||||
|
||||
if (type === STUDY_TREE_LAYOUT_TYPE.ALTERNATIVE_TRIAD_STUDIES) {
|
||||
const vLevel = Ra.pets.v.level;
|
||||
this.rows.push(
|
||||
normalRow(
|
||||
vLevel >= 5 ? TrS(1) : null,
|
||||
vLevel >= 10 ? TrS(2) : null,
|
||||
vLevel >= 15 ? TrS(3) : null,
|
||||
vLevel >= 20 ? TrS(4) : null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
this.rows.push(
|
||||
normalRow( TS(231), TS(232), TS(233), TS(234) ),
|
||||
normalRow( EC(11), EC(12) ),
|
||||
normalRow( TimeStudy.dilation ),
|
||||
@ -176,23 +194,22 @@ class TimeStudyTreeLayout {
|
||||
if (this._instances === undefined) {
|
||||
this._instances = [];
|
||||
}
|
||||
let layout = this._instances[type];
|
||||
if (layout === undefined) {
|
||||
layout = new TimeStudyTreeLayout(type);
|
||||
this._instances[type] = layout;
|
||||
}
|
||||
const layout = new TimeStudyTreeLayout(type);
|
||||
this._instances[type] = layout;
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
|
||||
const StudyTreeLayoutType = {
|
||||
const STUDY_TREE_LAYOUT_TYPE = {
|
||||
NORMAL: 0,
|
||||
ALTERNATIVE_62: 1,
|
||||
ALTERNATIVE_181: 2,
|
||||
ALTERNATIVE_62_181: 3,
|
||||
ALTERNATIVE_TRIAD_STUDIES: 4,
|
||||
get current() {
|
||||
const alt62 = Perk.bypassEC5Lock.isBought;
|
||||
const alt181 = Perk.bypassEC1Lock.isBought && Perk.bypassEC2Lock.isBought && Perk.bypassEC3Lock.isBought;
|
||||
if (Ra.pets.v.level >= 5) return this.ALTERNATIVE_TRIAD_STUDIES;
|
||||
if (alt62 && alt181) return this.ALTERNATIVE_62_181;
|
||||
if (alt62) return this.ALTERNATIVE_62;
|
||||
if (alt181) return this.ALTERNATIVE_181;
|
||||
@ -205,12 +222,17 @@ Vue.component("time-studies-tab", {
|
||||
data() {
|
||||
return {
|
||||
respec: player.respec,
|
||||
layoutType: StudyTreeLayoutType.NORMAL,
|
||||
layoutType: STUDY_TREE_LAYOUT_TYPE.NORMAL,
|
||||
vLevel: 0
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
respec(newValue) {
|
||||
player.respec = newValue;
|
||||
},
|
||||
vLevel() {
|
||||
// When vLevel changes, we recompute the study tree because of triad studies
|
||||
this.$recompute("layout");
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -225,7 +247,7 @@ Vue.component("time-studies-tab", {
|
||||
},
|
||||
respecClassObject() {
|
||||
return {
|
||||
"o-primary-btn--time-study-options": true,
|
||||
"o-primary-btn--subtab-option": true,
|
||||
"o-primary-btn--respec-active": this.respec
|
||||
};
|
||||
}
|
||||
@ -233,22 +255,24 @@ Vue.component("time-studies-tab", {
|
||||
methods: {
|
||||
update() {
|
||||
this.respec = player.respec;
|
||||
this.layoutType = StudyTreeLayoutType.current;
|
||||
this.layoutType = STUDY_TREE_LAYOUT_TYPE.current;
|
||||
this.vLevel = Ra.pets.v.level;
|
||||
},
|
||||
studyComponent(study) {
|
||||
switch (study.type) {
|
||||
case TimeStudyType.NORMAL: return "normal-time-study";
|
||||
case TimeStudyType.ETERNITY_CHALLENGE: return "ec-time-study";
|
||||
case TimeStudyType.DILATION: return "dilation-time-study";
|
||||
case TimeStudyType.TRIAD: return "triad-time-study";
|
||||
}
|
||||
throw "Unknown study type";
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-time-studies-tab">
|
||||
<div class="l-time-study-options">
|
||||
<div class="c-subtab-option-container">
|
||||
<primary-button
|
||||
class="o-primary-btn--time-study-options"
|
||||
class="o-primary-btn--subtab-option"
|
||||
onclick="exportStudyTree()"
|
||||
>Export tree</primary-button>
|
||||
<primary-button
|
||||
@ -256,7 +280,7 @@ Vue.component("time-studies-tab", {
|
||||
@click="respec = !respec"
|
||||
>Respec time studies on next Eternity</primary-button>
|
||||
<primary-button
|
||||
class="o-primary-btn--time-study-options"
|
||||
class="o-primary-btn--subtab-option"
|
||||
onclick="Modal.importTree.show()"
|
||||
>Import tree</primary-button>
|
||||
</div>
|
||||
@ -277,6 +301,5 @@ Vue.component("time-studies-tab", {
|
||||
<secret-time-study-connection :setup="layout.secretStudyConnection" />
|
||||
</svg>
|
||||
</div>
|
||||
<tt-shop class="l-time-studies-tab__tt-shop" />
|
||||
</div>`
|
||||
});
|
||||
});
|
||||
|
@ -22,12 +22,12 @@ Vue.component("time-study-connection", {
|
||||
const to = connection.to;
|
||||
function pathClassOf(study) {
|
||||
switch (study.path) {
|
||||
case TimeStudyPath.NORMAL_DIM: return "o-time-study-connection--normal-dim";
|
||||
case TimeStudyPath.INFINITY_DIM: return "o-time-study-connection--infinity-dim";
|
||||
case TimeStudyPath.TIME_DIM: return "o-time-study-connection--time-dim";
|
||||
case TimeStudyPath.ACTIVE: return "o-time-study-connection--active";
|
||||
case TimeStudyPath.PASSIVE: return "o-time-study-connection--passive";
|
||||
case TimeStudyPath.IDLE: return "o-time-study-connection--idle";
|
||||
case TIME_STUDY_PATH.ANTIMATTER_DIM: return "o-time-study-connection--antimatter-dim";
|
||||
case TIME_STUDY_PATH.INFINITY_DIM: return "o-time-study-connection--infinity-dim";
|
||||
case TIME_STUDY_PATH.TIME_DIM: return "o-time-study-connection--time-dim";
|
||||
case TIME_STUDY_PATH.ACTIVE: return "o-time-study-connection--active";
|
||||
case TIME_STUDY_PATH.PASSIVE: return "o-time-study-connection--passive";
|
||||
case TIME_STUDY_PATH.IDLE: return "o-time-study-connection--idle";
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
@ -97,4 +97,4 @@ class TimeStudyConnectionSetup {
|
||||
get isBought() {
|
||||
return this.from.isBought && this.to.isBought;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ Vue.component("time-study", {
|
||||
data() {
|
||||
return {
|
||||
isBought: false,
|
||||
isAvailable: false
|
||||
isAvailableForPurchase: false,
|
||||
STCost: 0
|
||||
};
|
||||
},
|
||||
props: {
|
||||
@ -13,6 +14,10 @@ Vue.component("time-study", {
|
||||
showCost: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showSTCost: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -28,14 +33,52 @@ Vue.component("time-study", {
|
||||
classObject() {
|
||||
return {
|
||||
"o-time-study": true,
|
||||
"o-time-study--unavailable": !this.isAvailable && !this.isBought,
|
||||
"o-time-study--bought": this.isBought,
|
||||
"l-time-study": true,
|
||||
"o-time-study--small": this.setup.isSmall,
|
||||
"l-time-study": true
|
||||
"o-time-study--unavailable": !this.isAvailableForPurchase && !this.isBought,
|
||||
"o-time-study--available": this.isAvailableForPurchase && !this.isBought,
|
||||
"o-time-study--bought": this.isBought,
|
||||
};
|
||||
},
|
||||
pathClass() {
|
||||
switch (this.study.type) {
|
||||
case TimeStudyType.NORMAL:
|
||||
switch (this.setup.path) {
|
||||
case TIME_STUDY_PATH.ANTIMATTER_DIM: return "o-time-study-antimatter-dim";
|
||||
case TIME_STUDY_PATH.INFINITY_DIM: return "o-time-study-infinity-dim";
|
||||
case TIME_STUDY_PATH.TIME_DIM: return "o-time-study-time-dim";
|
||||
case TIME_STUDY_PATH.ACTIVE: return "o-time-study-active";
|
||||
case TIME_STUDY_PATH.PASSIVE: return "o-time-study-passive";
|
||||
case TIME_STUDY_PATH.IDLE: return "o-time-study-idle";
|
||||
case TIME_STUDY_PATH.LIGHT: return "o-time-study-light";
|
||||
case TIME_STUDY_PATH.DARK: return "o-time-study-dark";
|
||||
default: return "o-time-study-normal";
|
||||
}
|
||||
break;
|
||||
case TimeStudyType.ETERNITY_CHALLENGE:
|
||||
return "o-time-study-eternity-challenge";
|
||||
case TimeStudyType.DILATION:
|
||||
if (this.study.id === 6) return "o-time-study-reality"
|
||||
return "o-time-study-dilation";
|
||||
case TimeStudyType.TRIAD:
|
||||
return "o-time-study-triad";
|
||||
}
|
||||
},
|
||||
studyClass() {
|
||||
let pathClasses = ""
|
||||
if (!this.isAvailableForPurchase && !this.isBought){
|
||||
pathClasses += `${this.pathClass}--unavailable`;
|
||||
}
|
||||
if (this.isAvailableForPurchase && !this.isBought){
|
||||
pathClasses += `${this.pathClass}--available`;
|
||||
}
|
||||
if (this.isBought){
|
||||
pathClasses += `${this.pathClass}--bought`;
|
||||
}
|
||||
return pathClasses;
|
||||
},
|
||||
config() {
|
||||
return this.study.config;
|
||||
return {...this.study.config, formatCost: formatInt};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -43,28 +86,36 @@ Vue.component("time-study", {
|
||||
const study = this.study;
|
||||
this.isBought = study.isBought;
|
||||
if (!this.isBought) {
|
||||
this.isAvailable = study.canBeBought && study.isAffordable;
|
||||
this.isAvailableForPurchase = study.canBeBought && study.isAffordable;
|
||||
}
|
||||
|
||||
this.STCost = this.study.STCost;
|
||||
},
|
||||
handleClick() {
|
||||
this.study.purchase();
|
||||
},
|
||||
shiftClick() {
|
||||
if (this.study.purchaseUntil) this.study.purchaseUntil();
|
||||
},
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<button :class="classObject"
|
||||
`<button :class="[classObject, studyClass]"
|
||||
:style="styleObject"
|
||||
@click.exact="handleClick"
|
||||
@click.shift.exact="shiftClick">
|
||||
<slot />
|
||||
<cost-display br
|
||||
v-if="showCost"
|
||||
v-if="(showCost && !showSTCost) || STCost === 0"
|
||||
:config="config"
|
||||
singular="Time Theorem"
|
||||
plural="Time Theorems"
|
||||
/>
|
||||
<div v-else-if="showSTCost">
|
||||
Cost: {{ formatInt(STCost) }} {{ "Space Theorem" | pluralize(STCost, "Space Theorems")}}
|
||||
<span v-if="config.cost">
|
||||
and {{formatInt(config.cost)}} TT
|
||||
</span>
|
||||
</div>
|
||||
</button>`
|
||||
});
|
||||
|
||||
@ -86,4 +137,4 @@ class TimeStudySetup {
|
||||
get path() {
|
||||
return this.study.path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("triad-time-study", {
|
||||
props: {
|
||||
setup: Object
|
||||
},
|
||||
computed: {
|
||||
study() {
|
||||
return this.setup.study;
|
||||
},
|
||||
id() {
|
||||
return this.study.id;
|
||||
},
|
||||
config() {
|
||||
return this.study.config;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
template:
|
||||
`<time-study :setup="setup" class="o-time-study--triad" :showSTCost="true">
|
||||
<hint-text type="studies" class="l-hint-text--time-study">T{{id}}</hint-text>
|
||||
<description-display :config="study.config" />
|
||||
<effect-display br :config="study.config" />
|
||||
</time-study>`
|
||||
});
|
@ -41,11 +41,11 @@ Vue.component("ep-multiplier-button", {
|
||||
template:
|
||||
`<div class="l-spoon-btn-group">
|
||||
<button :class="classObject" @click="upgrade.purchase()">
|
||||
You gain 5 times more EP
|
||||
Multiply Eternity Points from all sources by {{ formatX(5) }}
|
||||
<br>
|
||||
Currently: {{shorten(multiplier, 2, 0)}}x
|
||||
Currently: {{formatX(multiplier, 2, 0)}}
|
||||
<br>
|
||||
Cost: {{shorten(cost, 2, 0)}} EP
|
||||
Cost: {{format(cost, 2, 0)}} EP
|
||||
</button>
|
||||
<primary-button
|
||||
class="l--spoon-btn-group__little-spoon o-primary-btn--small-spoon"
|
||||
@ -58,4 +58,4 @@ Vue.component("ep-multiplier-button", {
|
||||
class="l--spoon-btn-group__little-spoon o-primary-btn--small-spoon"
|
||||
/>
|
||||
</div>`
|
||||
});
|
||||
});
|
||||
|
@ -15,7 +15,8 @@ Vue.component("eternity-upgrades-tab", {
|
||||
EternityUpgrade.tdMultRealTime,
|
||||
]
|
||||
];
|
||||
}
|
||||
},
|
||||
costIncreases: () => EternityUpgrade.epMult.costIncreaseThresholds.map(x => new Decimal(x)),
|
||||
},
|
||||
template:
|
||||
`<div class="l-eternity-upgrades-grid">
|
||||
@ -28,5 +29,11 @@ Vue.component("eternity-upgrades-tab", {
|
||||
/>
|
||||
</div>
|
||||
<ep-multiplier-button />
|
||||
<div>
|
||||
The cost for the EP multiplier jumps at {{format(costIncreases[0])}} EP,
|
||||
{{format(costIncreases[1], 2, 2)}} EP, and {{format(costIncreases[2])}} EP.
|
||||
<br>
|
||||
It gets expensive more quickly past {{format(costIncreases[3])}} EP.
|
||||
</div>
|
||||
</div>`
|
||||
});
|
56
javascripts/components/failable-ec-text.js
Normal file
@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("failable-ec-text", {
|
||||
data() {
|
||||
return {
|
||||
currentResource: new Decimal(0),
|
||||
maximumResource: new Decimal(0),
|
||||
currentEternityChallengeId: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
textStyle() {
|
||||
if (this.maximumResource.eq(0)) return {};
|
||||
|
||||
const ratio = this.currentResource.div(this.maximumResource).toNumber();
|
||||
// Goes from green to yellow to red. If theme is light, use a slightly lighter yellow
|
||||
// by not allowing full red and gree at the same time.
|
||||
const darkTheme = Theme.current().isDark && Theme.current().name !== "S6";
|
||||
// Setting this constant to 2 will give green - yellow - red, setting it to 1
|
||||
// will give a straight line between green and red in colorspace, intermediate values
|
||||
// will give intermediate results.
|
||||
const c = darkTheme ? 2 : 1.5;
|
||||
const rgb = [
|
||||
Math.round(Math.min(c * ratio, 1) * 255),
|
||||
Math.round(Math.min(c * (1 - ratio), 1) * 255),
|
||||
0
|
||||
];
|
||||
|
||||
return { color: `rgb(${rgb.join(",")})` };
|
||||
},
|
||||
text() {
|
||||
if (this.currentEternityChallengeId === 4) {
|
||||
return `${formatInt(this.currentResource)} / ${formatInt(this.maximumResource)} Infinities used`;
|
||||
}
|
||||
// We're always either in EC4 or EC12 when displaying this text.
|
||||
return `${TimeSpan.fromSeconds(this.currentResource.toNumber()).toString()} /
|
||||
${TimeSpan.fromSeconds(this.maximumResource.toNumber()).toString()} time spent`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
if (EternityChallenge.current && [4, 12].includes(EternityChallenge.current.id)) {
|
||||
this.currentEternityChallengeId = EternityChallenge.current.id;
|
||||
if (this.currentEternityChallengeId === 4) {
|
||||
this.currentResource.copyFrom(player.infinitied);
|
||||
} else {
|
||||
this.currentResource = new Decimal(Time.thisEternity.totalSeconds);
|
||||
}
|
||||
this.maximumResource = new Decimal(EternityChallenge.current.config.restriction(
|
||||
EternityChallenge.current.completions));
|
||||
}
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<span> - <span :style="textStyle">{{text}}</span></span>`
|
||||
});
|
@ -21,16 +21,19 @@ Vue.component("game-ui", {
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div v-if="view.initialized" id="ui" class="c-game-ui">
|
||||
<component :is="uiLayout">
|
||||
<component :is="page" />
|
||||
</component>
|
||||
<modal-popup v-if="view.modal.current" />
|
||||
<modal-glyph-selection v-if="view.modal.glyphSelection" />
|
||||
<modal-progress-bar v-if="view.modal.progressBar" />
|
||||
<link v-if="view.theme !== 'Normal'" type="text/css" rel="stylesheet" :href="themeCss">
|
||||
<div id="ui-container" style="display: flex; justify-content: center;">
|
||||
<div v-if="view.initialized" id="ui" class="c-game-ui">
|
||||
<component :is="uiLayout">
|
||||
<component :is="page" />
|
||||
</component>
|
||||
<modal-popup v-if="view.modal.current" :modal="view.modal.current"/>
|
||||
<modal-glyph-selection v-if="view.modal.glyphSelection" />
|
||||
<modal-progress-bar v-if="view.modal.progressBar" />
|
||||
<link v-if="view.theme !== 'Normal'" type="text/css" rel="stylesheet" :href="themeCss">
|
||||
<help-me />
|
||||
</div>
|
||||
<div id="notification-container" class="l-notification-container" />
|
||||
<help-me />
|
||||
<tt-shop v-if="view.subtab === 'studies'" class="l-time-studies-tab__tt-shop" />
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
@ -8,21 +8,36 @@ Vue.component("autobuyer-box", {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
interval: 0
|
||||
interval: 0,
|
||||
hasMaxedInterval: false,
|
||||
bulk: 0,
|
||||
bulkUnlocked: false,
|
||||
bulkUnlimited: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
intervalDisplay() {
|
||||
return TimeSpan.fromMilliseconds(this.interval).totalSeconds.toFixed(2);
|
||||
return format(TimeSpan.fromMilliseconds(this.interval).totalSeconds, 2, 2);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.interval = this.autobuyer.interval;
|
||||
this.hasMaxedInterval = this.autobuyer.hasMaxedInterval;
|
||||
this.bulk = this.autobuyer.bulk;
|
||||
// If it's undefined, the autobuyer isn't the dimboost autobuyer
|
||||
// and we don't have to worry about bulk being unlocked.
|
||||
this.bulkUnlocked = this.autobuyer.isBulkBuyUnlocked !== false;
|
||||
this.bulkUnlimited = this.autobuyer.hasUnlimitedBulk;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="c-autobuyer-box__small-text">Current interval: {{intervalDisplay}} seconds</div>`
|
||||
`<div class="c-autobuyer-box__small-text">
|
||||
Current interval: {{intervalDisplay}} seconds
|
||||
<span v-if="hasMaxedInterval && bulkUnlocked && bulk">
|
||||
<br>Current bulk: {{bulkUnlimited ? "Unlimited" : formatX(bulk, 2)}}
|
||||
</span>
|
||||
</div>`
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@ -37,7 +52,11 @@ Vue.component("autobuyer-box", {
|
||||
return {
|
||||
isUnlocked: false,
|
||||
isActive: false,
|
||||
globalToggle: false
|
||||
globalToggle: false,
|
||||
canBeBought: false,
|
||||
antimatterCost: new Decimal(0),
|
||||
isBought: false,
|
||||
antimatter: new Decimal(0)
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -51,27 +70,63 @@ Vue.component("autobuyer-box", {
|
||||
this.isUnlocked = autobuyer.isUnlocked;
|
||||
this.isActive = autobuyer.isActive;
|
||||
this.globalToggle = player.options.autobuyersOn;
|
||||
this.canBeBought = this.autobuyer.canBeBought;
|
||||
this.antimatterCost = this.autobuyer.antimatterCost;
|
||||
this.isBought = this.autobuyer.isBought;
|
||||
this.antimatter.copyFrom(Currency.antimatter);
|
||||
},
|
||||
toggle() {
|
||||
if (!this.globalToggle) return;
|
||||
this.isActive = !this.isActive;
|
||||
},
|
||||
purchase() {
|
||||
this.autobuyer.purchase();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
canBuy() {
|
||||
return this.antimatter.gte(this.antimatterCost);
|
||||
},
|
||||
autobuyerBuyBoxClass() {
|
||||
return {
|
||||
"c-autobuyer-buy-box--purchaseable": this.canBuy
|
||||
};
|
||||
},
|
||||
autobuyerToggleClass() {
|
||||
return this.isActive ? "fas fa-check" : "fas fa-times";
|
||||
},
|
||||
autobuyerStateClass() {
|
||||
return {
|
||||
"o-autobuyer-toggle-checkbox__label": true,
|
||||
"o-autobuyer-toggle-checkbox__label--active": this.isActive,
|
||||
"o-autobuyer-toggle-checkbox__label--disabled": !this.globalToggle
|
||||
};
|
||||
},
|
||||
},
|
||||
template:
|
||||
`<div v-if="isUnlocked" class="c-autobuyer-box l-autobuyer-box">
|
||||
<div class="l-autobuyer-box__header">{{name}}</div>
|
||||
<slot name="beforeInterval" />
|
||||
<interval-label v-if="showInterval" :autobuyer="autobuyer"/>
|
||||
<div class="l-autobuyer-box__content">
|
||||
<slot />
|
||||
`<div v-if="isUnlocked || isBought" class="c-autobuyer-box-row">
|
||||
<div class="l-autobuyer-box__header">
|
||||
{{name}}
|
||||
<interval-label v-if="showInterval" :autobuyer="autobuyer"/>
|
||||
</div>
|
||||
<div class="o-autobuyer-toggle-checkbox l-autobuyer-box__footer" @click="toggle">
|
||||
<span class="o-autobuyer-toggle-checkbox__label">Is active:</span>
|
||||
<div class="c-autobuyer-box-row__intervalSlot"><slot name="intervalSlot" /></div>
|
||||
<div class="c-autobuyer-box-row__toggleSlot"><slot name="toggleSlot" /></div>
|
||||
<div class="c-autobuyer-box-row__prioritySlot"><slot name="prioritySlot" /></div>
|
||||
<div class="c-autobuyer-box-row__optionSlot"><slot name="optionSlot" /></div>
|
||||
<div class="l-autobuyer-box__footer" @click="toggle">
|
||||
<label
|
||||
:for="name"
|
||||
:class="autobuyerStateClass">
|
||||
<span :class="autobuyerToggleClass"></span>
|
||||
</label>
|
||||
<input
|
||||
:checked="isActive && globalToggle"
|
||||
:disabled="!globalToggle"
|
||||
:name="name"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="canBeBought" @click="purchase" class="c-autobuyer-buy-box" :class="autobuyerBuyBoxClass">
|
||||
Buy the {{ name }} for {{ format(antimatterCost) }} antimatter
|
||||
</div>`
|
||||
});
|
||||
|
@ -93,7 +93,14 @@ const AutobuyerInputFunctions = {
|
||||
copyValue: value => new Decimal(value),
|
||||
tryParse: input => {
|
||||
try {
|
||||
const decimal = Decimal.fromString(input.replace(",", ""));
|
||||
let decimal;
|
||||
if (/^e\d*[.]?\d+$/u.test(input.replace(",", ""))) {
|
||||
// Logarithm Notation
|
||||
decimal = Decimal.pow10(parseFloat(input.replace(",", "").slice(1)));
|
||||
} else {
|
||||
// Scientific notation
|
||||
decimal = Decimal.fromString(input.replace(",", ""));
|
||||
}
|
||||
return isNaN(decimal.mantissa) || isNaN(decimal.exponent) ? undefined : decimal;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
|
@ -7,13 +7,15 @@ Vue.component("autobuyer-interval-button", {
|
||||
data() {
|
||||
return {
|
||||
cost: 0,
|
||||
isMaxed: false
|
||||
isMaxed: false,
|
||||
isUnlocked: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.cost = this.autobuyer.cost;
|
||||
this.isMaxed = this.autobuyer.hasMaxedInterval;
|
||||
this.isUnlocked = this.autobuyer.isUnlocked;
|
||||
},
|
||||
upgradeInterval() {
|
||||
this.autobuyer.upgradeInterval();
|
||||
@ -21,8 +23,13 @@ Vue.component("autobuyer-interval-button", {
|
||||
},
|
||||
template:
|
||||
`<button
|
||||
v-if="!isMaxed"
|
||||
v-if="!isMaxed && isUnlocked"
|
||||
class="o-autobuyer-btn l-autobuyer-box__button"
|
||||
@click="upgradeInterval"
|
||||
>40% smaller interval<br>Cost: {{shortenDimensions(cost)}} IP</button>`
|
||||
});
|
||||
>{{formatPercents(0.4)}} smaller interval<br>Cost: {{format(cost, 2, 0)}} IP</button>
|
||||
<button
|
||||
v-else-if="!isMaxed"
|
||||
class="o-autobuyer-btn l-autobuyer-box__button">
|
||||
Complete the challenge to upgrade interval
|
||||
</button>`
|
||||
});
|
||||
|
@ -21,7 +21,7 @@ Vue.component("autobuyer-priority-selector", {
|
||||
},
|
||||
template:
|
||||
`<div>
|
||||
<span>Priority:</span>
|
||||
<div>Priority:</div>
|
||||
<select @change="handleChange">
|
||||
<option v-for="i in 9" :value="i" :selected="i === value">{{i}}</option>
|
||||
</select>
|
||||
|
@ -5,8 +5,8 @@ Vue.component("autobuyer-toggles", {
|
||||
return {
|
||||
autobuyersOn: false,
|
||||
bulkOn: false,
|
||||
isAutoRealityUnlocked: false,
|
||||
autoRealityMode: AutoRealityMode.RM,
|
||||
showContinuum: false,
|
||||
disableContinuum: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -15,45 +15,56 @@ Vue.component("autobuyer-toggles", {
|
||||
},
|
||||
bulkOn(newValue) {
|
||||
player.options.bulkOn = newValue;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
autoRealityModeDisplay() {
|
||||
switch (this.autoRealityMode) {
|
||||
case AutoRealityMode.RM: return "reality machines";
|
||||
case AutoRealityMode.GLYPH: return "glyph level";
|
||||
case AutoRealityMode.EITHER: return "either";
|
||||
case AutoRealityMode.BOTH: return "both";
|
||||
}
|
||||
throw new Error("Unknown auto reality mode");
|
||||
},
|
||||
disableContinuum(newValue) {
|
||||
player.options.disableContinuum = newValue;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.autobuyersOn = player.options.autobuyersOn;
|
||||
this.bulkOn = player.options.bulkOn;
|
||||
this.isAutoRealityUnlocked = Autobuyer.reality.isUnlocked;
|
||||
this.autoRealityMode = Autobuyer.reality.mode;
|
||||
this.showContinuum = Ra.has(RA_UNLOCKS.RA_LAITELA_UNLOCK);
|
||||
this.disableContinuum = player.options.disableContinuum;
|
||||
},
|
||||
toggleAllAutobuyers() {
|
||||
const allAutobuyersDisabled = Autobuyers.unlocked.every(autobuyer => !autobuyer.isActive);
|
||||
if (allAutobuyersDisabled) {
|
||||
for (const autobuyer of Autobuyers.unlocked) {
|
||||
autobuyer.isActive = true;
|
||||
}
|
||||
} else {
|
||||
for (const autobuyer of Autobuyers.unlocked) {
|
||||
autobuyer.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-autobuyer-toggles">
|
||||
`<div class="c-subtab-option-container">
|
||||
<primary-button-on-off-custom
|
||||
v-model="autobuyersOn"
|
||||
on="Disable autobuyers"
|
||||
off="Enable autobuyers"
|
||||
class="o-primary-btn--autobuyer-toggle"
|
||||
class="o-primary-btn--subtab-option"
|
||||
/>
|
||||
<primary-button
|
||||
class="o-primary-btn--subtab-option"
|
||||
@click="toggleAllAutobuyers()">
|
||||
Toggle all autobuyers
|
||||
</primary-button>
|
||||
<primary-button-on-off-custom
|
||||
v-model="bulkOn"
|
||||
on="Disable bulk buy"
|
||||
off="Enable bulk buy"
|
||||
class="o-primary-btn--autobuyer-toggle"
|
||||
class="o-primary-btn--subtab-option"
|
||||
/>
|
||||
<primary-button-on-off-custom
|
||||
v-if="showContinuum"
|
||||
v-model="disableContinuum"
|
||||
on="Enable Continuum"
|
||||
off="Disable Continuum"
|
||||
class="o-primary-btn--subtab-option"
|
||||
/>
|
||||
<primary-button
|
||||
v-if="isAutoRealityUnlocked"
|
||||
class="o-primary-btn--autobuyer-toggle"
|
||||
onclick="Autobuyer.reality.toggleMode();"
|
||||
>Auto reality mode: {{autoRealityModeDisplay}}</primary-button>
|
||||
</div>`
|
||||
});
|
||||
|
@ -1,32 +1,29 @@
|
||||
"use strict";
|
||||
|
||||
Vue.component("autobuyers-tab", {
|
||||
data: () => ({
|
||||
hasContinuum: false
|
||||
}),
|
||||
methods: {
|
||||
update() {
|
||||
this.hasContinuum = Laitela.continuumActive;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<div class="l-autobuyers-tab">
|
||||
<autobuyer-toggles class="l-autobuyers-tab__toggles" />
|
||||
<div class="l-autobuyer-grid">
|
||||
<div class="l-autobuyer-grid__row">
|
||||
<reality-autobuyer-box />
|
||||
<eternity-autobuyer-box />
|
||||
</div>
|
||||
<div class="l-autobuyer-grid__row">
|
||||
<dimboost-autobuyer-box />
|
||||
<galaxy-autobuyer-box />
|
||||
<big-crunch-autobuyer-box />
|
||||
</div>
|
||||
<div class="l-autobuyer-grid__row">
|
||||
<dimension-autobuyer-box v-for="column in 3" :key="column" :tier="column"/>
|
||||
</div>
|
||||
<div class="l-autobuyer-grid__row">
|
||||
<dimension-autobuyer-box v-for="column in 3" :key="column + 3" :tier="column + 3"/>
|
||||
</div>
|
||||
<div class="l-autobuyer-grid__row">
|
||||
<dimension-autobuyer-box v-for="column in 2" :key="column + 6" :tier="column + 6"/>
|
||||
<tickspeed-autobuyer-box />
|
||||
</div>
|
||||
<div class="l-autobuyer-grid__row">
|
||||
<sacrifice-autobuyer-box />
|
||||
</div>
|
||||
</div>
|
||||
<autobuyer-toggles />
|
||||
<reality-autobuyer-box />
|
||||
<eternity-autobuyer-box />
|
||||
<big-crunch-autobuyer-box />
|
||||
<galaxy-autobuyer-box />
|
||||
<dimboost-autobuyer-box />
|
||||
<dimension-autobuyer-box v-if="!hasContinuum" v-for="tier in 8" :key="tier" :tier="tier"/>
|
||||
<tickspeed-autobuyer-box v-if="!hasContinuum" />
|
||||
<sacrifice-autobuyer-box />
|
||||
<template v-if="hasContinuum">
|
||||
Continuum makes Antimatter Dimension and tickspeed autobuyers obsolete, as you now automatically have a
|
||||
<br>
|
||||
certain amount of simulated Antimatter Dimension and tickspeed purchases based on your antimatter.
|
||||
</template>
|
||||
</div>`
|
||||
});
|
||||
|
@ -4,16 +4,16 @@ Vue.component("big-crunch-autobuyer-box", {
|
||||
data() {
|
||||
return {
|
||||
postBreak: false,
|
||||
mode: AutoCrunchMode.AMOUNT,
|
||||
mode: AUTO_CRUNCH_MODE.AMOUNT,
|
||||
hasAdditionalModes: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
autobuyer: () => Autobuyer.bigCrunch,
|
||||
modes: () => [
|
||||
AutoCrunchMode.AMOUNT,
|
||||
AutoCrunchMode.TIME,
|
||||
AutoCrunchMode.X_LAST
|
||||
AUTO_CRUNCH_MODE.AMOUNT,
|
||||
AUTO_CRUNCH_MODE.TIME,
|
||||
AUTO_CRUNCH_MODE.X_LAST
|
||||
]
|
||||
},
|
||||
methods: {
|
||||
@ -24,21 +24,21 @@ Vue.component("big-crunch-autobuyer-box", {
|
||||
},
|
||||
modeProps(mode) {
|
||||
switch (mode) {
|
||||
case AutoCrunchMode.AMOUNT: return {
|
||||
case AUTO_CRUNCH_MODE.AMOUNT: return {
|
||||
title: "Big Crunch at X IP",
|
||||
input: {
|
||||
property: "amount",
|
||||
type: "decimal"
|
||||
},
|
||||
};
|
||||
case AutoCrunchMode.TIME: return {
|
||||
case AUTO_CRUNCH_MODE.TIME: return {
|
||||
title: "Seconds between Crunches",
|
||||
input: {
|
||||
property: "time",
|
||||
type: "float"
|
||||
},
|
||||
};
|
||||
case AutoCrunchMode.X_LAST: return {
|
||||
case AUTO_CRUNCH_MODE.X_LAST: return {
|
||||
title: "X times last Crunch",
|
||||
input: {
|
||||
property: "xLast",
|
||||
@ -56,25 +56,29 @@ Vue.component("big-crunch-autobuyer-box", {
|
||||
},
|
||||
template:
|
||||
`<autobuyer-box :autobuyer="autobuyer" :showInterval="!postBreak" name="Automatic Big Crunch">
|
||||
<autobuyer-interval-button slot="beforeInterval" :autobuyer="autobuyer" />
|
||||
<div v-if="postBreak">
|
||||
<select
|
||||
v-if="hasAdditionalModes"
|
||||
class="c-autobuyer-box__mode-select l-autobuyer-box__mode-select"
|
||||
@change="changeMode"
|
||||
>
|
||||
<option
|
||||
v-for="optionMode in modes"
|
||||
:value="optionMode"
|
||||
:selected="mode === optionMode"
|
||||
>{{modeProps(optionMode).title}}</option>
|
||||
</select>
|
||||
<span v-else>{{modeProps(mode).title}}:</span>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
:key="mode"
|
||||
v-bind="modeProps(mode).input"
|
||||
/>
|
||||
</div>
|
||||
<autobuyer-interval-button slot="intervalSlot" :autobuyer="autobuyer" />
|
||||
<template v-if="postBreak">
|
||||
<template slot="intervalSlot">
|
||||
<select
|
||||
v-if="hasAdditionalModes"
|
||||
class="c-autobuyer-box__mode-select"
|
||||
@change="changeMode"
|
||||
>
|
||||
<option
|
||||
v-for="optionMode in modes"
|
||||
:value="optionMode"
|
||||
:selected="mode === optionMode"
|
||||
>{{modeProps(optionMode).title}}</option>
|
||||
</select>
|
||||
<span v-else>{{modeProps(mode).title}}:</span>
|
||||
</template>
|
||||
<template slot="toggleSlot">
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
:key="mode"
|
||||
v-bind="modeProps(mode).input"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</autobuyer-box>`
|
||||
});
|
||||
|
@ -3,56 +3,67 @@
|
||||
Vue.component("dimboost-autobuyer-box", {
|
||||
data() {
|
||||
return {
|
||||
limitDimBoosts: false,
|
||||
isBulkBuyUnlocked: false,
|
||||
isBuyMaxUnlocked: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
limitDimBoosts(newValue) {
|
||||
this.autobuyer.limitDimBoosts = newValue;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
autobuyer: () => Autobuyer.dimboost
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const autobuyer = this.autobuyer;
|
||||
this.isBulkBuyUnlocked = autobuyer.isBulkBuyUnlocked;
|
||||
this.isBuyMaxUnlocked = autobuyer.isBuyMaxUnlocked;
|
||||
this.isBulkBuyUnlocked = this.autobuyer.isBulkBuyUnlocked;
|
||||
this.isBuyMaxUnlocked = this.autobuyer.isBuyMaxUnlocked;
|
||||
this.limitDimBoosts = this.autobuyer.limitDimBoosts;
|
||||
}
|
||||
},
|
||||
template:
|
||||
`<autobuyer-box :autobuyer="autobuyer" :showInterval="!isBuyMaxUnlocked" name="Automatic DimBoosts">
|
||||
<div v-if="isBuyMaxUnlocked">
|
||||
<span>Buy max every X seconds:</span>
|
||||
<autobuyer-interval-button slot="intervalSlot" :autobuyer="autobuyer" />
|
||||
<template :slot=" isBuyMaxUnlocked ? 'toggleSlot' : 'intervalSlot' " style="margin-top: 1.2rem;">
|
||||
<div class="o-autobuyer-toggle-checkbox c-autobuyer-box__small-text" @click="limitDimBoosts = !limitDimBoosts"
|
||||
style="margin-top: 1.2rem;">
|
||||
<input type="checkbox" :checked="limitDimBoosts"/>
|
||||
<span>Limit dimboosts to:</span>
|
||||
</div>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="float"
|
||||
property="buyMaxInterval"
|
||||
:autobuyer="autobuyer"
|
||||
type="int"
|
||||
property="maxDimBoosts"
|
||||
/>
|
||||
</div>
|
||||
<template v-else>
|
||||
<autobuyer-interval-button slot="beforeInterval" :autobuyer="autobuyer" />
|
||||
<div>
|
||||
<span class="c-autobuyer-box__small-text">Limit DimBoosts to:</span>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="int"
|
||||
property="maxDimBoosts"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="c-autobuyer-box__small-text">Galaxies required to always DimBoost:</span>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="int"
|
||||
property="galaxies"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isBulkBuyUnlocked">
|
||||
<span class="c-autobuyer-box__small-text">Bulk DimBoost Amount:</span>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="int"
|
||||
property="bulk"
|
||||
/>
|
||||
</template>
|
||||
<template :slot=" isBuyMaxUnlocked ? 'prioritySlot' : 'toggleSlot' ">
|
||||
<div class="c-autobuyer-box__small-text" style="height: 3rem;">
|
||||
Galaxies required to always DimBoost,
|
||||
ignoring the limit:
|
||||
</div>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="int"
|
||||
property="galaxies"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="isBuyMaxUnlocked" slot="intervalSlot">
|
||||
<div class="c-autobuyer-box__small-text" style="margin-top: 1.2rem;">Activates every X seconds:</div>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="float"
|
||||
property="buyMaxInterval"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="isBulkBuyUnlocked" slot="prioritySlot">
|
||||
<div class="c-autobuyer-box__small-text" style="margin-top: 1.2rem;">Bulk DimBoost Amount:</div>
|
||||
<autobuyer-input
|
||||
:autobuyer="autobuyer"
|
||||
type="int"
|
||||
property="bulk"
|
||||
/>
|
||||
</template>
|
||||
</autobuyer-box>`
|
||||
});
|
||||
|
@ -10,6 +10,8 @@ Vue.component("dimension-autobuyer-box", {
|
||||
return {
|
||||
hasMaxedInterval: false,
|
||||
hasMaxedBulk: false,
|
||||
isUnlocked: false,
|
||||
bulkUnlimited: false,
|
||||
bulk: 1,
|
||||
cost: 1
|
||||
};
|
||||
@ -20,14 +22,16 @@ Vue.component("dimension-autobuyer-box", {
|
||||
if (!this.hasMaxedBulk) {
|
||||
bulk = Math.min(bulk * 2, 1e100);
|
||||
}
|
||||
return `${shortenDimensions(bulk)}x bulk purchase`;
|
||||
return `${formatX(bulk, 2, 0)} bulk purchase`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
const autobuyer = this.autobuyer;
|
||||
this.hasMaxedInterval = autobuyer.hasMaxedInterval;
|
||||
this.isUnlocked = autobuyer.isUnlocked;
|
||||
this.hasMaxedBulk = autobuyer.hasMaxedBulk;
|
||||
this.bulkUnlimited = autobuyer.hasUnlimitedBulk;
|
||||
this.bulk = autobuyer.bulk;
|
||||
this.cost = autobuyer.cost;
|
||||
},
|
||||
@ -37,15 +41,20 @@ Vue.component("dimension-autobuyer-box", {
|
||||
},
|
||||
template:
|
||||
`<button
|
||||
v-if="hasMaxedInterval"
|
||||
v-if="hasMaxedInterval && !bulkUnlimited && isUnlocked"
|
||||
class="o-autobuyer-btn"
|
||||
@click="upgradeBulk"
|
||||
>
|
||||
<span>{{bulkDisplay}}</span>
|
||||
<template v-if="!hasMaxedBulk">
|
||||
<br>
|
||||
<span>Cost: {{shortenDimensions(cost)}} IP</span>
|
||||
<span>Cost: {{format(cost, 2, 0)}} IP</span>
|
||||
</template>
|
||||
</button>
|
||||
<button
|
||||
v-else-if="hasMaxedInterval && !bulkUnlimited"
|
||||
class="o-autobuyer-btn l-autobuyer-box__button">
|
||||
Complete the challenge to upgrade bulk
|
||||
</button>`
|
||||
}
|
||||
},
|
||||
@ -54,7 +63,7 @@ Vue.component("dimension-autobuyer-box", {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mode: AutobuyerMode.BUY_SINGLE
|
||||
mode: AUTOBUYER_MODE.BUY_SINGLE
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -62,12 +71,12 @@ Vue.component("dimension-autobuyer-box", {
|
||||
return Autobuyer.dimension(this.tier);
|
||||
},
|
||||
name() {
|
||||
return `${DISPLAY_NAMES[this.tier]} Dimension Autobuyer`;
|
||||
return `${AntimatterDimension(this.tier).displayName} Dimension Autobuyer`;
|
||||
},
|
||||
modeDisplay() {
|
||||
switch (this.mode) {
|
||||
case AutobuyerMode.BUY_SINGLE: return "Buys singles";
|
||||
case AutobuyerMode.BUY_10: return "Buys max";
|
||||
case AUTOBUYER_MODE.BUY_SINGLE: return "Buys singles";
|
||||
case AUTOBUYER_MODE.BUY_10: return "Buys max";
|
||||
}
|
||||
throw "Unknown dimension autobuyer mode";
|
||||
}
|
||||
@ -83,12 +92,15 @@ Vue.component("dimension-autobuyer-box", {
|
||||
},
|
||||
template:
|
||||
`<autobuyer-box :autobuyer="autobuyer" :name="name" showInterval>
|
||||
<template slot="beforeInterval">
|
||||
<template slot="intervalSlot">
|
||||
<bulk-button :autobuyer="autobuyer" />
|
||||
<autobuyer-interval-button :autobuyer="autobuyer" />
|
||||
</template>
|
||||
<template slot="toggleSlot">
|
||||
<button class="o-autobuyer-btn" @click="toggleMode">{{modeDisplay}}</button>
|
||||
</template>
|
||||
<div class="l-autobuyer-box__fill" />
|
||||
<autobuyer-priority-selector :autobuyer="autobuyer" class="l-autobuyer-box__priority-selector" />
|
||||
<template slot="prioritySlot">
|
||||
<autobuyer-priority-selector :autobuyer="autobuyer" class="l-autobuyer-box__priority-selector" />
|
||||
</template>
|
||||
</autobuyer-box>`
|
||||
});
|
||||
|