function initializeUI() {
/*
Initializes the UI. Adds all html elements required for rendering.
*/
createAllRows(jobCategories, "jobTable")
createAllRows(skillCategories, "skillTable")
createAllRows(itemCategories, "itemTable")
createAllRows(milestoneCategories, "milestoneTable")
setLayout(peekSettingFromSave("layout"))
setFontSize(peekSettingFromSave("fontSize"))
setNotation(peekSettingFromSave("numberNotation"))
setCurrency(peekSettingFromSave("currencyNotation"))
setStickySidebar(peekSettingFromSave("stickySidebar"))
setTheme(peekSettingFromSave("theme"))
for (const key in gameData.requirements) {
const requirement = gameData.requirements[key]
requirement.queryElements()
}
}
function updateUI() {
/*
NOTE: To ensure that performance does not decrease,
please only call the render function when the user can actually see the content.
If they can always see the content put the function call at the top of this function.
NOTE2: Do NOT render anything to the screen outside of this function.
*/
// Always render the sidebar.
renderSideBar()
// Always render all the requirements.
renderRequirements()
const currentTab = gameData.settings.selectedTab
if (currentTab == Tab.JOBS || gameData.settings.layout == 0) {
renderRequirementsForCategoryType(gameData.taskData, jobCategories)
renderHeaderRows(jobCategories)
renderJobs()
}
if (currentTab == Tab.SKILLS || gameData.settings.layout == 0) {
updateRequiredRows(gameData.taskData, skillCategories)
renderHeaderRows(skillCategories)
renderSkills()
}
if (currentTab == Tab.SHOP || gameData.settings.layout == 0) {
updateRequiredRows(gameData.itemData, itemCategories)
renderShop()
}
if (currentTab == Tab.CHALLENGES)
renderChallenges()
if (currentTab == Tab.MILESTONES) {
updateRequiredRows(gameData.milestoneData, milestoneCategories)
renderMilestones()
}
if (currentTab == Tab.DARK_MATTER)
renderDarkMatter()
if (currentTab == Tab.SETTINGS)
renderSettings()
}
function renderSideBar() {
const task = gameData.currentJob
const quickTaskDisplayElement = document.getElementById("quickTaskDisplay")
const progressBar = quickTaskDisplayElement.getElementsByClassName("job")[0]
progressBar.getElementsByClassName("name")[0].textContent = (task.isHero ? "Great " : "") + task.name + " lvl " + formatLevel(task.level)
const progressFill = progressBar.getElementsByClassName("progressFill")[0]
if (task.isFinished) {
progressFill.style.width = "100%"
progressFill.classList.add("progress-fill-finished")
progressBar.classList.add("progress-bar-finished")
var time = gameData.realtime / 3
var x = time - Math.floor(time)
x = (x < 0.5 ? x : 1 - x) * 2;
progressFill.style.opacity = x
progressFill.classList.add("current-hero")
progressBar.classList.remove("progress-bar-hero")
} else {
progressFill.style.opacity = 1
progressFill.style.width = task.xp / task.getMaxXp() * 100 + "%"
progressFill.classList.remove("progress-fill-finished")
progressBar.classList.remove("progress-bar-finished")
task.isHero ? progressFill.classList.add("current-hero") : progressFill.classList.remove("current-hero")
task.isHero ? progressBar.classList.add("progress-bar-hero") : progressBar.classList.remove("progress-bar-hero")
}
document.getElementById("ageDisplay").textContent = formatAge(gameData.days)
document.getElementById("lifespanDisplay").textContent = formatWhole(daysToYears(getLifespan()))
document.getElementById("realtimeDisplay").textContent = formatTime(gameData.realtime)
document.getElementById("pauseButton").textContent = gameData.paused ? "Play" : "Pause"
formatCoins(gameData.coins, document.getElementById("coinDisplay"))
setSignDisplay()
formatCoins(getNet(), document.getElementById("netDisplay"))
formatCoins(getIncome(), document.getElementById("incomeDisplay"))
formatCoins(getExpense(), document.getElementById("expenseDisplay"))
document.getElementById("happinessDisplay").textContent = format(getHappiness())
document.getElementById("evilDisplay").textContent = format(gameData.evil)
document.getElementById("evilGainDisplay").textContent = format(getEvilGain())
document.getElementById("evilGainButtonDisplay").textContent = "+" + format(getEvilGain())
document.getElementById("essenceDisplay").textContent = format(gameData.essence)
document.getElementById("essenceGainDisplay").textContent = format(getEssenceGain())
document.getElementById("essenceGainButtonDisplay").textContent = "+" + format(getEssenceGain())
document.getElementById("darkMatterDisplay").textContent = format(gameData.dark_matter)
document.getElementById("darkMatterGainDisplay").textContent = format(getDarkMatterGain())
document.getElementById("darkMatterGainButtonDisplay").textContent = "+" + format(getDarkMatterGain())
document.getElementById("darkOrbsDisplay").textContent = format(gameData.dark_orbs)
document.getElementById("timeWarping").hidden = (getUnpausedGameSpeed() / baseGameSpeed) <= 1
document.getElementById("timeWarpingDisplay").textContent = "x" + format(getUnpausedGameSpeed() / baseGameSpeed, 2)
// Transcend for Next Milestone indicator
const button = document.getElementById("rebirthButton3").querySelector(".button")
button.style.background = isNextMilestoneInReach() ? "#065c21" : ""
// Hide the rebirthOneButton from the sidebar when you have `Almighty Eye` unlocked.
document.getElementById("rebirthButton1").hidden = gameData.requirements["Almighty Eye"].isCompleted()
// Challenges
document.getElementById("challengeName").textContent = getFormattedCurrentChallengeName()
if (gameData.active_challenge == "") {
document.getElementById("challengeTitle").hidden = true
document.getElementById("info").classList.remove("challenge")
} else {
document.getElementById("challengeTitle").hidden = false
document.getElementById("info").classList.add("challenge")
}
if (getDarkMatter() == 0)
gameData.requirements["Dark Matter info"].completed = false
}
function renderRequirementsForCategoryType(data, categoryType) {
const requiredRows = document.getElementsByClassName("requiredRow")
for (const requiredRow of requiredRows) {
let nextEntity = null
const category = categoryType[requiredRow.id]
if (category == null) {continue}
for (let i = 0; i < category.length; i++) {
const entityName = category[i]
if (i >= category.length - 1) break
const requirements = gameData.requirements[entityName]
if (requirements && i == 0) {
if (!requirements.isCompleted()) {
nextEntity = data[entityName]
break
}
}
const nextIndex = i + 1
if (nextIndex >= category.length) {break}
const nextEntityName = category[nextIndex]
nextEntityRequirements = gameData.requirements[nextEntityName]
if (!nextEntityRequirements.isCompleted()) {
nextEntity = data[nextEntityName]
break
}
}
if (nextEntity == null) {
requiredRow.classList.add("hiddenTask")
} else {
requiredRow.classList.remove("hiddenTask")
const requirementObject = gameData.requirements[nextEntity.name]
const requirements = requirementObject.requirements
const coinElement = requiredRow.querySelector(".coins")
const levelElement = requiredRow.querySelector(".levels")
const evilElement = requiredRow.querySelector(".evil")
const essenceElement = requiredRow.querySelector(".essence")
const darkMatterElement = requiredRow.querySelector(".darkMatter")
coinElement.classList.add("hiddenTask")
levelElement.classList.add("hiddenTask")
evilElement.classList.add("hiddenTask")
essenceElement.classList.add("hiddenTask")
darkMatterElement.classList.add("hiddenTask")
let finalText = ""
if (data == gameData.taskData) {
if (requirementObject instanceof EvilRequirement) {
evilElement.classList.remove("hiddenTask")
evilElement.textContent = format(requirements[0].requirement) + " evil"
} else if (requirementObject instanceof EssenceRequirement) {
essenceElement.classList.remove("hiddenTask")
essenceElement.textContent = format(requirements[0].requirement) + " essence"
} else if (requirementObject instanceof DarkMatterRequirement) {
darkMatterElement.classList.remove("hiddenTask")
darkMatterElement.textContent = format(requirements[0].requirement) + " Dark Matter"
} else if (requirementObject instanceof AgeRequirement) {
essenceElement.classList.remove("hiddenTask")
essenceElement.textContent = "Age " + format(requirements[0].requirement)
}
else {
levelElement.classList.remove("hiddenTask")
for (const requirement of requirements) {
const task = gameData.taskData[requirement.task]
if (task.level >= requirement.requirement) continue
finalText += " " + requirement.task + " " + formatLevel(task.level) + "/" + formatLevel(requirement.requirement) + ","
}
finalText = finalText.substring(0, finalText.length - 1)
levelElement.textContent = finalText
}
}
else if (data == gameData.itemData) {
coinElement.classList.remove("hiddenTask")
formatCoins(requirements[0].requirement, coinElement)
}
else if (data == gameData.milestoneData) {
essenceElement.classList.remove("hiddenTask")
essenceElement.textContent = format(requirements[0].requirement) + " essence"
}
}
}
}
function renderJobs() {
for (const key in gameData.taskData) {
let task = gameData.taskData[key]
if (!(task instanceof Job)) continue
const row = getTaskRowByName(task.name)
row.querySelector(".level").textContent = formatLevel(task.level)
row.querySelector(".xpGain").textContent = task.getXpGainFormatted()
row.querySelector(".xpLeft").textContent = task.getXpLeftFormatted()
let tooltip = tooltips[key]
if (!task.isHero && isHeroesUnlocked()) {
const requirementObject = gameData.requirements[key]
const requirements = requirementObject.requirements
const prev = getPreviousTaskInCategory(key)
tooltip += "
Required: "
let reqlist = ""
let prevReq = ""
if (prev != "") {
var prevTask = gameData.taskData[prev]
var prevlvl = (prevTask.isHero ? prevTask.level : 0)
if (prevlvl < 20)
prevReq = "Great " + prev + " " + prevlvl + "/20
"
}
if (requirementObject instanceof EvilRequirement) {
reqlist += format(requirements[0].requirement) + " evil
"
} else if (requirementObject instanceof EssenceRequirement) {
reqlist += format(requirements[0].requirement) + " essence
"
} else if (requirementObject instanceof AgeRequirement) {
reqlist += "Age " + format(requirements[0].requirement) + "
"
} else if (requirementObject instanceof DarkMatterRequirement) {
reqlist += format(requirements[0].requirement) + " Dark Matter
"
} else {
for (const requirement of requirements) {
const task_check = gameData.taskData[requirement.task]
const reqvalue = (requirement.herequirement == null ? requirement.requirement : requirement.herequirement)
if (task_check.isHero && task_check.level >= reqvalue) continue
if (prev != "" && task_check.name == prevTask.name) {
if (reqvalue <= 20)
continue
else
prevReq = " Great " + requirement.task + " " + (task_check.isHero ? task_check.level : 0) + "/" + reqvalue + "
"
} else {
reqlist += " Great " + requirement.task + " " + (task_check.isHero ? task_check.level : 0) + "/" + reqvalue + "
"
}
}
}
reqlist += prevReq
reqlist = reqlist.substring(0, reqlist.length - 4)
tooltip += reqlist + ""
}
row.querySelector(".tooltipText").innerHTML = tooltip
const maxLevel = row.getElementsByClassName("maxLevel")[0]
maxLevel.textContent = formatLevel(task.maxLevel)
gameData.rebirthOneCount > 0 ? maxLevel.classList.remove("hidden") : maxLevel.classList.add("hidden")
const progressBar = row.querySelector(".progressBar")
progressBar.querySelector(".name").textContent = (task.isHero ? "Great " : "") + task.name
const progressFill = row.querySelector(".progressFill")
if (task.isFinished) {
progressFill.style.width = "100%"
progressFill.classList.add("progress-fill-finished")
progressBar.classList.add("progress-bar-finished")
const time = gameData.realtime / 3
let x = time - Math.floor(time)
x = (x < 0.5 ? x : 1 - x) * 2;
progressFill.style.opacity = x
} else {
progressFill.style.width = task.xp / task.getMaxXp() * 100 + "%"
progressFill.style.opacity = 1
progressFill.classList.remove("progress-fill-finished")
progressBar.classList.remove("progress-bar-finished")
task.isHero ? progressFill.classList.add("progress-fill-hero") : progressFill.classList.remove("progress-fill-hero")
task.isHero ? progressBar.classList.add("progress-bar-hero") : progressBar.classList.remove("progress-bar-hero")
}
task == gameData.currentJob ? progressFill.classList.add(task.isHero ? "current-hero" : "current") : progressFill.classList.remove("current", "current-hero")
const valueElement = row.querySelector(".value")
valueElement.querySelector(".income").style.display = task instanceof Job
valueElement.querySelector(".effect").style.display = task instanceof Skill
formatCoins(task.getIncome(), valueElement.querySelector(".income"))
}
}
function renderSkills() {
for (const key in gameData.taskData) {
let task = gameData.taskData[key]
if (!(task instanceof Skill)) continue
const row = getTaskRowByName(task.name)
row.querySelector(".level").textContent = formatLevel(task.level)
row.querySelector(".xpGain").textContent = task.getXpGainFormatted()
row.querySelector(".xpLeft").textContent = task.getXpLeftFormatted()
let tooltip = tooltips[key]
if (!task.isHero && isHeroesUnlocked()) {
const requirementObject = gameData.requirements[key]
const requirements = requirementObject.requirements
const prev = getPreviousTaskInCategory(key)
tooltip += "
Required: "
let reqlist = ""
let prevReq = ""
if (prev != "") {
var prevTask = gameData.taskData[prev]
var prevlvl = (prevTask.isHero ? prevTask.level : 0)
if (prevlvl < 20)
prevReq = "Great " + prev + " " + prevlvl + "/20
"
}
if (requirementObject instanceof EvilRequirement) {
reqlist += format(requirements[0].requirement) + " evil
"
} else if (requirementObject instanceof EssenceRequirement) {
reqlist += format(requirements[0].requirement) + " essence
"
} else if (requirementObject instanceof AgeRequirement) {
reqlist += "Age " + format(requirements[0].requirement) + "
"
} else if (requirementObject instanceof DarkMatterRequirement) {
reqlist += format(requirements[0].requirement) + " Dark Matter
"
} else {
for (const requirement of requirements) {
const task_check = gameData.taskData[requirement.task]
const reqvalue = (requirement.herequirement == null ? requirement.requirement : requirement.herequirement)
if (task_check.isHero && task_check.level >= reqvalue) continue
if (prev != "" && task_check.name == prevTask.name) {
if (reqvalue <= 20)
continue
else
prevReq = " Great " + requirement.task + " " + (task_check.isHero ? task_check.level : 0) + "/" + reqvalue + "
"
} else {
reqlist += " Great " + requirement.task + " " + (task_check.isHero ? task_check.level : 0) + "/" + reqvalue + "
"
}
}
}
reqlist += prevReq
reqlist = reqlist.substring(0, reqlist.length - 4)
tooltip += reqlist + ""
}
row.querySelector(".tooltipText").innerHTML = tooltip
const maxLevel = row.getElementsByClassName("maxLevel")[0]
maxLevel.textContent = formatLevel(task.maxLevel)
gameData.rebirthOneCount > 0 ? maxLevel.classList.remove("hidden") : maxLevel.classList.add("hidden")
const progressBar = row.querySelector(".progressBar")
progressBar.querySelector(".name").textContent = (task.isHero ? "Great " : "") + task.name
const progressFill = row.querySelector(".progressFill")
if (task.isFinished) {
progressFill.style.width = "100%"
progressFill.classList.add("progress-fill-finished")
progressBar.classList.add("progress-bar-finished")
const time = gameData.realtime / 3
let x = time - Math.floor(time)
x = (x < 0.5 ? x : 1 - x) * 2;
progressFill.style.opacity = x
}
else {
progressFill.style.width = task.xp / task.getMaxXp() * 100 + "%"
progressFill.style.opacity = 1
progressFill.classList.remove("progress-fill-finished")
progressBar.classList.remove("progress-bar-finished")
task.isHero ? progressFill.classList.add("progress-fill-hero") : progressFill.classList.remove("progress-fill-hero")
task.isHero ? progressBar.classList.add("progress-bar-hero") : progressBar.classList.remove("progress-bar-hero")
}
task == gameData.currentJob ? progressFill.classList.add(task.isHero ? "current-hero" : "current") : progressFill.classList.remove("current", "current-hero")
const valueElement = row.querySelector(".value")
valueElement.querySelector(".income").style.display = task instanceof Job
valueElement.querySelector(".effect").style.display = task instanceof Skill
valueElement.querySelector(".effect").textContent = task.getEffectDescription()
}
}
function renderShop() {
for (const key in gameData.itemData) {
const item = gameData.itemData[key]
const row = getTaskRowByName(item.name)
const button = row.querySelector(".button")
button.disabled = gameData.coins < item.getExpense()
const name = button.querySelector(".name")
if (isHeroesUnlocked())
name.classList.add("legendary")
else
name.classList.remove("legendary")
const active = row.querySelector(".active")
const color = autoBuyEnabled
? itemCategories["Properties"].includes(item.name) ? headerRowColors["Properties_Auto"] : headerRowColors["Misc_Auto"]
: itemCategories["Properties"].includes(item.name) ? headerRowColors["Properties"] : headerRowColors["Misc"]
active.style.backgroundColor = gameData.currentMisc.includes(item) || item == gameData.currentProperty ? color : "white"
row.querySelector(".effect").textContent = item.getEffectDescription()
formatCoins(item.getExpense(), row.querySelector(".expense"))
}
}
function renderChallenges() {
document.getElementById("activeChallengeName").textContent = getFormattedCurrentChallengeName()
if (gameData.active_challenge == "") {
document.getElementById("exitChallengeDiv").hidden = true
for (let i = 1; i <= Object.keys(gameData.challenges).length; i++) {
const element = document.getElementById("challengeButton" + i)
if (element != null)
element.classList.remove("hidden")
}
} else {
document.getElementById("exitChallengeDiv").hidden = false
for (let i = 1; i <= Object.keys(gameData.challenges).length; i++) {
const element = document.getElementById("challengeButton" + i)
if (element != null)
element.classList.add("hidden")
const elementReward = document.getElementById("currentChallengeReward" + i)
if (elementReward != null) {
if (elementReward.classList.contains(gameData.active_challenge)) {
elementReward.classList.remove("hidden")
if (getChallengeBonus(gameData.active_challenge, true) > getChallengeBonus(gameData.active_challenge))
elementReward.classList.add("reward")
else
elementReward.classList.remove("reward")
}
else
elementReward.classList.add("hidden")
}
}
}
document.getElementById("challengeGoal1").textContent = format(getChallengeGoal("an_unhappy_life"))
formatCoins(getChallengeGoal("rich_and_the_poor"), document.getElementById("challengeGoal2"))
document.getElementById("challengeGoal3").textContent = format(getChallengeGoal("time_does_not_fly"))
document.getElementById("challengeGoal4").textContent = format(getChallengeGoal("dance_with_the_devil"))
document.getElementById("challengeGoal5").textContent = formatLevel(Math.floor(getChallengeGoal("legends_never_die")))
document.getElementById("challengeReward1").hidden = gameData.challenges.an_unhappy_life == 0
document.getElementById("challengeReward2").hidden = gameData.challenges.rich_and_the_poor == 0
document.getElementById("challengeReward3").hidden = gameData.challenges.time_does_not_fly == 0
document.getElementById("challengeReward4").hidden = gameData.challenges.dance_with_the_devil == 0
document.getElementById("challengeReward5").hidden = gameData.challenges.legends_never_die == 0
document.getElementById("currentChallengeHappinessBuff").textContent = format(getChallengeBonus("an_unhappy_life", true), 2)
document.getElementById("currentChallengeIncomeBuff").textContent = format(getChallengeBonus("rich_and_the_poor", true), 2)
document.getElementById("currentChallengeTimewarpingBuff").textContent = format(getChallengeBonus("time_does_not_fly", true), 2)
document.getElementById("currentChallengeEssenceGainBuff").textContent = format(getChallengeBonus("dance_with_the_devil", true), 2)
document.getElementById("currentChallengeEvilGainBuff").textContent = format(getChallengeBonus("legends_never_die", true), 2)
document.getElementById("challengeHappinessBuff").textContent = format(getChallengeBonus("an_unhappy_life"), 2)
document.getElementById("challengeIncomeBuff").textContent = format(getChallengeBonus("rich_and_the_poor"), 2)
document.getElementById("challengeTimewarpingBuff").textContent = format(getChallengeBonus("time_does_not_fly"), 2)
document.getElementById("challengeEssenceGainBuff").textContent = format(getChallengeBonus("dance_with_the_devil"), 2)
document.getElementById("challengeEvilGainBuff").textContent = format(getChallengeBonus("legends_never_die"), 2)
}
function renderMilestones() {
for (const key in gameData.milestoneData) {
const milestone = gameData.milestoneData[key]
const row = getTaskRowByName(milestone.name)
row.querySelector(".essence").textContent = format(milestone.expense)
let desc = milestone.description
if (milestone.getEffect != null)
desc = "x" + format(milestone.getEffect(), 1) + " " + desc
if (milestone.baseData.effect != null)
desc = "x" + format(milestone.baseData.effect, 0) + " " + desc
row.querySelector(".description").textContent = desc
}
}
function renderDarkMatter() {
// Dark Matter Shop
document.getElementById("darkOrbGeneratorCost").textContent = format(getDarkOrbGeneratorCost())
document.getElementById("darkOrbGenerator").textContent = format(getDarkOrbGeneration())
document.getElementById("aDealWithTheChairmanCost").textContent = format(getADealWithTheChairmanCost())
document.getElementById("aDealWithTheChairmanEffect").textContent = format(getTaaAndMagicXpGain())
document.getElementById("aGiftFromGodEffect").textContent = format(getAGiftFromGodEssenceGain())
document.getElementById("aGiftFromGodCost").textContent = format(getAGiftFromGodCost())
document.getElementById("lifeCoachEffect").textContent = format(getLifeCoachIncomeGain())
document.getElementById("lifeCoachCost").textContent = format(getLifeCoachCost())
document.getElementById("gottaBeFastEffect").textContent = format(getGottaBeFastGain(), 2)
document.getElementById("gottaBeFastCost").textContent = format(getGottaBeFastCost())
if (gameData.dark_matter_shop.a_miracle)
document.getElementById("aMiracleBuyButton").classList.add("hidden")
if (getDarkOrbGeneration() != Infinity)
document.getElementById("darkOrbGeneratorBuyButton").classList.remove("hidden")
else
document.getElementById("darkOrbGeneratorBuyButton").classList.add("hidden")
// Dark Matter Skill tree
renderSkillTreeButton(document.getElementById("speedIsLife1"), gameData.dark_matter_shop.speed_is_life != 0, gameData.dark_matter_shop.speed_is_life == 1)
renderSkillTreeButton(document.getElementById("speedIsLife2"), gameData.dark_matter_shop.speed_is_life != 0, gameData.dark_matter_shop.speed_is_life == 2)
renderSkillTreeButton(document.getElementById("yourGreatestDebt1"), gameData.dark_matter_shop.your_greatest_debt != 0, gameData.dark_matter_shop.your_greatest_debt == 1)
renderSkillTreeButton(document.getElementById("yourGreatestDebt2"), gameData.dark_matter_shop.your_greatest_debt != 0, gameData.dark_matter_shop.your_greatest_debt == 2)
renderSkillTreeButton(document.getElementById("essenceCollector1"), gameData.dark_matter_shop.essence_collector != 0, gameData.dark_matter_shop.essence_collector == 1)
renderSkillTreeButton(document.getElementById("essenceCollector2"), gameData.dark_matter_shop.essence_collector != 0, gameData.dark_matter_shop.essence_collector == 2)
renderSkillTreeButton(document.getElementById("explosionOfTheUniverse1"), gameData.dark_matter_shop.explosion_of_the_universe != 0, gameData.dark_matter_shop.explosion_of_the_universe == 1)
renderSkillTreeButton(document.getElementById("explosionOfTheUniverse2"), gameData.dark_matter_shop.explosion_of_the_universe != 0, gameData.dark_matter_shop.explosion_of_the_universe == 2)
}
function renderSettings() {
// Stats
const date = new Date(gameData.stats.startDate)
document.getElementById("startDateDisplay").textContent = date.toLocaleDateString()
const currentDate = new Date()
document.getElementById("playedDaysDisplay").textContent = format((currentDate.getTime() - date.getTime()) / (1000 * 3600 * 24), 2)
document.getElementById("playedGameTimeDisplay").textContent = format(gameData.totalDays, 2)
if (gameData.rebirthOneCount > 0)
document.getElementById("statsRebirth1").classList.remove("hidden")
else
document.getElementById("statsRebirth1").classList.add("hidden")
if (gameData.rebirthTwoCount > 0)
document.getElementById("statsRebirth2").classList.remove("hidden")
else
document.getElementById("statsRebirth2").classList.add("hidden")
if (gameData.rebirthThreeCount > 0)
document.getElementById("statsRebirth3").classList.remove("hidden")
else
document.getElementById("statsRebirth3").classList.add("hidden")
if (gameData.rebirthFourCount > 0)
document.getElementById("statsRebirth4").classList.remove("hidden")
else
document.getElementById("statsRebirth4").classList.add("hidden")
document.getElementById("rebirthOneCountDisplay").textContent = gameData.rebirthOneCount
document.getElementById("rebirthTwoCountDisplay").textContent = gameData.rebirthTwoCount
document.getElementById("rebirthThreeCountDisplay").textContent = gameData.rebirthThreeCount
document.getElementById("rebirthFourCountDisplay").textContent = gameData.rebirthFourCount
document.getElementById("rebirthOneFastestDisplay").textContent = formatTime(gameData.stats.fastest1, true)
document.getElementById("rebirthTwoFastestDisplay").textContent = formatTime(gameData.stats.fastest2, true)
document.getElementById("rebirthThreeFastestDisplay").textContent = formatTime(gameData.stats.fastest3, true)
document.getElementById("rebirthFourFastestDisplay").textContent = formatTime(gameData.stats.fastest4, true)
// Gain Stats
document.getElementById("evilPerSecondDisplay").textContent = format(gameData.stats.EvilPerSecond, 3)
document.getElementById("maxEvilPerSecondDisplay").textContent = format(gameData.stats.maxEvilPerSecond, 3)
document.getElementById("maxEvilPerSecondRtDisplay").textContent = formatTime(gameData.stats.maxEvilPerSecondRt)
document.getElementById("essencePerSecondDisplay").textContent = format(gameData.stats.EssencePerSecond, 3)
document.getElementById("maxEssencePerSecondDisplay").textContent = format(gameData.stats.maxEssencePerSecond, 3)
document.getElementById("maxEssencePerSecondRtDisplay").textContent = formatTime(gameData.stats.maxEssencePerSecondRt)
// Challenge Stats
document.getElementById("challengeStat1").hidden = gameData.challenges.an_unhappy_life == 0
document.getElementById("challengeStat2").hidden = gameData.challenges.rich_and_the_poor == 0
document.getElementById("challengeStat3").hidden = gameData.challenges.time_does_not_fly == 0
document.getElementById("challengeStat4").hidden = gameData.challenges.dance_with_the_devil == 0
document.getElementById("challengeStat5").hidden = gameData.challenges.legends_never_die == 0
document.getElementById("challengeHappinessBuffDisplay").textContent = format(getChallengeBonus("an_unhappy_life"), 2)
document.getElementById("challengeIncomeBuffDisplay").textContent = format(getChallengeBonus("rich_and_the_poor"), 2)
document.getElementById("challengeTimewarpingBuffDisplay").textContent = format(getChallengeBonus("time_does_not_fly"), 2)
document.getElementById("challengeEssenceGainBuffDisplay").textContent = format(getChallengeBonus("dance_with_the_devil"), 2)
document.getElementById("challengeEvilGainBuffDisplay").textContent = format(getChallengeBonus("legends_never_die"), 2)
}
function renderRequirements() {
for (const key in gameData.requirements) {
const requirement = gameData.requirements[key]
for (const element of requirement.elements) {
if (requirement.isCompleted()) {
element.classList.remove("hidden")
} else {
element.classList.add("hidden")
}
}
}
}
function renderHeaderRows(categories) {
for (const categoryName in categories) {
const className = removeSpaces(categoryName)
const headerRow = document.getElementsByClassName(className)[0]
const maxLevelElement = headerRow.querySelector(".maxLevel")
gameData.rebirthOneCount > 0 ? maxLevelElement.classList.remove("hidden") : maxLevelElement.classList.add("hidden")
}
}
function createRequiredRow(categoryName) {
const requiredRow = document.querySelector(".requiredRowTemplate").content.firstElementChild.cloneNode(true)
requiredRow.classList.add("requiredRow")
requiredRow.classList.add(removeSpaces(categoryName))
requiredRow.id = categoryName
return requiredRow
}
function createHeaderRow(templates, categoryType, categoryName) {
const headerRow = templates.headerRow.content.firstElementChild.cloneNode(true)
const categoryElement = headerRow.getElementsByClassName("category")[0]
if (categoryType == itemCategories) {
categoryElement.getElementsByClassName("name")[0].textContent = categoryName
} else {
categoryElement.textContent = categoryName
}
if (categoryType == jobCategories || categoryType == skillCategories) {
headerRow.getElementsByClassName("valueType")[0].textContent = categoryType == jobCategories ? "Income/day" : "Effect"
}
headerRow.style.backgroundColor = headerRowColors[categoryName]
headerRow.style.color = (gameData.settings.theme == 2) ? headerRowTextColors[categoryName] : "#ffffff"
headerRow.classList.add(removeSpaces(categoryName))
headerRow.classList.add("headerRow")
return headerRow
}
function createRow(templates, name, categoryName, categoryType) {
const row = templates.row.content.firstElementChild.cloneNode(true)
row.getElementsByClassName("name")[0].textContent = name
row.getElementsByClassName("tooltipText")[0].textContent = tooltips[name]
row.id = "row" + removeSpaces(removeStrangeCharacters(name))
if (categoryType == itemCategories) {
row.getElementsByClassName("button")[0].onclick = categoryName == "Properties" ? () => { setCurrentProperty(name) } : () => { setMisc(name) }
}
return row
}
function createAllRows(categoryType, tableId) {
const templates = {
headerRow: document.getElementsByClassName(
categoryType == itemCategories
? "headerRowItemTemplate"
: (categoryType == milestoneCategories ? "headerRowMilestoneTemplate" : "headerRowTaskTemplate")
)[0],
row: document.getElementsByClassName(
categoryType == itemCategories
? "rowItemTemplate"
: (categoryType == milestoneCategories ? "rowMilestoneTemplate": "rowTaskTemplate"))[0],
}
const table = document.getElementById(tableId)
for (const categoryName in categoryType) {
const headerRow = createHeaderRow(templates, categoryType, categoryName)
table.appendChild(headerRow)
const category = categoryType[categoryName]
category.forEach(function(name) {
const row = createRow(templates, name, categoryName, categoryType)
table.appendChild(row)
})
const requiredRow = createRequiredRow(categoryName)
table.append(requiredRow)
}
}
function updateRequiredRows(data, categoryType) {
const requiredRows = document.getElementsByClassName("requiredRow")
for (const requiredRow of requiredRows) {
let nextEntity = null
const category = categoryType[requiredRow.id]
if (category == null) {continue}
for (let i = 0; i < category.length; i++) {
const entityName = category[i]
if (i >= category.length - 1) break
const requirements = gameData.requirements[entityName]
if (requirements && i == 0) {
if (!requirements.isCompleted()) {
nextEntity = data[entityName]
break
}
}
const nextIndex = i + 1
if (nextIndex >= category.length) {break}
const nextEntityName = category[nextIndex]
nextEntityRequirements = gameData.requirements[nextEntityName]
if (!nextEntityRequirements.isCompleted()) {
nextEntity = data[nextEntityName]
break
}
}
if (nextEntity == null) {
requiredRow.classList.add("hiddenTask")
} else {
requiredRow.classList.remove("hiddenTask")
const requirementObject = gameData.requirements[nextEntity.name]
const requirements = requirementObject.requirements
const coinElement = requiredRow.querySelector(".coins")
const levelElement = requiredRow.querySelector(".levels")
const evilElement = requiredRow.querySelector(".evil")
const essenceElement = requiredRow.querySelector(".essence")
const darkMatterElement = requiredRow.querySelector(".darkMatter")
coinElement.classList.add("hiddenTask")
levelElement.classList.add("hiddenTask")
evilElement.classList.add("hiddenTask")
essenceElement.classList.add("hiddenTask")
darkMatterElement.classList.add("hiddenTask")
let finalText = ""
if (data == gameData.taskData) {
if (requirementObject instanceof EvilRequirement) {
evilElement.classList.remove("hiddenTask")
evilElement.textContent = format(requirements[0].requirement) + " evil"
} else if (requirementObject instanceof EssenceRequirement) {
essenceElement.classList.remove("hiddenTask")
essenceElement.textContent = format(requirements[0].requirement) + " essence"
} else if (requirementObject instanceof DarkMatterRequirement) {
darkMatterElement.classList.remove("hiddenTask")
darkMatterElement.textContent = format(requirements[0].requirement) + " Dark Matter"
} else if (requirementObject instanceof AgeRequirement) {
essenceElement.classList.remove("hiddenTask")
essenceElement.textContent = "Age " + format(requirements[0].requirement)
}
else {
levelElement.classList.remove("hiddenTask")
for (const requirement of requirements) {
const task = gameData.taskData[requirement.task]
if (task.level >= requirement.requirement) continue
finalText += " " + requirement.task + " " + formatLevel(task.level) + "/" + formatLevel(requirement.requirement) + ","
}
finalText = finalText.substring(0, finalText.length - 1)
levelElement.textContent = finalText
}
}
else if (data == gameData.itemData) {
coinElement.classList.remove("hiddenTask")
formatCoins(requirements[0].requirement, coinElement)
}
else if (data == gameData.milestoneData) {
essenceElement.classList.remove("hiddenTask")
essenceElement.textContent = format(requirements[0].requirement) + " essence"
}
}
}
}
function setStickySidebar(sticky) {
gameData.settings.stickySidebar = sticky;
settingsStickySidebar.checked = sticky;
info.style.position = sticky ? 'sticky' : 'initial';
}
function selectElementInGroup(group, index) {
const elements = document.getElementsByClassName(group)
for (const el of elements) {
el.classList.remove("selected")
}
elements[index].classList.add("selected")
}
function setLayout(id) {
gameData.settings.layout = id
if (id == 0) {
document.getElementById("skillsTabButton").classList.add("hidden")
document.getElementById("shopTabButton").classList.add("hidden")
document.getElementById("dummyPage1").classList.remove("hidden")
document.getElementById("dummyPage2").classList.remove("hidden")
document.getElementById("skills").classList.add("hidden")
document.getElementById("shop").classList.add("hidden")
document.getElementById("tabcolumn").classList.add("plain-tab-column")
document.getElementById("tabcolumn").classList.remove("tabs-tab-column")
document.getElementById("maincolumn").classList.add("plain-main-column")
document.getElementById("maincolumn").classList.remove("tabs-main-column")
document.getElementById("jobs").appendChild(document.getElementById("skillPage"))
document.getElementById("jobs").appendChild(document.getElementById("itemPage"))
} else {
document.getElementById("skillsTabButton").classList.remove("hidden")
document.getElementById("shopTabButton").classList.remove("hidden")
document.getElementById("dummyPage1").classList.add("hidden")
document.getElementById("dummyPage2").classList.add("hidden")
document.getElementById("skills").classList.remove("hidden")
document.getElementById("shop").classList.remove("hidden")
document.getElementById("tabcolumn").classList.add("tabs-tab-column")
document.getElementById("tabcolumn").classList.remove("plain-tab-column")
document.getElementById("maincolumn").classList.add("tabs-main-column")
document.getElementById("maincolumn").classList.remove("plain-main-column")
document.getElementById("skills").appendChild(document.getElementById("skillPage"))
document.getElementById("shop").appendChild(document.getElementById("itemPage"))
}
selectElementInGroup("Layout", id == 0 ? 1 : 0)
}
function setFontSize(id) {
const fontSizes = {
0: "xx-small",
1: "x-small",
2: "small",
3: "medium",
4: "large",
5: "x-large",
6: "xx-large",
7: "xxx-large",
}
if (id < 0) id = 0
if (id > 7) id = 7
gameData.settings.fontSize = id
document.getElementById("body").style.fontSize = fontSizes[id]
}
function renderSkillTreeButton(element, categoryBought, elementBought) {
element.disabled = categoryBought
if (elementBought)
element.classList.add("w3-blue-gray")
else
element.classList.remove("w3-blue-gray")
}
function setSignDisplay() {
const signDisplay = document.getElementById("signDisplay")
if (getNet() > -1 && getNet() < 1) {
signDisplay.textContent = ""
signDisplay.style.color = "gray"
} else if (getIncome() > getExpense()) {
signDisplay.textContent = "+"
signDisplay.style.color = "green"
} else {
signDisplay.textContent = "-"
signDisplay.style.color = "red"
}
}
function getTaskQuerySelector(taskName) {
const task = gameData.taskData[taskName]
return "#row" + removeSpaces(removeStrangeCharacters(task.name))
}
function getItemQuerySelector(itemName) {
const item = gameData.itemData[itemName]
return "#row" + removeSpaces(removeStrangeCharacters(item.name))
}
function getMilestoneQuerySelector(milestoneName) {
const milestone = gameData.milestoneData[milestoneName]
return "#row" + removeSpaces(removeStrangeCharacters(milestone.name))
}
function getTaskRowByName(name) {
return document.getElementById("row" + removeSpaces(removeStrangeCharacters(name)))
}
const Tab = Object.freeze({
JOBS: "jobs",
SKILLS: "skills",
SHOP: "shop",
CHALLENGES: "challenges",
MILESTONES: "milestones",
REBIRTH: "rebirth",
DARK_MATTER: "darkMatter",
SETTINGS: "settings"
})
/**
* @param {Tab} selectedTab
*/
function setTab(selectedTab) {
const tabElement = document.getElementById(selectedTab)
if (tabElement == null) {
setTab(Tab.JOBS)
return
}
gameData.settings.selectedTab = selectedTab
// Update the UI when switching tabs to prevent flikering.
updateUI()
const element = document.getElementById(selectedTab + "TabButton")
const tabs = Array.prototype.slice.call(document.getElementsByClassName("tab"))
tabs.forEach(function(tab) {
tab.style.display = "none"
})
tabElement.style.display = "flex"
const tabButtons = document.getElementsByClassName("tabButton")
for (tabButton of tabButtons) {
tabButton.classList.remove("w3-blue-gray")
}
element.classList.add("w3-blue-gray")
}
function setTabSettings(tab) {
const element = document.getElementById(tab + "TabButton")
const tabs = Array.prototype.slice.call(document.getElementsByClassName("tabSettings"))
tabs.forEach(function (tab) {
tab.style.display = "none"
})
document.getElementById(tab).style.display = "flex"
const tabButtons = document.getElementsByClassName("tabButtonSettings")
for (const tabButton of tabButtons) {
tabButton.classList.remove("w3-blue-gray")
}
element.classList.add("w3-blue-gray")
}
function setTabDarkMatter(tab) {
const element = document.getElementById(tab + "TabButton")
const tabs = Array.prototype.slice.call(document.getElementsByClassName("tabDarkMatter"))
tabs.forEach(function (tab) {
tab.style.display = "none"
})
document.getElementById(tab).style.display = "flex"
const tabButtons = document.getElementsByClassName("tabButtonDarkMatter")
for (const tabButton of tabButtons) {
tabButton.classList.remove("w3-blue-gray")
}
element.classList.add("w3-blue-gray")
}
// Keyboard shortcuts + Loadouts ( courtesy of Pseiko )
function changeTab(direction){
const tabs = Array.prototype.slice.call(document.getElementsByClassName("tab"))
const tabButtons = Array.prototype.slice.call(document.getElementsByClassName("tabButton"))
let currentTab = 0
for (const i in tabs) {
if (!tabs[i].style.display.includes("none") && !tabs[i].classList.contains("hidden"))
currentTab = i*1
}
let targetTab = currentTab + direction
if (targetTab < 0) {
setTab(Tab.SETTINGS)
return
}
targetTab = Math.max(0,targetTab)
if (targetTab > tabs.length - 1) targetTab = 0
while (tabButtons[targetTab].style.display.includes("none") || tabButtons[targetTab].classList.contains("hidden")){
targetTab = targetTab + direction
targetTab = Math.max(0, targetTab)
if (targetTab > tabs.length-1) targetTab = 0
}
setTab(tabs[targetTab].id)
}
window.addEventListener('keydown', function(e) {
if (e.key == " " && !e.repeat ) {
togglePause()
if (e.target == document.body) {
e.preventDefault();
}
}
if (e.key=="ArrowRight") changeTab(1)
if (e.key=="ArrowLeft") changeTab(-1)
});