"
].join("\n");
let divStartCenter = [
- "
"
+ "
"
].join("\n");
let divEnd = [
- "
"
+ "
"
].join("\n");
let pSpan = "
";
@@ -63,45 +63,45 @@ let pSpan = "
";
/* let benchHKCCBegin, benchHKCCEnd; */
let benchmarkTimes = {
- LoadSaveFile: {
- name: "LoadSaveFile()",
- timeStart: 0,
- timeEnd: 0
- },
- CheckCompletion: {
- name: "HKCheckCompletion()",
- timeStart: 0,
- timeEnd: 0
- },
- GenerateInnerHTML: {
- name: "GenerateInnerHTML()",
- timeStart: 0,
- timeEnd: 0
- },
- HKReadTextArea: {
- name: "HKReadTextArea()",
- timeStart: 0,
- timeEnd: 0
- },
- Total: {
- name: "Total",
- timeStart: 0,
- timeEnd: 0
- }
+ LoadSaveFile: {
+ name: "LoadSaveFile()",
+ timeStart: 0,
+ timeEnd: 0
+ },
+ CheckCompletion: {
+ name: "HKCheckCompletion()",
+ timeStart: 0,
+ timeEnd: 0
+ },
+ GenerateInnerHTML: {
+ name: "GenerateInnerHTML()",
+ timeStart: 0,
+ timeEnd: 0
+ },
+ HKReadTextArea: {
+ name: "HKReadTextArea()",
+ timeStart: 0,
+ timeEnd: 0
+ },
+ Total: {
+ name: "Total",
+ timeStart: 0,
+ timeEnd: 0
+ }
};
/* -------------------------- Functions ----------------------------- */
function Benchmark(bench) {
- for (let time in bench) {
+ for (let time in bench) {
- if (bench[time].timeStart !== 0) {
- console.info(`${bench[time].name} time (ms) =`, bench[time].timeEnd - bench[time].timeStart);
- }
- bench[time].timeStart = 0;
- bench[time].timeEnd = 0;
+ if (bench[time].timeStart !== 0) {
+ console.info(`${bench[time].name} time (ms) =`, bench[time].timeEnd - bench[time].timeStart);
}
+ bench[time].timeStart = 0;
+ bench[time].timeEnd = 0;
+ }
}
/**
@@ -110,194 +110,194 @@ function Benchmark(bench) {
*/
function HKCheckCompletion(jsonObject, benchStart = new Date()) {
- // start benchmark
- // benchHKCCBegin = new Date();
- benchmarkTimes.CheckCompletion.timeStart = benchStart;
+ // start benchmark
+ // benchHKCCBegin = new Date();
+ benchmarkTimes.CheckCompletion.timeStart = benchStart;
- let HKPlayerData;
- let HKWorldItems;
- let HKSceneData;
+ let HKPlayerData;
+ let HKWorldItems;
+ let HKSceneData;
- if (jsonObject.hasOwnProperty("playerData")) {
- HKPlayerData = jsonObject.playerData;
+ if (jsonObject.hasOwnProperty("playerData")) {
+ HKPlayerData = jsonObject.playerData;
+ } else {
+ HK.saveAnalyzed = false;
+ return false;
+ }
+
+ if (jsonObject.hasOwnProperty("sceneData")) {
+ HKSceneData = jsonObject.sceneData;
+ if (jsonObject.sceneData.hasOwnProperty("persistentBoolItems")) {
+ HKWorldItems = jsonObject.sceneData.persistentBoolItems;
} else {
- HK.saveAnalyzed = false;
- return false;
+ HK.saveAnalyzed = false;
+ return false;
}
+ } else {
+ HK.saveAnalyzed = false;
+ return false;
+ }
- if (jsonObject.hasOwnProperty("sceneData")) {
- HKSceneData = jsonObject.sceneData;
- if (jsonObject.sceneData.hasOwnProperty("persistentBoolItems")) {
- HKWorldItems = jsonObject.sceneData.persistentBoolItems;
- } else {
- HK.saveAnalyzed = false;
- return false;
- }
- } else {
- HK.saveAnalyzed = false;
- return false;
- }
+ // Pre-Cleaning and filling initial data (h2, id) needed for PrepareHTMLString()
+ // PrefillHTML(HK.sections);
- // Pre-Cleaning and filling initial data (h2, id) needed for PrepareHTMLString()
- // PrefillHTML(HK.sections);
+ // Prevents adding current percent data after each function call and resets what the analyzing has done to the original object. Prevents wrong data display after subsequent save analyzing.
+ ResetCompletion(HK);
- // Prevents adding current percent data after each function call and resets what the analyzing has done to the original object. Prevents wrong data display after subsequent save analyzing.
- ResetCompletion(HK);
+ // ================================================================================== //
- // ================================================================================== //
+ // ---------------- Time Played ----------------- //
- // ---------------- Time Played ----------------- //
+ CheckPlayTime(HK.sections.intro, HKPlayerData.playTime);
- CheckPlayTime(HK.sections.intro, HKPlayerData.playTime);
+ // ---------------- Game Completion Status ----------------- //
- // ---------------- Game Completion Status ----------------- //
+ CheckCompletionPercent(HK.sections.intro, HKPlayerData);
- CheckCompletionPercent(HK.sections.intro, HKPlayerData);
+ // ---------------- Game Completion Status ----------------- //
- // ---------------- Game Completion Status ----------------- //
+ CheckSaveFileVersion(HK.sections.intro, HKPlayerData.version);
- CheckSaveFileVersion(HK.sections.intro, HKPlayerData.version);
+ // ---------------- Fleur Divide ----------------- //
- // ---------------- Fleur Divide ----------------- //
+ // AppendHTML(HK.sections.intro, FLEUR_DIVIDE);
- // AppendHTML(HK.sections.intro, FLEUR_DIVIDE);
+ // ---------------- Health Masks ----------------- //
- // ---------------- Health Masks ----------------- //
+ CheckHealthMasks(HK.sections.intro, HKPlayerData.maxHealthBase, HKPlayerData.permadeathMode);
- CheckHealthMasks(HK.sections.intro, HKPlayerData.maxHealthBase, HKPlayerData.permadeathMode);
+ // ---------------- Soul Orbs ----------------- //
- // ---------------- Soul Orbs ----------------- //
+ CheckSoulOrbs(HK.sections.intro, HKPlayerData.maxMP + HKPlayerData.MPReserveMax);
- CheckSoulOrbs(HK.sections.intro, HKPlayerData.maxMP + HKPlayerData.MPReserveMax);
+ // ---------------- Charm Notches (Slots) ----------------- //
- // ---------------- Charm Notches (Slots) ----------------- //
+ CheckNotches(HK.sections.intro, HKPlayerData.charmSlots, HKPlayerData.charmSlotsFilled);
- CheckNotches(HK.sections.intro, HKPlayerData.charmSlots, HKPlayerData.charmSlotsFilled);
+ // ---------------- Geo Amount ----------------- //
- // ---------------- Geo Amount ----------------- //
+ CheckGeo(HK.sections.intro, HKPlayerData.geo, HKPlayerData.geoPool);
- CheckGeo(HK.sections.intro, HKPlayerData.geo, HKPlayerData.geoPool);
+ // ---------------- Bosses (Base Game) --------------------- //
- // ---------------- Bosses (Base Game) --------------------- //
+ CheckIfDataTrue(HK.sections.bosses, HK.sections.bosses.entries, HKPlayerData, HKWorldItems);
- CheckIfDataTrue(HK.sections.bosses, HK.sections.bosses.entries, HKPlayerData, HKWorldItems);
+ // ---------------- Charms --------------------- //
- // ---------------- Charms --------------------- //
+ CheckIfDataTrue(HK.sections.charms, HK.sections.charms.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.charms, HK.sections.charms.entries, HKPlayerData);
+ // ---------------- Colosseum of Fools --------------------- //
- // ---------------- Colosseum of Fools --------------------- //
+ CheckIfDataTrue(HK.sections.colosseum, HK.sections.colosseum.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.colosseum, HK.sections.colosseum.entries, HKPlayerData);
+ // ---------------- Dreamers --------------------- //
- // ---------------- Dreamers --------------------- //
+ CheckIfDataTrue(HK.sections.dreamers, HK.sections.dreamers.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.dreamers, HK.sections.dreamers.entries, HKPlayerData);
+ // ---------------- Dream Nail and Essence --------------------- //
- // ---------------- Dream Nail and Essence --------------------- //
+ CheckIfDataTrue(HK.sections.dreamNail, HK.sections.dreamNail.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.dreamNail, HK.sections.dreamNail.entries, HKPlayerData);
+ // ---------------- Equipment --------------------- //
- // ---------------- Equipment --------------------- //
+ CheckIfDataTrue(HK.sections.equipment, HK.sections.equipment.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.equipment, HK.sections.equipment.entries, HKPlayerData);
+ // ---------------- Nail Upgrades --------------------- //
- // ---------------- Nail Upgrades --------------------- //
+ CheckNailUpgrades(HK.sections.nailUpgrades, HK.sections.nailUpgrades.entries, HKPlayerData);
- CheckNailUpgrades(HK.sections.nailUpgrades, HK.sections.nailUpgrades.entries, HKPlayerData);
+ // ---------------- Mask Shards --------------------- //
- // ---------------- Mask Shards --------------------- //
+ CheckIfDataTrue(HK.sections.maskShards, HK.sections.maskShards.entries, HKPlayerData, HKWorldItems);
- CheckIfDataTrue(HK.sections.maskShards, HK.sections.maskShards.entries, HKPlayerData, HKWorldItems);
+ // ---------------- Nail Arts --------------------- //
- // ---------------- Nail Arts --------------------- //
+ CheckIfDataTrue(HK.sections.nailArts, HK.sections.nailArts.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.nailArts, HK.sections.nailArts.entries, HKPlayerData);
+ // ---------------- Spells --------------------- //
- // ---------------- Spells --------------------- //
+ CheckSpellLevel(HK.sections.spells, HK.sections.spells.entries, HKPlayerData);
- CheckSpellLevel(HK.sections.spells, HK.sections.spells.entries, HKPlayerData);
+ // ---------------- Vessel Fragments --------------------- //
- // ---------------- Vessel Fragments --------------------- //
+ CheckIfDataTrue(HK.sections.vesselFragments, HK.sections.vesselFragments.entries, HKPlayerData, HKWorldItems);
- CheckIfDataTrue(HK.sections.vesselFragments, HK.sections.vesselFragments.entries, HKPlayerData, HKWorldItems);
+ // ---------------- Warrior Dreams --------------------- //
- // ---------------- Warrior Dreams --------------------- //
+ CheckWarriorDreams(HK.sections.warriorDreams, HK.sections.warriorDreams.entries, HKPlayerData);
- CheckWarriorDreams(HK.sections.warriorDreams, HK.sections.warriorDreams.entries, HKPlayerData);
+ // ---------------- Grimm Troupe Content Pack --------------------- //
- // ---------------- Grimm Troupe Content Pack --------------------- //
+ CheckIfDataTrue(HK.sections.grimmTroupe, HK.sections.grimmTroupe.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.grimmTroupe, HK.sections.grimmTroupe.entries, HKPlayerData);
+ // ---------------- Lifeblood Content Pack --------------------- //
- // ---------------- Lifeblood Content Pack --------------------- //
+ CheckIfDataTrue(HK.sections.lifeblood, HK.sections.lifeblood.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.lifeblood, HK.sections.lifeblood.entries, HKPlayerData);
+ // ---------------- Godmaster Content Pack --------------------- //
- // ---------------- Godmaster Content Pack --------------------- //
+ CheckIfDataTrue(HK.sections.godmaster, HK.sections.godmaster.entries, HKPlayerData);
- CheckIfDataTrue(HK.sections.godmaster, HK.sections.godmaster.entries, HKPlayerData);
+ // ---------------- Fleur Divide ----------------- //
- // ---------------- Fleur Divide ----------------- //
+ // AppendHTML(HK.sections.godmaster, FLEUR_DIVIDE);
- // AppendHTML(HK.sections.godmaster, FLEUR_DIVIDE);
+ // ------------------------- Essential Things ----------------------------- //
- // ------------------------- Essential Things ----------------------------- //
+ CheckAdditionalThings(HK.sections.essential, HK.sections.essential.entries, HKPlayerData, HKWorldItems);
- CheckAdditionalThings(HK.sections.essential, HK.sections.essential.entries, HKPlayerData, HKWorldItems);
+ // ---------------- Fleur Divide ----------------- //
- // ---------------- Fleur Divide ----------------- //
+ // AppendHTML(HK.sections.essential, FLEUR_DIVIDE);
- // AppendHTML(HK.sections.essential, FLEUR_DIVIDE);
+ // ------------------------- Achievements ----------------------------- //
- // ------------------------- Achievements ----------------------------- //
+ CheckAdditionalThings(HK.sections.achievements, HK.sections.achievements.entries, HKPlayerData, HKWorldItems);
- CheckAdditionalThings(HK.sections.achievements, HK.sections.achievements.entries, HKPlayerData, HKWorldItems);
+ // ---------------- Fleur Divide ----------------- //
- // ---------------- Fleur Divide ----------------- //
+ // AppendHTML(HK.sections.achievements, FLEUR_DIVIDE);
- // AppendHTML(HK.sections.achievements, FLEUR_DIVIDE);
+ // ------------------------- Game Statistics ----------------------------- //
- // ------------------------- Game Statistics ----------------------------- //
+ CheckAdditionalThings(HK.sections.statistics, HK.sections.statistics.entries, HKPlayerData, HKWorldItems, HKSceneData);
- CheckAdditionalThings(HK.sections.statistics, HK.sections.statistics.entries, HKPlayerData, HKWorldItems, HKSceneData);
+ // ------------------------- Godhome Statistics ----------------------------- //
- // ------------------------- Godhome Statistics ----------------------------- //
+ CheckAdditionalThings(HK.sections.godhomeStatistics, HK.sections.godhomeStatistics.entries, HKPlayerData, HKWorldItems, HKSceneData);
- CheckAdditionalThings(HK.sections.godhomeStatistics, HK.sections.godhomeStatistics.entries, HKPlayerData, HKWorldItems, HKSceneData);
+ // ------------------------- Hints ----------------------------- //
- // ------------------------- Hints ----------------------------- //
+ CheckHintsTrue(HK.sections.hints, HK.sections.hints.entries, HKPlayerData, HKWorldItems);
- CheckHintsTrue(HK.sections.hints, HK.sections.hints.entries, HKPlayerData, HKWorldItems);
+ // ------------------------- Extended game completion check ----------------------------- //
- // ------------------------- Extended game completion check ----------------------------- //
+ /* Percent completion is filled inside GenerateInnerHTML() using CompletionFill() */
+ CheckExtendedCompletion(HK);
- /* Percent completion is filled inside GenerateInnerHTML() using CompletionFill() */
- CheckExtendedCompletion(HK);
+ // ------------------------- Indicate that the save file was loaded and analyzed correctly ----------------------------- //
- // ------------------------- Indicate that the save file was loaded and analyzed correctly ----------------------------- //
+ HK.saveAnalyzed = true;
- HK.saveAnalyzed = true;
+ // ------------------------- Generate everything on the page with updated values ----------------------------- //
- // ------------------------- Generate everything on the page with updated values ----------------------------- //
+ GenerateInnerHTML(HK);
- GenerateInnerHTML(HK);
+ // Prevents wrong checkbox behaviour (must run after everything is finished)
+ CheckboxHintsToggle();
+ CheckboxSpoilersToggle();
- // Prevents wrong checkbox behaviour (must run after everything is finished)
- CheckboxHintsToggle();
- CheckboxSpoilersToggle();
+ /* focus the text area after analyzing the save, without scrolling the document (too slow) */
+ /* document.getElementById("save-area").focus({preventScroll: true}); */
- /* focus the text area after analyzing the save, without scrolling the document (too slow) */
- /* document.getElementById("save-area").focus({preventScroll: true}); */
+ // finish and show benchmark
+ // benchHKCCEnd = new Date();
+ benchmarkTimes.CheckCompletion.timeEnd = new Date();
+ // console.info("HKCheckCompletion() time (ms) =", benchHKCCEnd - benchHKCCBegin);
- // finish and show benchmark
- // benchHKCCEnd = new Date();
- benchmarkTimes.CheckCompletion.timeEnd = new Date();
- // console.info("HKCheckCompletion() time (ms) =", benchHKCCEnd - benchHKCCBegin);
+ // Benchmark(benchmarkTimes);
- // Benchmark(benchmarkTimes);
-
- return true;
+ return true;
}
/**
@@ -308,24 +308,24 @@ function HKCheckCompletion(jsonObject, benchStart = new Date()) {
*/
function PrepareHTMLString(section, textPrefix = "Unknown Completion Element: ", textSuffix = "Unknown Description Element", wiki = "") {
- let icon = completionSymbol;
- let b = ["
", ""];
- if (!textPrefix.length) b = ["", ""];
- if (wiki.length) b = [`
`, ""];
+ let icon = completionSymbol;
+ let b = ["
", ""];
+ if (!textPrefix.length) b = ["", ""];
+ if (wiki.length) b = [`
`, ""];
- let span = ["
", ""];
- let spoilerSpan = ["
", ""];
- if (section.id === "hk-hints") {
- span[0] = "
";
- icon = "";
- }
+ let span = ["", ""];
+ let spoilerSpan = ["", ""];
+ if (section.id === "hk-hints") {
+ span[0] = "";
+ icon = "";
+ }
- // let dash = "";
- if (textSuffix.length && textPrefix.length) textSuffix = "— " + textSuffix;
- if (textPrefix.includes("")) textSuffix = `${textSuffix}`;
+ // let dash = "";
+ if (textSuffix.length && textPrefix.length) textSuffix = "— " + textSuffix;
+ if (textPrefix.includes("")) textSuffix = `${textSuffix}`;
- // return divStart + icon + b[0] + textPrefix + b[1] + span[0] + pSpan + spoilerSpan[0] + dash + textSuffix + spoilerSpan[1] + span[1] + divEnd;
- return `
+ // return divStart + icon + b[0] + textPrefix + b[1] + span[0] + pSpan + spoilerSpan[0] + dash + textSuffix + spoilerSpan[1] + span[1] + divEnd;
+ return `
${divStart}
${icon}${b[0]}${textPrefix}${b[1]}${span[0]}${pSpan}${spoilerSpan[0]}${textSuffix}${spoilerSpan[1]}${span[1]}
${divEnd}
@@ -337,24 +337,24 @@ function PrepareHTMLString(section, textPrefix = "Unknown Completion Element: ",
*/
function CurrentDataTrue(section = {}, entry = "") {
- /* Increase section percentage except the Game Status and Hints sections */
- switch (section.id) {
+ /* Increase section percentage except the Game Status and Hints sections */
+ switch (section.id) {
- case "hk-intro":
- case "hk-hints":
- break;
+ case "hk-intro":
+ case "hk-hints":
+ break;
- case "hk-equipment":
+ case "hk-equipment":
- // double % for equipment
- section.percent += 2;
- break;
+ // double % for equipment
+ section.percent += 2;
+ break;
- default:
- section.percent++;
- }
+ default:
+ section.percent++;
+ }
- section.entries[entry].icon = "green";
+ section.entries[entry].icon = "green";
}
/**
@@ -362,7 +362,7 @@ function CurrentDataTrue(section = {}, entry = "") {
*/
function CurrentDataFalse(section = {}, entry = "") {
- section.entries[entry].icon = "red";
+ section.entries[entry].icon = "red";
}
/**
@@ -377,7 +377,7 @@ function CurrentDataFalse(section = {}, entry = "") {
*/
function CurrentDataBlank(section = {}, entry = "") {
- section.entries[entry].icon = "none";
+ section.entries[entry].icon = "none";
}
/**
@@ -387,23 +387,23 @@ function CurrentDataBlank(section = {}, entry = "") {
*/
function CheckPlayTime(section, playTime) {
- let seconds = Math.floor(playTime);
- let minutes = Math.floor((seconds / 60) % 60);
- let hours = Math.floor(seconds / 3600);
- let sec = Math.floor(seconds % 60);
+ let seconds = Math.floor(playTime);
+ let minutes = Math.floor((seconds / 60) % 60);
+ let hours = Math.floor(seconds / 3600);
+ let sec = Math.floor(seconds % 60);
- section.entries.timePlayed.timeH = hours;
- section.entries.timePlayed.timeM = minutes;
- section.entries.timePlayed.timeS = sec;
+ section.entries.timePlayed.timeH = hours;
+ section.entries.timePlayed.timeM = minutes;
+ section.entries.timePlayed.timeS = sec;
- if (sec < 10) sec = "0" + sec;
- if (minutes < 10) minutes = "0" + minutes;
+ if (sec < 10) sec = "0" + sec;
+ if (minutes < 10) minutes = "0" + minutes;
- let textFill = "Time Played:" + pSpan + "" + hours + " h " + minutes + " min " + sec + " sec";
+ let textFill = "Time Played:" + pSpan + "" + hours + " h " + minutes + " min " + sec + " sec";
- section.entries.timePlayed.spoiler = hours + " h " + minutes + " min " + sec + " sec";
+ section.entries.timePlayed.spoiler = hours + " h " + minutes + " min " + sec + " sec";
- // document.getElementById(section.id).innerHTML += divStart + SYMBOL_CLOCK + textFill + divEnd;
+ // document.getElementById(section.id).innerHTML += divStart + SYMBOL_CLOCK + textFill + divEnd;
}
/**
@@ -413,45 +413,45 @@ function CheckPlayTime(section, playTime) {
*/
function CheckCompletionPercent(section, playerData) {
- let completionPercentage = Math.round(playerData.completionPercentage);
- let maxPercent = 0;
+ let completionPercentage = Math.round(playerData.completionPercentage);
+ let maxPercent = 0;
- /* Normal (current) game version behaviour: 112% */
- section.maxPercent = section.maxPercentDefault;
- maxPercent = section.maxPercentDefault;
- section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterDefault;
+ /* Normal (current) game version behaviour: 112% */
+ section.maxPercent = section.maxPercentDefault;
+ maxPercent = section.maxPercentDefault;
+ section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterDefault;
- section.percent = completionPercentage;
- section.entries.gameCompletion.spoiler = completionPercentage;
+ section.percent = completionPercentage;
+ section.entries.gameCompletion.spoiler = completionPercentage;
- /* Lifeblood behaviour: 107% */
- if (!playerData.hasOwnProperty("hasGodfinder")) {
+ /* Lifeblood behaviour: 107% */
+ if (!playerData.hasOwnProperty("hasGodfinder")) {
- section.maxPercent = section.maxPercentLifeblood;
- maxPercent = section.maxPercentLifeblood;
- section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterLifeblood;
- }
+ section.maxPercent = section.maxPercentLifeblood;
+ maxPercent = section.maxPercentLifeblood;
+ section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterLifeblood;
+ }
- /* Grimm Troupe bahaviour: 106% */
- if (!playerData.hasOwnProperty("killedHiveKnight")) {
+ /* Grimm Troupe bahaviour: 106% */
+ if (!playerData.hasOwnProperty("killedHiveKnight")) {
- section.maxPercent = section.maxPercentGrimmTroupe;
- maxPercent = section.maxPercentGrimmTroupe;
- section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterGrimmTroupe;
- }
+ section.maxPercent = section.maxPercentGrimmTroupe;
+ maxPercent = section.maxPercentGrimmTroupe;
+ section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterGrimmTroupe;
+ }
- /* Base Game behaviour with no Content Packs: 100% */
- if (!playerData.hasOwnProperty("gotCharm_37")) {
+ /* Base Game behaviour with no Content Packs: 100% */
+ if (!playerData.hasOwnProperty("gotCharm_37")) {
- section.maxPercent = section.maxPercentBaseGame;
- maxPercent = section.maxPercentBaseGame;
- section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterBaseGame;
- }
+ section.maxPercent = section.maxPercentBaseGame;
+ maxPercent = section.maxPercentBaseGame;
+ section.entries.gameCompletion.spoilerAfter = section.entries.gameCompletion.spoilerAfterBaseGame;
+ }
- (completionPercentage >= maxPercent) ? CurrentDataTrue(section, "gameCompletion"): CurrentDataFalse(section, "gameCompletion");
+ (completionPercentage >= maxPercent) ? CurrentDataTrue(section, "gameCompletion"): CurrentDataFalse(section, "gameCompletion");
- /* let textFill = "Game Completion:" + pSpan + "" + completionPercentage + " %" + pSpan + "(out of " + section.maxPercent + " %)"; */
- // document.getElementById(section.id).innerHTML += divStart + completionSymbol + textFill + divEnd;
+ /* let textFill = "Game Completion:" + pSpan + "" + completionPercentage + " %" + pSpan + "(out of " + section.maxPercent + " %)"; */
+ // document.getElementById(section.id).innerHTML += divStart + completionSymbol + textFill + divEnd;
}
/**
@@ -460,63 +460,63 @@ function CheckCompletionPercent(section, playerData) {
*/
function CheckExtendedCompletion(db) {
- let sections = db.sections;
- let entries = {};
- let gameCompletionExtended = db.sections.intro.entries.gameCompletionExtended;
- let intro = db.sections.intro;
+ let sections = db.sections;
+ let entries = {};
+ let gameCompletionExtended = db.sections.intro.entries.gameCompletionExtended;
+ let intro = db.sections.intro;
- for (let section in sections) {
+ for (let section in sections) {
- entries = sections[section].entries;
+ entries = sections[section].entries;
- switch (section) {
+ switch (section) {
- case "intro":
- case "hints":
- continue;
+ case "intro":
+ case "hints":
+ continue;
- default:
+ default:
- for (let entry in entries) {
+ for (let entry in entries) {
- /* Skip counting these entries */
- switch (entry) {
+ /* Skip counting these entries */
+ switch (entry) {
- case "oldNail":
- case "geoPool":
- case "rancidEggs":
- case "jinnEggsSold":
- case "xunFlowerBrokeTimes":
- case "geoRocks":
- case "itemsDiscovered":
- continue;
- }
+ case "oldNail":
+ case "geoPool":
+ case "rancidEggs":
+ case "jinnEggsSold":
+ case "xunFlowerBrokeTimes":
+ case "geoRocks":
+ case "itemsDiscovered":
+ continue;
+ }
- if (entries[entry].hasOwnProperty("icon")) {
+ if (entries[entry].hasOwnProperty("icon")) {
- intro.extendedCompletionTotal++;
+ intro.extendedCompletionTotal++;
- if (entries[entry].icon === "green") {
- intro.extendedCompletionDone++;
- }
-
- if (entries[entry].hasOwnProperty("disabled") && entries[entry].disabled == true) {
- intro.extendedCompletionTotal--;
- }
- }
- }
+ if (entries[entry].icon === "green") {
+ intro.extendedCompletionDone++;
+ }
+ if (entries[entry].hasOwnProperty("disabled") && entries[entry].disabled == true) {
+ intro.extendedCompletionTotal--;
+ }
+ }
}
+
}
+ }
- if (intro.extendedCompletionDone >= intro.extendedCompletionTotal) {
- gameCompletionExtended.icon === "green";
- }
+ if (intro.extendedCompletionDone >= intro.extendedCompletionTotal) {
+ gameCompletionExtended.icon === "green";
+ }
- let percent = (intro.extendedCompletionDone/intro.extendedCompletionTotal) * 100;
+ let percent = (intro.extendedCompletionDone / intro.extendedCompletionTotal) * 100;
- gameCompletionExtended.spoiler = intro.extendedCompletionDone;
- gameCompletionExtended.spoilerAfter = ` / ${intro.extendedCompletionTotal} = ${percent.toFixed(2)} %`;
+ gameCompletionExtended.spoiler = intro.extendedCompletionDone;
+ gameCompletionExtended.spoilerAfter = ` / ${intro.extendedCompletionTotal} = ${percent.toFixed(2)} %`;
}
/**
@@ -526,12 +526,12 @@ function CheckExtendedCompletion(db) {
*/
function CheckSaveFileVersion(section, saveVersion = HK.sections.intro.entries.saveVersion.spoiler) {
- CurrentDataBlank(section, section.entries.saveVersion.id);
+ CurrentDataBlank(section, section.entries.saveVersion.id);
- section.entries.saveVersion.spoiler = `${saveVersion}`;
+ section.entries.saveVersion.spoiler = `${saveVersion}`;
- /* let textFill = `Save Version:${pSpan}${saveVersion}${pSpan}`; */
- // document.getElementById(section.id).innerHTML += divStart + completionSymbol + textFill + divEnd;
+ /* let textFill = `Save Version:${pSpan}${saveVersion}${pSpan}`; */
+ // document.getElementById(section.id).innerHTML += divStart + completionSymbol + textFill + divEnd;
}
/**
@@ -542,28 +542,28 @@ function CheckSaveFileVersion(section, saveVersion = HK.sections.intro.entries.s
*/
function CheckHealthMasks(section, masks = 5, permadeathMode = 0) {
- section.entries.health.amountTotal = masks;
+ section.entries.health.amountTotal = masks;
- if (permadeathMode > 0) {
- section.entries.health.permadeathMode = true;
- } else {
- section.entries.health.permadeathMode = false;
- }
+ if (permadeathMode > 0) {
+ section.entries.health.permadeathMode = true;
+ } else {
+ section.entries.health.permadeathMode = false;
+ }
- /* let icon = SYMBOL_EMPTY;
- let textFill = "Health:";
- let maskImages = "";
- let maskNormal = `
`;
- let maskSteel = `
`;
- let maskImg = "";
+ /* let icon = SYMBOL_EMPTY;
+ let textFill = "Health:";
+ let maskImages = "";
+ let maskNormal = `
`;
+ let maskSteel = `
`;
+ let maskImg = "";
- (permadeathMode > 0) ? maskImg = maskSteel: maskImg = maskNormal;
+ (permadeathMode > 0) ? maskImg = maskSteel: maskImg = maskNormal;
- for (let i = 0; i < masks; i++) {
- maskImages += maskImg;
- } */
+ for (let i = 0; i < masks; i++) {
+ maskImages += maskImg;
+ } */
- // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + maskImages + divEnd;
+ // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + maskImages + divEnd;
}
/**
@@ -573,19 +573,19 @@ function CheckHealthMasks(section, masks = 5, permadeathMode = 0) {
*/
function CheckSoulOrbs(section, totalSoul) {
- /* let icon = SYMBOL_EMPTY;
- let textFill = "Soul:";
- let soulImages = "";
- let soulNormal = `
`;
- let soulImg = soulNormal;
+ /* let icon = SYMBOL_EMPTY;
+ let textFill = "Soul:";
+ let soulImages = "";
+ let soulNormal = `
`;
+ let soulImg = soulNormal;
- for (let i = 0, total = totalSoul / 33; i < total; i++) {
- soulImages += soulImg;
- } */
+ for (let i = 0, total = totalSoul / 33; i < total; i++) {
+ soulImages += soulImg;
+ } */
- section.entries.soul.amountTotal = totalSoul;
+ section.entries.soul.amountTotal = totalSoul;
- // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + soulImages + divEnd;
+ // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + soulImages + divEnd;
}
/**
@@ -595,21 +595,21 @@ function CheckSoulOrbs(section, totalSoul) {
*/
function CheckGeo(section, geoValue = 0, geoPoolValue = 0) {
- section.entries.geo.amount = geoValue;
- section.entries.geo.amountShade = geoPoolValue;
- section.entries.geo.amountTotal = geoValue + geoPoolValue;
+ section.entries.geo.amount = geoValue;
+ section.entries.geo.amountShade = geoPoolValue;
+ section.entries.geo.amountTotal = geoValue + geoPoolValue;
- /* let icon = SYMBOL_EMPTY;
- let textFill = `Geo:
${geoValue}`;
+ /* let icon = SYMBOL_EMPTY;
+ let textFill = `Geo:
${geoValue}`;
- // Show Shade Geo value and image only if Shade has at least 1 Geo on it
- if (geoPoolValue > 0) textFill += `
- ${pSpan}+
${geoPoolValue}`;
+ // Show Shade Geo value and image only if Shade has at least 1 Geo on it
+ if (geoPoolValue > 0) textFill += `
+ ${pSpan}+
${geoPoolValue}`;
- // Show also total Geo (Geo + Shade Geo) if player has at least 1 geo alongside the shade geo
- if (geoValue > 0 && geoPoolValue > 0) textFill += `${pSpan}=${pSpan}${geoValue+geoPoolValue}`; */
+ // Show also total Geo (Geo + Shade Geo) if player has at least 1 geo alongside the shade geo
+ if (geoValue > 0 && geoPoolValue > 0) textFill += `${pSpan}=${pSpan}${geoValue+geoPoolValue}`; */
- // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + divEnd;
+ // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + divEnd;
}
/**
@@ -620,60 +620,60 @@ function CheckGeo(section, geoValue = 0, geoPoolValue = 0) {
*/
function CheckNotches(section, notchesTotal = 3, notchesFilled = 0) {
- let {
- notchesOvercharmed,
- notchesUnused
- } = 0;
+ let {
+ notchesOvercharmed,
+ notchesUnused
+ } = 0;
- section.entries.notches.amountTotal = notchesTotal;
+ section.entries.notches.amountTotal = notchesTotal;
- // How many overcharmed notches images to show
- notchesOvercharmed = notchesFilled - notchesTotal;
- if (notchesOvercharmed < 1) notchesOvercharmed = 0;
+ // How many overcharmed notches images to show
+ notchesOvercharmed = notchesFilled - notchesTotal;
+ if (notchesOvercharmed < 1) notchesOvercharmed = 0;
- section.entries.notches.amountOvercharmed = notchesOvercharmed;
+ section.entries.notches.amountOvercharmed = notchesOvercharmed;
- // How many unused notches images to show
- notchesUnused = notchesTotal - notchesFilled;
- if (notchesUnused < 1) notchesUnused = 0;
+ // How many unused notches images to show
+ notchesUnused = notchesTotal - notchesFilled;
+ if (notchesUnused < 1) notchesUnused = 0;
- section.entries.notches.amountUnused = notchesUnused;
+ section.entries.notches.amountUnused = notchesUnused;
- // Correct number of filled/used notches images to show when player is overcharmed
- if (notchesFilled > notchesTotal) notchesFilled = notchesTotal;
+ // Correct number of filled/used notches images to show when player is overcharmed
+ if (notchesFilled > notchesTotal) notchesFilled = notchesTotal;
- section.entries.notches.amountFilled = notchesFilled;
+ section.entries.notches.amountFilled = notchesFilled;
- /* let icon = SYMBOL_EMPTY;
- let textFill = `Notches:${pSpan}`;
+ /* let icon = SYMBOL_EMPTY;
+ let textFill = `Notches:${pSpan}`;
- let notchImages = "";
- let notchNormalImage = `
`;
- let notchFilledImage = `
`;
- let notchOvercharmedImage = `
`;
+ let notchImages = "";
+ let notchNormalImage = `
`;
+ let notchFilledImage = `
`;
+ let notchOvercharmedImage = `
`;
- // First check filled (used) notches and fill them (skips if no filled notches)
- if (notchesFilled > 0) {
- for (let i = 0; i < notchesFilled; i++) {
- notchImages += notchFilledImage;
- }
- }
+ // First check filled (used) notches and fill them (skips if no filled notches)
+ if (notchesFilled > 0) {
+ for (let i = 0; i < notchesFilled; i++) {
+ notchImages += notchFilledImage;
+ }
+ }
- // Second check overcharmed notches and fill them (skips if player is not overcharmed)
- if (notchesOvercharmed > 0) {
- for (let i = 0; i < notchesOvercharmed; i++) {
- notchImages += notchOvercharmedImage;
- }
- }
+ // Second check overcharmed notches and fill them (skips if player is not overcharmed)
+ if (notchesOvercharmed > 0) {
+ for (let i = 0; i < notchesOvercharmed; i++) {
+ notchImages += notchOvercharmedImage;
+ }
+ }
- // Lastly, fill all unused notches
- if (notchesUnused > 0) {
- for (let i = 0; i < notchesUnused; i++) {
- notchImages += notchNormalImage;
- }
- } */
+ // Lastly, fill all unused notches
+ if (notchesUnused > 0) {
+ for (let i = 0; i < notchesUnused; i++) {
+ notchImages += notchNormalImage;
+ }
+ } */
- // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + notchImages + divEnd;
+ // document.getElementById(section.id).innerHTML += divStartCenter + icon + textFill + notchImages + divEnd;
}
/**
@@ -685,190 +685,190 @@ function CheckNotches(section, notchesTotal = 3, notchesFilled = 0) {
*/
function CheckIfDataTrue(section, dataObject, playerData, worldData = []) {
- /* let {
- textPrefix,
- textSuffix,
- } = "";
- let sFillText = "";
- let wiki = ""; */
- let checkText = "";
+ /* let {
+ textPrefix,
+ textSuffix,
+ } = "";
+ let sFillText = "";
+ let wiki = ""; */
+ let checkText = "";
- for (let i in dataObject) {
+ for (let i in dataObject) {
- /* textPrefix = dataObject[i].name;
- textSuffix = dataObject[i].spoiler;
- (dataObject[i].hasOwnProperty("wiki")) ? wiki = dataObject[i].wiki: wiki = ""; */
+ /* textPrefix = dataObject[i].name;
+ textSuffix = dataObject[i].spoiler;
+ (dataObject[i].hasOwnProperty("wiki")) ? wiki = dataObject[i].wiki: wiki = ""; */
- switch (i) {
- case "gotCharm_36":
- // prevents green checkbox and adding 1% when only got one white fragment
- (playerData.gotQueenFragment === true && playerData.gotKingFragment === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
+ switch (i) {
+ case "gotCharm_36":
+ // prevents green checkbox and adding 1% when only got one white fragment
+ (playerData.gotQueenFragment === true && playerData.gotKingFragment === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
- case "gotCharm_37":
- case "gotCharm_38":
- case "gotCharm_39":
- case "gotCharm_40":
- case "killedGrimm":
- case "grimmChildLevel":
- case "killedHiveKnight":
- case "hasGodfinder":
+ case "gotCharm_37":
+ case "gotCharm_38":
+ case "gotCharm_39":
+ case "gotCharm_40":
+ case "killedGrimm":
+ case "grimmChildLevel":
+ case "killedHiveKnight":
+ case "hasGodfinder":
- // fades out the entries if save file is from older game versions
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
+ // fades out the entries if save file is from older game versions
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
- break;
- }
-
- // Checks for Nightmare King (4) or Banishment (5)
- if (i === "grimmChildLevel") {
- // (playerData.grimmChildLevel >= 4) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
-
- /* Check if Nightmare King or Banishment by looking at grimmChildLevel */
- switch (playerData[i]) {
-
- case 4:
- dataObject[i].name = dataObject[i].nameNightmareKing;
- dataObject[i].spoiler = dataObject[i].spoilerNightmareKing;
- dataObject[i].wiki = dataObject[i].wikiNightmareKing;
-
- CurrentDataTrue(section, i);
-
- break;
- case 5:
- dataObject[i].name = dataObject[i].nameBanishment;
- dataObject[i].spoiler = dataObject[i].spoilerBanishment;
- dataObject[i].wiki = dataObject[i].wikiBanishment;
-
- CurrentDataTrue(section, i);
-
- break;
- default:
- CurrentDataFalse(section, i);
- dataObject[i].name = dataObject[i].nameDefault;
- dataObject[i].spoiler = dataObject[i].spoilerDefault;
- dataObject[i].wiki = dataObject[i].wikiDefault;
- }
-
- break;
- }
-
- if (i === "gotCharm_40") {
- CurrentDataFalse(section, i);
- dataObject[i].name = dataObject[i].nameDefault;
- dataObject[i].spoiler = dataObject[i].spoilerDefault;
- dataObject[i].wiki = dataObject[i].wikiDefault;
-
- switch (playerData.grimmChildLevel) {
-
- case 1:
- if (playerData[i] === true) {
- dataObject[i].name = dataObject[i].nameGrimmchildP1;
- dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP1;
- dataObject[i].wiki = dataObject[i].wikiGrimmchild;
-
- CurrentDataTrue(section, i);
- }
-
- break;
- case 2:
- dataObject[i].name = dataObject[i].nameGrimmchildP2;
- dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP2;
- dataObject[i].wiki = dataObject[i].wikiGrimmchild;
-
- CurrentDataTrue(section, i);
-
- break;
- case 3:
- dataObject[i].name = dataObject[i].nameGrimmchildP3;
- dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP3;
- dataObject[i].wiki = dataObject[i].wikiGrimmchild;
-
- CurrentDataTrue(section, i);
-
- break;
- case 4:
- dataObject[i].name = dataObject[i].nameGrimmchildP4;
- dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP4;
- dataObject[i].wiki = dataObject[i].wikiGrimmchild;
-
- CurrentDataTrue(section, i);
-
- break;
- case 5:
- dataObject[i].name = dataObject[i].nameCarefreeMelody;
- dataObject[i].spoiler = dataObject[i].spoilerCarefreeMelody;
- dataObject[i].wiki = dataObject[i].wikiCarefreeMelody;
-
- CurrentDataTrue(section, i);
-
- break;
- default:
- dataObject[i].name = dataObject[i].nameDefault;
- dataObject[i].spoiler = dataObject[i].spoilerDefault;
- dataObject[i].wiki = dataObject[i].wikiDefault;
- }
-
- break;
- }
-
- (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
-
- break;
-
- case "bossGruzMother":
- case "bossBroodingMawlek":
- case "maskShardCrossroadsSprings":
- case "maskShardCrossroadsMawlek":
- case "maskShardGrubfather":
- case "maskShardBretta":
- case "maskShardQueensStation":
- case "maskShardWaterways":
- case "maskShardStoneSanctuary":
- case "maskShardCrystalPeak":
- case "maskShardDeepnest":
- case "maskShardHive":
- case "maskShardDelicateFlower":
- case "vesselFragmentGreenpath":
- case "vesselFragmentCrossroads":
- case "vesselFragmentCityOfTears":
- case "vesselFragmentDeepnest":
- case "vesselFragmentFountain":
- (WorldDataActivated(dataObject[i].id, dataObject[i].sceneName, worldData)) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "pantheonMaster":
- case "pantheonArtist":
- case "pantheonSage":
- case "pantheonKnight":
- checkText = CheckGodmasterDoors(dataObject[i], playerData);
-
- if (checkText === "PropertyNotFound") {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- break;
-
- } else if (checkText === "PantheonCompleted") {
- CurrentDataTrue(section, i);
- break;
-
- } else {
- CurrentDataFalse(section, i);
- }
- break;
-
- default:
- (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
}
- /* sFillText += PrepareHTMLString(section, textPrefix, textSuffix, wiki); */
+ // Checks for Nightmare King (4) or Banishment (5)
+ if (i === "grimmChildLevel") {
+ // (playerData.grimmChildLevel >= 4) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+
+ /* Check if Nightmare King or Banishment by looking at grimmChildLevel */
+ switch (playerData[i]) {
+
+ case 4:
+ dataObject[i].name = dataObject[i].nameNightmareKing;
+ dataObject[i].spoiler = dataObject[i].spoilerNightmareKing;
+ dataObject[i].wiki = dataObject[i].wikiNightmareKing;
+
+ CurrentDataTrue(section, i);
+
+ break;
+ case 5:
+ dataObject[i].name = dataObject[i].nameBanishment;
+ dataObject[i].spoiler = dataObject[i].spoilerBanishment;
+ dataObject[i].wiki = dataObject[i].wikiBanishment;
+
+ CurrentDataTrue(section, i);
+
+ break;
+ default:
+ CurrentDataFalse(section, i);
+ dataObject[i].name = dataObject[i].nameDefault;
+ dataObject[i].spoiler = dataObject[i].spoilerDefault;
+ dataObject[i].wiki = dataObject[i].wikiDefault;
+ }
+
+ break;
+ }
+
+ if (i === "gotCharm_40") {
+ CurrentDataFalse(section, i);
+ dataObject[i].name = dataObject[i].nameDefault;
+ dataObject[i].spoiler = dataObject[i].spoilerDefault;
+ dataObject[i].wiki = dataObject[i].wikiDefault;
+
+ switch (playerData.grimmChildLevel) {
+
+ case 1:
+ if (playerData[i] === true) {
+ dataObject[i].name = dataObject[i].nameGrimmchildP1;
+ dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP1;
+ dataObject[i].wiki = dataObject[i].wikiGrimmchild;
+
+ CurrentDataTrue(section, i);
+ }
+
+ break;
+ case 2:
+ dataObject[i].name = dataObject[i].nameGrimmchildP2;
+ dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP2;
+ dataObject[i].wiki = dataObject[i].wikiGrimmchild;
+
+ CurrentDataTrue(section, i);
+
+ break;
+ case 3:
+ dataObject[i].name = dataObject[i].nameGrimmchildP3;
+ dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP3;
+ dataObject[i].wiki = dataObject[i].wikiGrimmchild;
+
+ CurrentDataTrue(section, i);
+
+ break;
+ case 4:
+ dataObject[i].name = dataObject[i].nameGrimmchildP4;
+ dataObject[i].spoiler = dataObject[i].spoilerGrimmchildP4;
+ dataObject[i].wiki = dataObject[i].wikiGrimmchild;
+
+ CurrentDataTrue(section, i);
+
+ break;
+ case 5:
+ dataObject[i].name = dataObject[i].nameCarefreeMelody;
+ dataObject[i].spoiler = dataObject[i].spoilerCarefreeMelody;
+ dataObject[i].wiki = dataObject[i].wikiCarefreeMelody;
+
+ CurrentDataTrue(section, i);
+
+ break;
+ default:
+ dataObject[i].name = dataObject[i].nameDefault;
+ dataObject[i].spoiler = dataObject[i].spoilerDefault;
+ dataObject[i].wiki = dataObject[i].wikiDefault;
+ }
+
+ break;
+ }
+
+ (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+
+ break;
+
+ case "bossGruzMother":
+ case "bossBroodingMawlek":
+ case "maskShardCrossroadsSprings":
+ case "maskShardCrossroadsMawlek":
+ case "maskShardGrubfather":
+ case "maskShardBretta":
+ case "maskShardQueensStation":
+ case "maskShardWaterways":
+ case "maskShardStoneSanctuary":
+ case "maskShardCrystalPeak":
+ case "maskShardDeepnest":
+ case "maskShardHive":
+ case "maskShardDelicateFlower":
+ case "vesselFragmentGreenpath":
+ case "vesselFragmentCrossroads":
+ case "vesselFragmentCityOfTears":
+ case "vesselFragmentDeepnest":
+ case "vesselFragmentFountain":
+ (WorldDataActivated(dataObject[i].id, dataObject[i].sceneName, worldData)) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ case "pantheonMaster":
+ case "pantheonArtist":
+ case "pantheonSage":
+ case "pantheonKnight":
+ checkText = CheckGodmasterDoors(dataObject[i], playerData);
+
+ if (checkText === "PropertyNotFound") {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
+ break;
+
+ } else if (checkText === "PantheonCompleted") {
+ CurrentDataTrue(section, i);
+ break;
+
+ } else {
+ CurrentDataFalse(section, i);
+ }
+ break;
+
+ default:
+ (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
}
- // AppendHTML(section, sFillText);
+ /* sFillText += PrepareHTMLString(section, textPrefix, textSuffix, wiki); */
+ }
+
+ // AppendHTML(section, sFillText);
}
/**
@@ -879,31 +879,31 @@ function CheckIfDataTrue(section, dataObject, playerData, worldData = []) {
*/
function CheckSpellLevel(section, dataObject, playerData) {
- let sFillText = "";
+ let sFillText = "";
- for (let i in dataObject) {
- switch (i) {
- case "vengefulSpirit":
- case "shadeSoul":
- (playerData.fireballLevel >= dataObject[i].fireballLevel) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
- break;
- case "desolateDive":
- case "descendingDark":
- (playerData.quakeLevel >= dataObject[i].quakeLevel) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
- break;
- case "howlingWraiths":
- case "abyssShriek":
- (playerData.screamLevel >= dataObject[i].screamLevel) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
- break;
- default:
- break;
- }
+ for (let i in dataObject) {
+ switch (i) {
+ case "vengefulSpirit":
+ case "shadeSoul":
+ (playerData.fireballLevel >= dataObject[i].fireballLevel) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
+ break;
+ case "desolateDive":
+ case "descendingDark":
+ (playerData.quakeLevel >= dataObject[i].quakeLevel) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
+ break;
+ case "howlingWraiths":
+ case "abyssShriek":
+ (playerData.screamLevel >= dataObject[i].screamLevel) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
+ break;
+ default:
+ break;
}
+ }
- // AppendHTML(section, sFillText);
+ // AppendHTML(section, sFillText);
}
/**
@@ -914,14 +914,14 @@ function CheckSpellLevel(section, dataObject, playerData) {
*/
function CheckWarriorDreams(section, dataObject, playerData) {
- let sFillText = "";
+ let sFillText = "";
- for (let i in dataObject) {
- (playerData[i] >= 2) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
- }
+ for (let i in dataObject) {
+ (playerData[i] >= 2) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ sFillText += PrepareHTMLString(section, dataObject[i].name, dataObject[i].spoiler, dataObject[i].wiki);
+ }
- // AppendHTML(section, sFillText);
+ // AppendHTML(section, sFillText);
}
/**
@@ -931,13 +931,13 @@ function CheckWarriorDreams(section, dataObject, playerData) {
*/
function CheckGodmasterDoors(dataObject, playerData) {
- if (playerData.hasOwnProperty(dataObject.property) === false) {
- return "PropertyNotFound";
- } else if (playerData[dataObject.property].completed === true) {
- return "PantheonCompleted";
- } else {
- return "PantheonNotCompleted";
- }
+ if (playerData.hasOwnProperty(dataObject.property) === false) {
+ return "PropertyNotFound";
+ } else if (playerData[dataObject.property].completed === true) {
+ return "PantheonCompleted";
+ } else {
+ return "PantheonNotCompleted";
+ }
}
/**
@@ -948,19 +948,19 @@ function CheckGodmasterDoors(dataObject, playerData) {
*/
function CheckNailUpgrades(section, dataObject, playerData) {
- // appends "Nail" to every array element
- // same as names in the database object
- let nail = ["old", "sharpened", "channeled", "coiled", "pure"].map((element) => element + "Nail");
+ // appends "Nail" to every array element
+ // same as names in the database object
+ let nail = ["old", "sharpened", "channeled", "coiled", "pure"].map((element) => element + "Nail");
- let sFillText = "";
+ let sFillText = "";
- for (let i = 0; i < 5; i++) {
- (playerData.nailSmithUpgrades >= i) ? CurrentDataTrue(section, nail[i]): CurrentDataFalse(section, nail[i]);
- sFillText += PrepareHTMLString(section, dataObject[nail[i]].name, dataObject[nail[i]].spoiler, dataObject[nail[i]].wiki);
- }
- if (section.percent) section.percent--; // subject one for the Old Nail
+ for (let i = 0; i < 5; i++) {
+ (playerData.nailSmithUpgrades >= i) ? CurrentDataTrue(section, nail[i]): CurrentDataFalse(section, nail[i]);
+ sFillText += PrepareHTMLString(section, dataObject[nail[i]].name, dataObject[nail[i]].spoiler, dataObject[nail[i]].wiki);
+ }
+ if (section.percent) section.percent--; // subject one for the Old Nail
- // AppendHTML(section, sFillText);
+ // AppendHTML(section, sFillText);
}
/**
@@ -971,15 +971,15 @@ function CheckNailUpgrades(section, dataObject, playerData) {
*/
function WorldDataActivated(idText, sceneNameText, worldData) {
- // Search for the Interactable
- for (let i = 0, length = worldData.length; i < length; i++) {
- // Verify if the Interactable is activated and return the result
- if (worldData[i].id === idText && worldData[i].sceneName === sceneNameText && worldData[i].activated === true) {
- return true;
- }
+ // Search for the Interactable
+ for (let i = 0, length = worldData.length; i < length; i++) {
+ // Verify if the Interactable is activated and return the result
+ if (worldData[i].id === idText && worldData[i].sceneName === sceneNameText && worldData[i].activated === true) {
+ return true;
}
- // If not, return false
- return false;
+ }
+ // If not, return false
+ return false;
}
/**
@@ -1028,548 +1028,548 @@ function WorldDataActivated(idText, sceneNameText, worldData) {
*/
function CheckAdditionalThings(section, dataObject, playerData, worldData, sceneData) {
- /* let {
- textPrefix,
- textSuffix,
- wiki
- } = "";
- let sFillText = ""; */
-
- // Start main loop
- for (let i in dataObject) {
- /* textPrefix = dataObject[i].name;
- (dataObject[i].hasOwnProperty("spoiler")) ? textSuffix = dataObject[i].spoiler: textSuffix = "";
- (dataObject[i].hasOwnProperty("wiki")) ? wiki = dataObject[i].wiki: wiki = ""; */
-
- let {
- amount,
- countTotal,
- total,
- notActivated,
- activated,
- discoveredTotal
- } = 0;
-
- switch (i) {
- case "areaMaps":
- case "grubsCollected":
- case "grubRewards":
- case "charmsOwned":
- case "charmSlots":
- case "dreamOrbs":
- case "whisperingRoots":
- case "fountainGeo":
- case "nailDamage":
- case "stationsOpened":
- case "journalEntriesCompleted":
- case "journalNotesCompleted":
- case "whiteDefenderDefeats":
- case "greyPrinceDefeats":
- if (i === "areaMaps") {
- amount = CountMaps(dataObject[i].list);
- } else if (i === "whisperingRoots") {
- amount = CountWorldItem("Dream Plant");
- } else {
- amount = playerData[i];
- }
-
- if (i === "stationsOpened") {
- if (playerData.openedHiddenStation === true) amount++;
- }
-
- countTotal = amount;
- dataObject[i].amount = amount;
-
- if (i === "journalEntriesCompleted" || i === "journalNotesCompleted") {
- countTotal = `${amount} / ${playerData.journalEntriesTotal}`;
- dataObject[i].amountTotal = playerData.journalEntriesTotal;
-
- /* when Zote is dead, the max Journal entries will equal = 160 instead of 164. For the green tick */
- if (playerData.zoteRescuedBuzzer === false && playerData.hasWalljump === true) {
- dataObject[i].max = dataObject[i].maxZoteOff; /* Substract GPZ and 3 Zotelings from max */
- dataObject[i].spoiler = dataObject[i].spoilerZoteOff; /* Change spoiler for less confusion */
- } else {
- /* otherwise, set back to 164 */
- dataObject[i].max = dataObject[i].maxDefault;
- dataObject[i].spoiler = dataObject[i].spoilerDefault;
- }
- }
-
- if (i === "grubsCollected") {
- LogMissingGrubs();
- }
-
- /* textPrefix += `: ${countTotal}`; */
-
- if (i === "grubRewards") {
- dataObject[i].amountTotal = playerData.grubsCollected;
- /* textPrefix += ` / ${playerData.grubsCollected}`; */
- }
-
- if (i === "greyPrinceDefeats") {
- // backwards compatibility with earlier game versions
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- // textPrefix = `${dataObject[i].name}`;
- break;
- } else if (playerData.zoteDead === true || (playerData.zoteRescuedBuzzer === false && playerData.hasWalljump === true)) {
- dataObject[i].disabled = true;
- // textPrefix = `${textPrefix}`;
- }
- }
-
- if (i === "whiteDefenderDefeats") {
- // backwards compatibility with earlier game versions
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- // textPrefix = `${dataObject[i].name}`;
- break;
- }
- }
-
- (amount >= dataObject[i].max) ? CurrentDataTrue(section, i): CurrentDataBlank(section, i);
- break;
-
- case "geoPool":
- case "rancidEggs":
- case "jinnEggsSold":
- case "xunFlowerBrokeTimes":
- // textPrefix += ": " + Math.abs(playerData[i]);
-
- dataObject[i].amount = Math.abs(playerData[i]);
-
- (i === "geoPool" && playerData[i] > 0) ? CurrentDataBlank(section, i): CurrentDataTrue(section, i);
-
- if (i === "jinnEggsSold") {
- // fade out if not on Steel Soul
- if (playerData.permadeathMode < 1) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- // textPrefix = `${textPrefix}`;
- break;
- }
- }
-
- break;
-
- case "geoRocks":
- discoveredTotal = sceneData.geoRocks.length;
-
- notActivated = CountGeoRocks(discoveredTotal, "unbroken");
- activated = CountGeoRocks(discoveredTotal, "broken");
-
- dataObject[i].discoveredTotal = discoveredTotal;
- dataObject[i].notActivated = notActivated;
- dataObject[i].activated = activated;
-
- /* textPrefix += `: ${notActivated} | ${activated} | ${discoveredTotal}`; */
- CurrentDataTrue(section, i);
- break;
-
- case "itemsDiscovered":
- discoveredTotal = sceneData.persistentBoolItems.length;
-
- notActivated = CountItems(discoveredTotal, "notActivated");
- activated = CountItems(discoveredTotal, "active");
-
- dataObject[i].discoveredTotal = discoveredTotal;
- dataObject[i].notActivated = notActivated;
- dataObject[i].activated = activated;
-
- /* textPrefix += `: ${notActivated} | ${activated} | ${discoveredTotal}`; */
- CurrentDataTrue(section, i);
- break;
-
- case "shopkeeperKey":
- (playerData.hasSlykey === true || playerData.gaveSlykey === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "elegantKey":
- (playerData.hasWhiteKey === true || playerData.usedWhiteKey === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "loveKey":
- (playerData.hasLoveKey === true || playerData.openedLoveDoor === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "paleOreSeer": // #2
- (playerData.dreamReward3 === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- /* -------------------- Interactables ------------------------------- */
- case "simpleKeyCityOfTears": // #2
- case "simpleKeyAncientBasin": // #3
- case "paleOreAncientBasin": // #1
- case "paleOreCrystalPeak": // #3
- case "paleOreDeepnest": // #4
- case "paleOreGrubfather": // #5
- case "paleOreColosseum": // #6
- case "pantheonSoulWarrior":
- case "pantheonCrystalGuardian":
- case "pantheonEnragedGuardian":
- case "mantisVillageFloorLever":
- case "pathOfPainEntrance":
- case "whiteLadyRoom":
- case "arcaneEggLifebloodCoreRoom":
- case "throneRoomLoreTablet":
- (FindWorldItem(dataObject[i].id, dataObject[i].sceneName)) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "relicsWandererJournal":
- case "relicsHallownestSeal":
- case "relicsKingsIdol":
- case "relicsArcaneEgg":
- total = playerData[dataObject[i].nameHeld] + playerData[dataObject[i].nameSold];
-
- (total >= dataObject[i].max) ? CurrentDataTrue(section, i): CurrentDataBlank(section, i);
-
- dataObject[i].amount = total;
-
- /* textPrefix += ": " + total; */
- break;
-
- case "bossDoorStateTier5":
- if (playerData.hasOwnProperty("bossDoorStateTier5") === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- } else {
- (playerData[i].completed === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- }
- break;
-
- case "killsBindingSeal":
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- break;
- }
- (playerData[i] == 0) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "killsBigBuzzer":
- (playerData[i] == 0) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- break;
-
- case "killedVoidIdol_1":
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- break;
- }
- (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- if (playerData[i] === false && (playerData.killedVoidIdol_2 === true || playerData.killedVoidIdol_3 === true)) CurrentDataTrue(section, i);
- break;
-
- case "killedVoidIdol_2":
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- break;
- }
- (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
- if (playerData[i] === false && playerData.killedVoidIdol_3 === true) CurrentDataTrue(section, i);
- break;
-
- case "greyPrinceDefeated":
- // compatibility with earlier game versions
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- break;
- } else if (playerData.zoteDead === true || (playerData.zoteRescuedBuzzer === false && playerData.hasWalljump === true)) {
- dataObject[i].disabled = true;
- /* textPrefix = `${textPrefix}`; */
- }
- (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataBlank(section, i);
- if (playerData.zoteRescuedBuzzer === true && playerData[i] === false) CurrentDataFalse(section, i);
- break;
-
- case "zoteStatus":
- CurrentDataFalse(section, i);
- dataObject[i].name = dataObject[i].nameDefault;
- dataObject[i].spoiler = dataObject[i].spoilerDefault;
-
- if (playerData.zoteDead === true) {
- /* textPrefix = dataObject[i].nameNeglect;
- textSuffix = dataObject[i].spoilerNeglect; */
- dataObject[i].name = dataObject[i].nameNeglect;
- dataObject[i].spoiler = dataObject[i].spoilerNeglect;
-
- CurrentDataTrue(section, i);
-
- } else if (playerData.killedZote === true) {
- /* textPrefix = dataObject[i].nameRivalry;
- textSuffix = dataObject[i].spoilerRivalry; */
- dataObject[i].name = dataObject[i].nameRivalry;
- dataObject[i].spoiler = dataObject[i].spoilerRivalry;
-
- CurrentDataTrue(section, i);
-
- } else if (playerData.zoteRescuedBuzzer === false) {
- if (playerData.hasWalljump === false) {
- /* textPrefix = dataObject[i].nameTrappedVengefly;
- textSuffix = dataObject[i].spoilerTrappedVengefly; */
- dataObject[i].name = dataObject[i].nameTrappedVengefly;
- dataObject[i].spoiler = dataObject[i].spoilerTrappedVengefly;
-
- } else if (playerData.hasWalljump === true) {
- /* textPrefix = dataObject[i].nameNotRescuedVengefly;
- textSuffix = dataObject[i].spoilerNotRescuedVengefly; */
- dataObject[i].name = dataObject[i].nameNotRescuedVengefly;
- dataObject[i].spoiler = dataObject[i].spoilerNotRescuedVengefly;
- }
- } else if (playerData.zoteRescuedBuzzer === true) {
- if (playerData.zoteRescuedDeepnest === false) {
- /* textPrefix = dataObject[i].nameTrappedDeepnest;
- textSuffix = dataObject[i].spoilerTrappedDeepnest; */
- dataObject[i].name = dataObject[i].nameTrappedDeepnest;
- dataObject[i].spoiler = dataObject[i].spoilerTrappedDeepnest;
-
- } else if (playerData.zoteRescuedDeepnest === true) {
- if (playerData.killedZote === false) {
- /* textPrefix = dataObject[i].nameColosseum;
- textSuffix = dataObject[i].spoilerColosseum; */
- dataObject[i].name = dataObject[i].nameColosseum;
- dataObject[i].spoiler = dataObject[i].spoilerColosseum;
- }
- }
- }
- break;
-
- case "nailsmithStatus":
- CurrentDataFalse(section, i);
- dataObject[i].name = dataObject[i].nameDefault;
- dataObject[i].spoiler = dataObject[i].spoilerDefault;
-
- if (playerData.nailsmithKilled === true) {
- /* textPrefix = dataObject[i].namePurity;
- textSuffix = dataObject[i].spoilerPurity; */
- dataObject[i].name = dataObject[i].namePurity;
- dataObject[i].spoiler = dataObject[i].spoilerPurity;
-
- CurrentDataTrue(section, i);
-
- } else if (playerData.nailsmithConvoArt === true) {
- /* textPrefix = dataObject[i].nameHappyCouple;
- textSuffix = dataObject[i].spoilerHappyCouple; */
- dataObject[i].name = dataObject[i].nameHappyCouple;
- dataObject[i].spoiler = dataObject[i].spoilerHappyCouple;
-
- CurrentDataTrue(section, i);
-
- } else if (playerData.nailsmithSpared === true) {
- /* textPrefix = dataObject[i].nameSheoHutWaiting;
- textSuffix = dataObject[i].spoilerSheoHutWaiting; */
- dataObject[i].name = dataObject[i].nameSheoHutWaiting;
- dataObject[i].spoiler = dataObject[i].spoilerSheoHutWaiting;
-
- } else {
- /* textPrefix = dataObject[i].nameUpgradeNail;
- textSuffix = dataObject[i].spoilerUpgradeNail; */
- dataObject[i].name = dataObject[i].nameUpgradeNail;
- dataObject[i].spoiler = dataObject[i].spoilerUpgradeNail;
- }
- break;
-
- case "mrMushroomState1":
- case "mrMushroomState2":
- case "mrMushroomState3":
- case "mrMushroomState4":
- case "mrMushroomState5":
- case "mrMushroomState6":
- case "mrMushroomState7":
- CheckMrMushroomState(section, dataObject[i], playerData["mrMushroomState"]);
- break;
-
- default:
- // backwards compatibility with earlier game versions
- if (playerData.hasOwnProperty(i) === false) {
- CurrentDataBlank(section, i);
- dataObject[i].disabled = true;
- // textPrefix = `${dataObject[i].name}`;
- break;
- } else if (playerData[i] === true) {
- CurrentDataTrue(section, i);
- } else {
- CurrentDataFalse(section, i);
- }
- } // end switch (i)
-
- /* sFillText += PrepareHTMLString(section, textPrefix, textSuffix, wiki); */
- } // end for (let i in dataObject)
-
- // AppendHTML(section, sFillText);
-
- // ==========================================
- // -------------- Methods ---------------- //
-
- /**
- * Verifies if the specific Interactable (Item, Boss, Chest etc.) is activated (completed). Returns true or false.
- * @param {string} idText ID text of the Interactable (id in sceneData)
- * @param {string} sceneNameText Map codename of the Interactable (sceneName in sceneData)
- * @returns {boolean}
- */
- function FindWorldItem(idText = "", sceneNameText = "") {
- for (let i = 0, length = worldData.length; i < length; i++) {
- if (worldData[i].id === idText && worldData[i].sceneName === sceneNameText && worldData[i].activated === true) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Searches for a given item that the player has found and returns the amount of them that the player completed.
- * @param {string} itemId Name of the item
- * @returns {number}
- */
- function CountWorldItem(itemId = "") {
- let total = 0;
- for (let i = 0, length = worldData.length; i < length; i++) {
- if (worldData[i].id === itemId) {
- if (worldData[i].activated === true) total++;
- }
- }
- return total;
- }
-
- /**
- * Counts the number of maps the player has acquired (from the list in an array)
- * @param {array} mapArray Array of strings with area map names
- * @returns {number}
- */
- function CountMaps(mapArray) {
- let totalMaps = 0;
- for (let i = 0, len = mapArray.length; i < len; i++) {
- if (playerData[mapArray[i]] === true) totalMaps++;
- }
- return totalMaps;
- }
-
- /**
- * Counts the total amount of Geo Rocks Unbroken or Broken. Logs to console all the Unbroken IDs and Map locations.
- * @param {number} arrayLength How many items the Geo Rocks array is currently storing (for iteration)
- * @param {string} mode Choose which Geo Rocks to count (broken or unbroken)
- */
- function CountGeoRocks(arrayLength, mode = "unbroken") {
-
- let countTotal = 0;
- let geoRocksLog = [];
-
- if (mode === "unbroken") {
- for (let i = 0; i < arrayLength; i++) {
- if (sceneData.geoRocks[i].hitsLeft > 0) {
- countTotal++;
- geoRocksLog.push(`#${countTotal} 🏔️ ${sceneData.geoRocks[i].id} 🗺️ ${TranslateMapName(sceneData.geoRocks[i].sceneName)} ⌨️ ${sceneData.geoRocks[i].sceneName}`);
- }
- }
-
- if (!countTotal) {
- console.log("%cAll Geo Rocks Broken!", "color: #16c60c; font-weight: 700;");
- } else {
- console.groupCollapsed(`%cUnbroken Geo Rocks (${countTotal}):`, "color: #16c60c; font-weight: 700;");
-
- for (let i = 0, length = geoRocksLog.length; i < length; i++) {
- console.log(geoRocksLog[i]);
- }
-
- console.groupEnd();
- }
+ /* let {
+ textPrefix,
+ textSuffix,
+ wiki
+ } = "";
+ let sFillText = ""; */
+
+ // Start main loop
+ for (let i in dataObject) {
+ /* textPrefix = dataObject[i].name;
+ (dataObject[i].hasOwnProperty("spoiler")) ? textSuffix = dataObject[i].spoiler: textSuffix = "";
+ (dataObject[i].hasOwnProperty("wiki")) ? wiki = dataObject[i].wiki: wiki = ""; */
+
+ let {
+ amount,
+ countTotal,
+ total,
+ notActivated,
+ activated,
+ discoveredTotal
+ } = 0;
+
+ switch (i) {
+ case "areaMaps":
+ case "grubsCollected":
+ case "grubRewards":
+ case "charmsOwned":
+ case "charmSlots":
+ case "dreamOrbs":
+ case "whisperingRoots":
+ case "fountainGeo":
+ case "nailDamage":
+ case "stationsOpened":
+ case "journalEntriesCompleted":
+ case "journalNotesCompleted":
+ case "whiteDefenderDefeats":
+ case "greyPrinceDefeats":
+ if (i === "areaMaps") {
+ amount = CountMaps(dataObject[i].list);
+ } else if (i === "whisperingRoots") {
+ amount = CountWorldItem("Dream Plant");
} else {
- for (let i = 0; i < arrayLength; i++) {
- if (sceneData.geoRocks[i].hitsLeft === 0) countTotal++;
- }
+ amount = playerData[i];
}
- return countTotal;
- }
+ if (i === "stationsOpened") {
+ if (playerData.openedHiddenStation === true) amount++;
+ }
- /**
- * Counts the amount of in-game Interactables Activated or Not Activated. Logs to console all the Not Activated IDs and Map locations.
- * @param {number} arrayLength How many items the Interactables array is currently storing (for iteration)
- * @param {string} mode Choose which Interactables to count (notActivated or activated)
- */
- function CountItems(arrayLength, mode = "notActivated") {
+ countTotal = amount;
+ dataObject[i].amount = amount;
- let countTotal = 0;
- let itemsLog = [];
+ if (i === "journalEntriesCompleted" || i === "journalNotesCompleted") {
+ countTotal = `${amount} / ${playerData.journalEntriesTotal}`;
+ dataObject[i].amountTotal = playerData.journalEntriesTotal;
- if (mode === "notActivated") {
- for (let i = 0; i < arrayLength; i++) {
- if (worldData[i].activated === false &&
- worldData[i].semiPersistent === false) {
- countTotal++;
- itemsLog.push(`#${countTotal} ${worldData[i].id} 🗺️ ${TranslateMapName(worldData[i].sceneName)} ⌨️ ${worldData[i].sceneName}`);
- }
- }
+ /* when Zote is dead, the max Journal entries will equal = 160 instead of 164. For the green tick */
+ if (playerData.zoteRescuedBuzzer === false && playerData.hasWalljump === true) {
+ dataObject[i].max = dataObject[i].maxZoteOff; /* Substract GPZ and 3 Zotelings from max */
+ dataObject[i].spoiler = dataObject[i].spoilerZoteOff; /* Change spoiler for less confusion */
+ } else {
+ /* otherwise, set back to 164 */
+ dataObject[i].max = dataObject[i].maxDefault;
+ dataObject[i].spoiler = dataObject[i].spoilerDefault;
+ }
+ }
- if (!countTotal) {
- console.log("%cAll Interactables Activated!", "color: #16c60c; font-weight: 700;");
- } else {
- console.groupCollapsed(`%cNot Activated Interactables (${countTotal}):`, "color: #16c60c; font-weight: 700;");
+ if (i === "grubsCollected") {
+ LogMissingGrubs();
+ }
- for (let i = 0, length = itemsLog.length; i < length; i++) {
- console.log(itemsLog[i]);
- }
+ /* textPrefix += `: ${countTotal}`; */
- console.groupEnd();
- }
+ if (i === "grubRewards") {
+ dataObject[i].amountTotal = playerData.grubsCollected;
+ /* textPrefix += ` / ${playerData.grubsCollected}`; */
+ }
+
+ if (i === "greyPrinceDefeats") {
+ // backwards compatibility with earlier game versions
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ // textPrefix = `${dataObject[i].name}`;
+ break;
+ } else if (playerData.zoteDead === true || (playerData.zoteRescuedBuzzer === false && playerData.hasWalljump === true)) {
+ dataObject[i].disabled = true;
+ // textPrefix = `${textPrefix}`;
+ }
+ }
+
+ if (i === "whiteDefenderDefeats") {
+ // backwards compatibility with earlier game versions
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ // textPrefix = `${dataObject[i].name}`;
+ break;
+ }
+ }
+
+ (amount >= dataObject[i].max) ? CurrentDataTrue(section, i): CurrentDataBlank(section, i);
+ break;
+
+ case "geoPool":
+ case "rancidEggs":
+ case "jinnEggsSold":
+ case "xunFlowerBrokeTimes":
+ // textPrefix += ": " + Math.abs(playerData[i]);
+
+ dataObject[i].amount = Math.abs(playerData[i]);
+
+ (i === "geoPool" && playerData[i] > 0) ? CurrentDataBlank(section, i): CurrentDataTrue(section, i);
+
+ if (i === "jinnEggsSold") {
+ // fade out if not on Steel Soul
+ if (playerData.permadeathMode < 1) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ // textPrefix = `${textPrefix}`;
+ break;
+ }
+ }
+
+ break;
+
+ case "geoRocks":
+ discoveredTotal = sceneData.geoRocks.length;
+
+ notActivated = CountGeoRocks(discoveredTotal, "unbroken");
+ activated = CountGeoRocks(discoveredTotal, "broken");
+
+ dataObject[i].discoveredTotal = discoveredTotal;
+ dataObject[i].notActivated = notActivated;
+ dataObject[i].activated = activated;
+
+ /* textPrefix += `: ${notActivated} | ${activated} | ${discoveredTotal}`; */
+ CurrentDataTrue(section, i);
+ break;
+
+ case "itemsDiscovered":
+ discoveredTotal = sceneData.persistentBoolItems.length;
+
+ notActivated = CountItems(discoveredTotal, "notActivated");
+ activated = CountItems(discoveredTotal, "active");
+
+ dataObject[i].discoveredTotal = discoveredTotal;
+ dataObject[i].notActivated = notActivated;
+ dataObject[i].activated = activated;
+
+ /* textPrefix += `: ${notActivated} | ${activated} | ${discoveredTotal}`; */
+ CurrentDataTrue(section, i);
+ break;
+
+ case "shopkeeperKey":
+ (playerData.hasSlykey === true || playerData.gaveSlykey === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ case "elegantKey":
+ (playerData.hasWhiteKey === true || playerData.usedWhiteKey === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ case "loveKey":
+ (playerData.hasLoveKey === true || playerData.openedLoveDoor === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ case "paleOreSeer": // #2
+ (playerData.dreamReward3 === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ /* -------------------- Interactables ------------------------------- */
+ case "simpleKeyCityOfTears": // #2
+ case "simpleKeyAncientBasin": // #3
+ case "paleOreAncientBasin": // #1
+ case "paleOreCrystalPeak": // #3
+ case "paleOreDeepnest": // #4
+ case "paleOreGrubfather": // #5
+ case "paleOreColosseum": // #6
+ case "pantheonSoulWarrior":
+ case "pantheonCrystalGuardian":
+ case "pantheonEnragedGuardian":
+ case "mantisVillageFloorLever":
+ case "pathOfPainEntrance":
+ case "whiteLadyRoom":
+ case "arcaneEggLifebloodCoreRoom":
+ case "throneRoomLoreTablet":
+ (FindWorldItem(dataObject[i].id, dataObject[i].sceneName)) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ case "relicsWandererJournal":
+ case "relicsHallownestSeal":
+ case "relicsKingsIdol":
+ case "relicsArcaneEgg":
+ total = playerData[dataObject[i].nameHeld] + playerData[dataObject[i].nameSold];
+
+ (total >= dataObject[i].max) ? CurrentDataTrue(section, i): CurrentDataBlank(section, i);
+
+ dataObject[i].amount = total;
+
+ /* textPrefix += ": " + total; */
+ break;
+
+ case "bossDoorStateTier5":
+ if (playerData.hasOwnProperty("bossDoorStateTier5") === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
} else {
- for (let i = 0; i < arrayLength; i++) {
- if (worldData[i].activated === true) countTotal++;
- }
+ (playerData[i].completed === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
}
+ break;
- return countTotal;
- }
-
- /**
- * Compares and logs all unrescued Grubs in a list: IDs and map locations
- */
- function LogMissingGrubs() {
-
- let rescuedGrubsSceneList = [];
-
- for (let i = 0, length = worldData.length; i < length; i++) {
- if (worldData[i].id.includes("Grub Bottle")) {
- if (worldData[i].activated === true) {
- // There are 3 duplicates of the same map scene name from older game save files. Prevents adding duplicates
- /* if (worldData[i].sceneName === "Ruins2_11" && worldData[i].id === "Grub Bottle (1)") {
- continue;
- } else if (worldData[i].sceneName === "Ruins2_11" && worldData[i].id === "Grub Bottle (2)") {
- continue;
- } else { */
- rescuedGrubsSceneList.push(worldData[i].sceneName);
- // }
- }
- }
+ case "killsBindingSeal":
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
+ break;
}
+ (playerData[i] == 0) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
- // Filtering the reference database Grub list to include only the missing values
- let missingGrubsList = section.grubsList.filter(x => !rescuedGrubsSceneList.includes(x));
- let length = missingGrubsList.length;
+ case "killsBigBuzzer":
+ (playerData[i] == 0) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ break;
+
+ case "killedVoidIdol_1":
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
+ break;
+ }
+ (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ if (playerData[i] === false && (playerData.killedVoidIdol_2 === true || playerData.killedVoidIdol_3 === true)) CurrentDataTrue(section, i);
+ break;
+
+ case "killedVoidIdol_2":
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
+ break;
+ }
+ (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataFalse(section, i);
+ if (playerData[i] === false && playerData.killedVoidIdol_3 === true) CurrentDataTrue(section, i);
+ break;
+
+ case "greyPrinceDefeated":
+ // compatibility with earlier game versions
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
+ break;
+ } else if (playerData.zoteDead === true || (playerData.zoteRescuedBuzzer === false && playerData.hasWalljump === true)) {
+ dataObject[i].disabled = true;
+ /* textPrefix = `${textPrefix}`; */
+ }
+ (playerData[i] === true) ? CurrentDataTrue(section, i): CurrentDataBlank(section, i);
+ if (playerData.zoteRescuedBuzzer === true && playerData[i] === false) CurrentDataFalse(section, i);
+ break;
+
+ case "zoteStatus":
+ CurrentDataFalse(section, i);
+ dataObject[i].name = dataObject[i].nameDefault;
+ dataObject[i].spoiler = dataObject[i].spoilerDefault;
+
+ if (playerData.zoteDead === true) {
+ /* textPrefix = dataObject[i].nameNeglect;
+ textSuffix = dataObject[i].spoilerNeglect; */
+ dataObject[i].name = dataObject[i].nameNeglect;
+ dataObject[i].spoiler = dataObject[i].spoilerNeglect;
+
+ CurrentDataTrue(section, i);
+
+ } else if (playerData.killedZote === true) {
+ /* textPrefix = dataObject[i].nameRivalry;
+ textSuffix = dataObject[i].spoilerRivalry; */
+ dataObject[i].name = dataObject[i].nameRivalry;
+ dataObject[i].spoiler = dataObject[i].spoilerRivalry;
+
+ CurrentDataTrue(section, i);
+
+ } else if (playerData.zoteRescuedBuzzer === false) {
+ if (playerData.hasWalljump === false) {
+ /* textPrefix = dataObject[i].nameTrappedVengefly;
+ textSuffix = dataObject[i].spoilerTrappedVengefly; */
+ dataObject[i].name = dataObject[i].nameTrappedVengefly;
+ dataObject[i].spoiler = dataObject[i].spoilerTrappedVengefly;
+
+ } else if (playerData.hasWalljump === true) {
+ /* textPrefix = dataObject[i].nameNotRescuedVengefly;
+ textSuffix = dataObject[i].spoilerNotRescuedVengefly; */
+ dataObject[i].name = dataObject[i].nameNotRescuedVengefly;
+ dataObject[i].spoiler = dataObject[i].spoilerNotRescuedVengefly;
+ }
+ } else if (playerData.zoteRescuedBuzzer === true) {
+ if (playerData.zoteRescuedDeepnest === false) {
+ /* textPrefix = dataObject[i].nameTrappedDeepnest;
+ textSuffix = dataObject[i].spoilerTrappedDeepnest; */
+ dataObject[i].name = dataObject[i].nameTrappedDeepnest;
+ dataObject[i].spoiler = dataObject[i].spoilerTrappedDeepnest;
+
+ } else if (playerData.zoteRescuedDeepnest === true) {
+ if (playerData.killedZote === false) {
+ /* textPrefix = dataObject[i].nameColosseum;
+ textSuffix = dataObject[i].spoilerColosseum; */
+ dataObject[i].name = dataObject[i].nameColosseum;
+ dataObject[i].spoiler = dataObject[i].spoilerColosseum;
+ }
+ }
+ }
+ break;
+
+ case "nailsmithStatus":
+ CurrentDataFalse(section, i);
+ dataObject[i].name = dataObject[i].nameDefault;
+ dataObject[i].spoiler = dataObject[i].spoilerDefault;
+
+ if (playerData.nailsmithKilled === true) {
+ /* textPrefix = dataObject[i].namePurity;
+ textSuffix = dataObject[i].spoilerPurity; */
+ dataObject[i].name = dataObject[i].namePurity;
+ dataObject[i].spoiler = dataObject[i].spoilerPurity;
+
+ CurrentDataTrue(section, i);
+
+ } else if (playerData.nailsmithConvoArt === true) {
+ /* textPrefix = dataObject[i].nameHappyCouple;
+ textSuffix = dataObject[i].spoilerHappyCouple; */
+ dataObject[i].name = dataObject[i].nameHappyCouple;
+ dataObject[i].spoiler = dataObject[i].spoilerHappyCouple;
+
+ CurrentDataTrue(section, i);
+
+ } else if (playerData.nailsmithSpared === true) {
+ /* textPrefix = dataObject[i].nameSheoHutWaiting;
+ textSuffix = dataObject[i].spoilerSheoHutWaiting; */
+ dataObject[i].name = dataObject[i].nameSheoHutWaiting;
+ dataObject[i].spoiler = dataObject[i].spoilerSheoHutWaiting;
- if (!length) {
- console.log("%cAll Grubs Rescued!", "color: #16c60c; font-weight: 700;");
} else {
- console.groupCollapsed(`%cUnrescued Grubs (${length}):`, "color: #16c60c; font-weight: 700;");
+ /* textPrefix = dataObject[i].nameUpgradeNail;
+ textSuffix = dataObject[i].spoilerUpgradeNail; */
+ dataObject[i].name = dataObject[i].nameUpgradeNail;
+ dataObject[i].spoiler = dataObject[i].spoilerUpgradeNail;
+ }
+ break;
- for (let i = 0; i < length; i++) {
- console.log(`#${section.grubsList.indexOf(missingGrubsList[i]) + 1} 🗺️ ${TranslateMapName(missingGrubsList[i])} ⌨️ ${missingGrubsList[i]}`);
- }
+ case "mrMushroomState1":
+ case "mrMushroomState2":
+ case "mrMushroomState3":
+ case "mrMushroomState4":
+ case "mrMushroomState5":
+ case "mrMushroomState6":
+ case "mrMushroomState7":
+ CheckMrMushroomState(section, dataObject[i], playerData["mrMushroomState"]);
+ break;
- console.groupEnd();
+ default:
+ // backwards compatibility with earlier game versions
+ if (playerData.hasOwnProperty(i) === false) {
+ CurrentDataBlank(section, i);
+ dataObject[i].disabled = true;
+ // textPrefix = `${dataObject[i].name}`;
+ break;
+ } else if (playerData[i] === true) {
+ CurrentDataTrue(section, i);
+ } else {
+ CurrentDataFalse(section, i);
+ }
+ } // end switch (i)
+
+ /* sFillText += PrepareHTMLString(section, textPrefix, textSuffix, wiki); */
+ } // end for (let i in dataObject)
+
+ // AppendHTML(section, sFillText);
+
+ // ==========================================
+ // -------------- Methods ---------------- //
+
+ /**
+ * Verifies if the specific Interactable (Item, Boss, Chest etc.) is activated (completed). Returns true or false.
+ * @param {string} idText ID text of the Interactable (id in sceneData)
+ * @param {string} sceneNameText Map codename of the Interactable (sceneName in sceneData)
+ * @returns {boolean}
+ */
+ function FindWorldItem(idText = "", sceneNameText = "") {
+ for (let i = 0, length = worldData.length; i < length; i++) {
+ if (worldData[i].id === idText && worldData[i].sceneName === sceneNameText && worldData[i].activated === true) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Searches for a given item that the player has found and returns the amount of them that the player completed.
+ * @param {string} itemId Name of the item
+ * @returns {number}
+ */
+ function CountWorldItem(itemId = "") {
+ let total = 0;
+ for (let i = 0, length = worldData.length; i < length; i++) {
+ if (worldData[i].id === itemId) {
+ if (worldData[i].activated === true) total++;
+ }
+ }
+ return total;
+ }
+
+ /**
+ * Counts the number of maps the player has acquired (from the list in an array)
+ * @param {array} mapArray Array of strings with area map names
+ * @returns {number}
+ */
+ function CountMaps(mapArray) {
+ let totalMaps = 0;
+ for (let i = 0, len = mapArray.length; i < len; i++) {
+ if (playerData[mapArray[i]] === true) totalMaps++;
+ }
+ return totalMaps;
+ }
+
+ /**
+ * Counts the total amount of Geo Rocks Unbroken or Broken. Logs to console all the Unbroken IDs and Map locations.
+ * @param {number} arrayLength How many items the Geo Rocks array is currently storing (for iteration)
+ * @param {string} mode Choose which Geo Rocks to count (broken or unbroken)
+ */
+ function CountGeoRocks(arrayLength, mode = "unbroken") {
+
+ let countTotal = 0;
+ let geoRocksLog = [];
+
+ if (mode === "unbroken") {
+ for (let i = 0; i < arrayLength; i++) {
+ if (sceneData.geoRocks[i].hitsLeft > 0) {
+ countTotal++;
+ geoRocksLog.push(`#${countTotal} 🏔️ ${sceneData.geoRocks[i].id} 🗺️ ${TranslateMapName(sceneData.geoRocks[i].sceneName)} ⌨️ ${sceneData.geoRocks[i].sceneName}`);
+ }
+ }
+
+ if (!countTotal) {
+ console.log("%cAll Geo Rocks Broken!", "color: #16c60c; font-weight: 700;");
+ } else {
+ console.groupCollapsed(`%cUnbroken Geo Rocks (${countTotal}):`, "color: #16c60c; font-weight: 700;");
+
+ for (let i = 0, length = geoRocksLog.length; i < length; i++) {
+ console.log(geoRocksLog[i]);
}
- return false;
+ console.groupEnd();
+ }
+ } else {
+ for (let i = 0; i < arrayLength; i++) {
+ if (sceneData.geoRocks[i].hitsLeft === 0) countTotal++;
+ }
}
+
+ return countTotal;
+ }
+
+ /**
+ * Counts the amount of in-game Interactables Activated or Not Activated. Logs to console all the Not Activated IDs and Map locations.
+ * @param {number} arrayLength How many items the Interactables array is currently storing (for iteration)
+ * @param {string} mode Choose which Interactables to count (notActivated or activated)
+ */
+ function CountItems(arrayLength, mode = "notActivated") {
+
+ let countTotal = 0;
+ let itemsLog = [];
+
+ if (mode === "notActivated") {
+ for (let i = 0; i < arrayLength; i++) {
+ if (worldData[i].activated === false &&
+ worldData[i].semiPersistent === false) {
+ countTotal++;
+ itemsLog.push(`#${countTotal} ${worldData[i].id} 🗺️ ${TranslateMapName(worldData[i].sceneName)} ⌨️ ${worldData[i].sceneName}`);
+ }
+ }
+
+ if (!countTotal) {
+ console.log("%cAll Interactables Activated!", "color: #16c60c; font-weight: 700;");
+ } else {
+ console.groupCollapsed(`%cNot Activated Interactables (${countTotal}):`, "color: #16c60c; font-weight: 700;");
+
+ for (let i = 0, length = itemsLog.length; i < length; i++) {
+ console.log(itemsLog[i]);
+ }
+
+ console.groupEnd();
+ }
+ } else {
+ for (let i = 0; i < arrayLength; i++) {
+ if (worldData[i].activated === true) countTotal++;
+ }
+ }
+
+ return countTotal;
+ }
+
+ /**
+ * Compares and logs all unrescued Grubs in a list: IDs and map locations
+ */
+ function LogMissingGrubs() {
+
+ let rescuedGrubsSceneList = [];
+
+ for (let i = 0, length = worldData.length; i < length; i++) {
+ if (worldData[i].id.includes("Grub Bottle")) {
+ if (worldData[i].activated === true) {
+ // There are 3 duplicates of the same map scene name from older game save files. Prevents adding duplicates
+ /* if (worldData[i].sceneName === "Ruins2_11" && worldData[i].id === "Grub Bottle (1)") {
+ continue;
+ } else if (worldData[i].sceneName === "Ruins2_11" && worldData[i].id === "Grub Bottle (2)") {
+ continue;
+ } else { */
+ rescuedGrubsSceneList.push(worldData[i].sceneName);
+ // }
+ }
+ }
+ }
+
+ // Filtering the reference database Grub list to include only the missing values
+ let missingGrubsList = section.grubsList.filter(x => !rescuedGrubsSceneList.includes(x));
+ let length = missingGrubsList.length;
+
+ if (!length) {
+ console.log("%cAll Grubs Rescued!", "color: #16c60c; font-weight: 700;");
+ } else {
+ console.groupCollapsed(`%cUnrescued Grubs (${length}):`, "color: #16c60c; font-weight: 700;");
+
+ for (let i = 0; i < length; i++) {
+ console.log(`#${section.grubsList.indexOf(missingGrubsList[i]) + 1} 🗺️ ${TranslateMapName(missingGrubsList[i])} ⌨️ ${missingGrubsList[i]}`);
+ }
+
+ console.groupEnd();
+ }
+
+ return false;
+ }
}
/**
@@ -1580,11 +1580,11 @@ function CheckAdditionalThings(section, dataObject, playerData, worldData, scene
*/
function CheckMrMushroomState(section, entry, mrMushroomState = 0) {
- if (mrMushroomState >= entry.state) {
- CurrentDataTrue(section, `mrMushroomState${entry.state}`);
- } else {
- CurrentDataFalse(section, `mrMushroomState${entry.state}`);
- }
+ if (mrMushroomState >= entry.state) {
+ CurrentDataTrue(section, `mrMushroomState${entry.state}`);
+ } else {
+ CurrentDataFalse(section, `mrMushroomState${entry.state}`);
+ }
}
/**
@@ -1597,73 +1597,73 @@ function CheckMrMushroomState(section, entry, mrMushroomState = 0) {
*/
function CheckHintsTrue(section, dataObject, playerData, worldData) {
- /* let sFillText = ""; */
+ /* let sFillText = ""; */
- if (playerData.killedHollowKnight === true) {
- // a text to show when player already finished their first playthrough (killed Hollow Knight first time)
- /* AppendHTML(section, "...a successful Knight who doesn't need hints anymore. The Knight explores the world of Hallownest patiently in constant search of its remaining secrets..."); */
- section.current = "endOfHints";
- return true;
- }
+ if (playerData.killedHollowKnight === true) {
+ // a text to show when player already finished their first playthrough (killed Hollow Knight first time)
+ /* AppendHTML(section, "...a successful Knight who doesn't need hints anymore. The Knight explores the world of Hallownest patiently in constant search of its remaining secrets..."); */
+ section.current = "endOfHints";
+ return true;
+ }
- for (let i in dataObject) {
+ for (let i in dataObject) {
- if (i === "endOfHints") {
- break;
- } else if (playerData[i] === true) {
- continue;
- } else if (i === "fireballLevel") {
- if (playerData[i] >= 1) {
- continue;
- } else {
- section.current = i;
- break;
- }
- } else if (i === "Crossroads_04") {
- let GruzMotherDefeated = false;
+ if (i === "endOfHints") {
+ break;
+ } else if (playerData[i] === true) {
+ continue;
+ } else if (i === "fireballLevel") {
+ if (playerData[i] >= 1) {
+ continue;
+ } else {
+ section.current = i;
+ break;
+ }
+ } else if (i === "Crossroads_04") {
+ let GruzMotherDefeated = false;
- for (let k = 0, length = worldData.length; k < length; k++) {
- if (worldData[k].id === "Battle Scene" && worldData[k].sceneName === "Crossroads_04" && worldData[k].activated === true) {
- GruzMotherDefeated = true;
- break;
- }
- }
- if (GruzMotherDefeated) {
- continue; // next dataObject (i)
- } else {
- section.current = i;
- break;
- }
- } else if (i === "dungDefenderOrHornet2") {
- if (playerData.defeatedDungDefender === true) {
- continue;
- } else if (playerData.hornetOutskirtsDefeated === true) {
- continue;
- } else { // if no Dung Defender or Hornet 2
- section.current = i;
- break;
- }
- } else if (i === "ismaTearOrShadeCloak") {
- if (playerData.hasAcidArmour === true) {
- continue;
- } else if (playerData.hasKingsBrand === true) {
- if (playerData.hasShadowDash === true) {
- continue;
- } else { // if Kings Brand but no Shade Cloak
- section.current = i;
- break;
- }
- } else { // if no Isma's Tear or Kings Brand
- section.current = i;
- break;
- }
- } else { // if anything from the hints list is not done
- section.current = i;
- break;
+ for (let k = 0, length = worldData.length; k < length; k++) {
+ if (worldData[k].id === "Battle Scene" && worldData[k].sceneName === "Crossroads_04" && worldData[k].activated === true) {
+ GruzMotherDefeated = true;
+ break;
}
- } // end: for (let i in dataObject)
+ }
+ if (GruzMotherDefeated) {
+ continue; // next dataObject (i)
+ } else {
+ section.current = i;
+ break;
+ }
+ } else if (i === "dungDefenderOrHornet2") {
+ if (playerData.defeatedDungDefender === true) {
+ continue;
+ } else if (playerData.hornetOutskirtsDefeated === true) {
+ continue;
+ } else { // if no Dung Defender or Hornet 2
+ section.current = i;
+ break;
+ }
+ } else if (i === "ismaTearOrShadeCloak") {
+ if (playerData.hasAcidArmour === true) {
+ continue;
+ } else if (playerData.hasKingsBrand === true) {
+ if (playerData.hasShadowDash === true) {
+ continue;
+ } else { // if Kings Brand but no Shade Cloak
+ section.current = i;
+ break;
+ }
+ } else { // if no Isma's Tear or Kings Brand
+ section.current = i;
+ break;
+ }
+ } else { // if anything from the hints list is not done
+ section.current = i;
+ break;
+ }
+ } // end: for (let i in dataObject)
- // AppendHTML(section, sFillText);
+ // AppendHTML(section, sFillText);
} // function CheckHintsTrue()
/**
@@ -1671,33 +1671,33 @@ function CheckHintsTrue(section, dataObject, playerData, worldData) {
*/
function HKReadTextArea(textAreaId = "") {
- // start benchmark
- benchmarkTimes.HKReadTextArea.timeStart = new Date();
+ // start benchmark
+ benchmarkTimes.HKReadTextArea.timeStart = new Date();
- // starts the main HTML generating function GenerateInnerHTML() and ensures proper checkbox behaviour
- InitializeHTMLPopulation(HK);
+ // starts the main HTML generating function GenerateInnerHTML() and ensures proper checkbox behaviour
+ InitializeHTMLPopulation(HK);
- let contents = document.getElementById(textAreaId).value;
+ let contents = document.getElementById(textAreaId).value;
- if (contents.length) {
+ if (contents.length) {
- try {
- let jsonObject = JSON.parse(contents);
- // console.log(jsonObject);
- if (jsonObject.hasOwnProperty("playerData")) HKCheckCompletion(jsonObject);
- // console.log(jsonObject);
+ try {
+ let jsonObject = JSON.parse(contents);
+ // console.log(jsonObject);
+ if (jsonObject.hasOwnProperty("playerData")) HKCheckCompletion(jsonObject);
+ // console.log(jsonObject);
- // end benchmark and show results
- benchmarkTimes.HKReadTextArea.timeEnd = new Date();
+ // end benchmark and show results
+ benchmarkTimes.HKReadTextArea.timeEnd = new Date();
- console.info(`HKReadTextArea() time (ms) =`, benchmarkTimes.HKReadTextArea.timeEnd - benchmarkTimes.HKReadTextArea.timeStart);
+ console.info(`HKReadTextArea() time (ms) =`, benchmarkTimes.HKReadTextArea.timeEnd - benchmarkTimes.HKReadTextArea.timeStart);
- } catch (error) {
- HK.saveAnalyzed = false;
- alert(`This seems like not a valid Hollow Knight save.\n${error}`);
- console.info(`This seems like not a valid Hollow Knight save.\n${error}`);
- }
+ } catch (error) {
+ HK.saveAnalyzed = false;
+ alert(`This seems like not a valid Hollow Knight save.\n${error}`);
+ console.info(`This seems like not a valid Hollow Knight save.\n${error}`);
}
+ }
}
/**
@@ -1706,17 +1706,17 @@ function HKReadTextArea(textAreaId = "") {
*/
function InitializeHTMLPopulation(db) {
- GenerateInnerHTML(db);
+ GenerateInnerHTML(db);
- // Check local storage first to set proper checkbox state before the below functions start (default is always unchecked)
- if (StorageAvailable('localStorage')) {
- if (localStorage.getItem("hkCheckboxHints") === "checked") document.getElementById("checkbox-hints").checked = true;
- if (localStorage.getItem("hkCheckboxSpoilers") === "checked") document.getElementById("checkbox-spoilers").checked = true;
- }
+ // Check local storage first to set proper checkbox state before the below functions start (default is always unchecked)
+ if (StorageAvailable('localStorage')) {
+ if (localStorage.getItem("hkCheckboxHints") === "checked") document.getElementById("checkbox-hints").checked = true;
+ if (localStorage.getItem("hkCheckboxSpoilers") === "checked") document.getElementById("checkbox-spoilers").checked = true;
+ }
- // Prevents wrong checkbox behaviour (must run after everything is finished)
- CheckboxHintsToggle();
- CheckboxSpoilersToggle();
+ // Prevents wrong checkbox behaviour (must run after everything is finished)
+ CheckboxHintsToggle();
+ CheckboxSpoilersToggle();
}
/**
@@ -1725,76 +1725,76 @@ function InitializeHTMLPopulation(db) {
*/
function ResetCompletion(db) {
- let sections = db.sections;
- let entries = {};
+ let sections = db.sections;
+ let entries = {};
- db.saveAnalyzed = false;
+ db.saveAnalyzed = false;
- /* Bring Extended Completion to default values (0) */
- let gameCompletionExtended = db.sections.intro.entries.gameCompletionExtended;
- let intro = db.sections.intro;
+ /* Bring Extended Completion to default values (0) */
+ let gameCompletionExtended = db.sections.intro.entries.gameCompletionExtended;
+ let intro = db.sections.intro;
- intro.extendedCompletionDone = 0;
- intro.extendedCompletionTotal = 0;
- gameCompletionExtended.spoiler = 0;
- gameCompletionExtended.spoilerAfter = "";
+ intro.extendedCompletionDone = 0;
+ intro.extendedCompletionTotal = 0;
+ gameCompletionExtended.spoiler = 0;
+ gameCompletionExtended.spoilerAfter = "";
- for (let section in sections) {
- entries = sections[section].entries;
+ for (let section in sections) {
+ entries = sections[section].entries;
- if (sections[section].hasOwnProperty("percent")) sections[section].percent = 0;
+ if (sections[section].hasOwnProperty("percent")) sections[section].percent = 0;
- switch (section) {
- case "intro":
- case "hints":
- break;
+ switch (section) {
+ case "intro":
+ case "hints":
+ break;
- default:
+ default:
- for (let entry in entries) {
- if (entries[entry].hasOwnProperty("icon")) {
- entries[entry].icon = "red";
- }
+ for (let entry in entries) {
+ if (entries[entry].hasOwnProperty("icon")) {
+ entries[entry].icon = "red";
+ }
- if (entries[entry].hasOwnProperty("disabled")) {
- entries[entry].disabled = false;
- }
+ if (entries[entry].hasOwnProperty("disabled")) {
+ entries[entry].disabled = false;
+ }
- if (entries[entry].hasOwnProperty("amount")) {
- entries[entry].amount = 0;
- }
+ if (entries[entry].hasOwnProperty("amount")) {
+ entries[entry].amount = 0;
+ }
- if (entries[entry].hasOwnProperty("amountTotal")) {
- entries[entry].amountTotal = 0;
- }
+ if (entries[entry].hasOwnProperty("amountTotal")) {
+ entries[entry].amountTotal = 0;
+ }
- if (entry.hasOwnProperty("currentName")) {
- delete entries[entry].currentName;
- }
+ if (entry.hasOwnProperty("currentName")) {
+ delete entries[entry].currentName;
+ }
- if (entry.hasOwnProperty("currentSpoiler")) {
- delete entries[entry].currentSpoiler;
- }
- }
+ if (entry.hasOwnProperty("currentSpoiler")) {
+ delete entries[entry].currentSpoiler;
+ }
}
}
+ }
}
/* ----------------------- Event Listeners -------------------------- */
// Populate HTML at load (before img and css)
document.addEventListener("DOMContentLoaded", () => {
- InitializeHTMLPopulation(HK);
+ InitializeHTMLPopulation(HK);
});
// Analyze Text button
document.getElementById("save-area-read").addEventListener("click", () => {
- HKReadTextArea("save-area");
+ HKReadTextArea("save-area");
}, false);
export {
- // to use in LoadSaveFile.js for auto-analyzing file after decoding
- HKCheckCompletion,
- benchmarkTimes,
- Benchmark
+ // to use in LoadSaveFile.js for auto-analyzing file after decoding
+ HKCheckCompletion,
+ benchmarkTimes,
+ Benchmark
};
\ No newline at end of file
diff --git a/src/js/LoadJson.js b/src/js/LoadJson.js
index 07bd5fe..ea35089 100644
--- a/src/js/LoadJson.js
+++ b/src/js/LoadJson.js
@@ -2,21 +2,21 @@
// save file names list in the save/ folder
var fileName = [
- "reznor0", // 0
- "reznor1beforegruz", // 1
- "reznor2aftergruz", // 2
- "reznor5hornet", // 3
- "reznor29ss", // 4
- "ext48", // 5
- "reznor88banish", // 6
- "reznor99whitefragment", // 7
- "reznor100", // 8
- "reznor103ss", // 9
- "reznor107", // 10
- "reznor112grimm", // 11
- "PoP/kanna", // 12
- "PoP/Reaper4578", // 13
- "PoP/tintingaroo", // 14
+ "reznor0", // 0
+ "reznor1beforegruz", // 1
+ "reznor2aftergruz", // 2
+ "reznor5hornet", // 3
+ "reznor29ss", // 4
+ "ext48", // 5
+ "reznor88banish", // 6
+ "reznor99whitefragment", // 7
+ "reznor100", // 8
+ "reznor103ss", // 9
+ "reznor107", // 10
+ "reznor112grimm", // 11
+ "PoP/kanna", // 12
+ "PoP/Reaper4578", // 13
+ "PoP/tintingaroo", // 14
];
/**
@@ -25,40 +25,40 @@ var fileName = [
* @param callback Function to be called when the request completes
*/
function LoadJSON(filename) {
- // new Http request object (asynchronous), both the web page and the XML file it tries to load, must be located on the same server.
- var xobj = new XMLHttpRequest();
+ // new Http request object (asynchronous), both the web page and the XML file it tries to load, must be located on the same server.
+ var xobj = new XMLHttpRequest();
- xobj.overrideMimeType("application/json");
+ xobj.overrideMimeType("application/json");
- // Specifies the request
- /* method: the request type GET or POST
- url: the file location
- async: true (asynchronous) or false (synchronous)
- user: optional user name
- psw: optional password */
- xobj.open('GET', filename, true); // Path to the file
+ // Specifies the request
+ /* method: the request type GET or POST
+ url: the file location
+ async: true (asynchronous) or false (synchronous)
+ user: optional user name
+ psw: optional password */
+ xobj.open('GET', filename, true); // Path to the file
- // Sends the request to the server - Used for GET requests
- xobj.send(null);
+ // Sends the request to the server - Used for GET requests
+ xobj.send(null);
- // Defines a function to be called when the readyState property changes
- /* xobj.onreadystatechange = function GetResponseText() {
- if (xobj.readyState == 4 && xobj.status == "200") {
- // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
- // Returns the response data as a string
- return callback(xobj.responseText);
- } else return false;
- }; */
- // Sends the request to the server - Used for GET requests
- // xobj.send(null);
+ // Defines a function to be called when the readyState property changes
+ /* xobj.onreadystatechange = function GetResponseText() {
+ if (xobj.readyState == 4 && xobj.status == "200") {
+ // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
+ // Returns the response data as a string
+ return callback(xobj.responseText);
+ } else return false;
+ }; */
+ // Sends the request to the server - Used for GET requests
+ // xobj.send(null);
- xobj.onload = function JSONparse() {
- // Parse JSON string into object
- const jsonObject = JSON.parse(xobj.responseText);
- document.getElementById("save-area").value = JSON.stringify(jsonObject);
- return jsonObject;
- // console.log(jsonObj);
- };
+ xobj.onload = function JSONparse() {
+ // Parse JSON string into object
+ const jsonObject = JSON.parse(xobj.responseText);
+ document.getElementById("save-area").value = JSON.stringify(jsonObject);
+ return jsonObject;
+ // console.log(jsonObj);
+ };
}
/* function JSONparse(response) {
@@ -77,37 +77,37 @@ LoadJSON("../save/" + fileName[11] + ".json");
* @param {string} filename Path and .xml file name to be loaded
*/
function XMLtoJSON(filename) {
-
- var request = new XMLHttpRequest();
- request.open('GET', filename, true); // Path to the file
+ var request = new XMLHttpRequest();
- request.send();
+ request.open('GET', filename, true); // Path to the file
- request.onload = function XMLparse() {
+ request.send();
- const xml = request.responseXML;
+ request.onload = function XMLparse() {
- // console.log(xml);
+ const xml = request.responseXML;
- let dictionary = xml.getElementsByTagName("Entry");
-
- let oldName = "";
- let newName = "";
- let dictionaryObject = new Object();
+ // console.log(xml);
- for (let i = 0, length = dictionary.length; i < length; i++) {
-
- oldName = dictionary[i].getElementsByTagName("oldName")[0].childNodes[0].nodeValue;
- newName = dictionary[i].getElementsByTagName("newName")[0].childNodes[0].nodeValue;
+ let dictionary = xml.getElementsByTagName("Entry");
- dictionaryObject[oldName] = newName;
- }
+ let oldName = "";
+ let newName = "";
+ let dictionaryObject = new Object();
- // console.log(JSON.stringify(dictionaryObject));
+ for (let i = 0, length = dictionary.length; i < length; i++) {
- return dictionaryObject;
- };
+ oldName = dictionary[i].getElementsByTagName("oldName")[0].childNodes[0].nodeValue;
+ newName = dictionary[i].getElementsByTagName("newName")[0].childNodes[0].nodeValue;
+
+ dictionaryObject[oldName] = newName;
+ }
+
+ // console.log(JSON.stringify(dictionaryObject));
+
+ return dictionaryObject;
+ };
}
// XMLtoJSON("../files/TranslatorDictionary.xml");
\ No newline at end of file
diff --git a/src/js/LoadSaveFile.js b/src/js/LoadSaveFile.js
index 7003720..a8aa48b 100644
--- a/src/js/LoadSaveFile.js
+++ b/src/js/LoadSaveFile.js
@@ -10,9 +10,9 @@
const aesjs = require("./aes-js.js");
// For reading the text area after save decoding
import {
- HKCheckCompletion,
- benchmarkTimes,
- Benchmark
+ HKCheckCompletion,
+ benchmarkTimes,
+ Benchmark
} from "./HKCheckCompletion.js";
const CSHARP_HEADER = [0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0]; // 22 bytes
@@ -37,31 +37,31 @@ const ECB_STREAM_CIPHER = new aesjs.ModeOfOperation.ecb(AES_KEY); // create a ne
// eslint-disable-next-line no-unused-vars
function LoadSaveFile(input, time) {
- const inputFileList = input.files;
- // console.info("Input length: " + input.files.length)
- // Cease further processing if user canceled the file input dialog
- if (inputFileList.length < 1) return false;
+ const inputFileList = input.files;
+ // console.info("Input length: " + input.files.length)
+ // Cease further processing if user canceled the file input dialog
+ if (inputFileList.length < 1) return false;
- // start benchmark
- benchmarkTimes.LoadSaveFile.timeStart = time;
- benchmarkTimes.Total.timeStart = time;
+ // start benchmark
+ benchmarkTimes.LoadSaveFile.timeStart = time;
+ benchmarkTimes.Total.timeStart = time;
- // Prepares a File object from the first file of the input files for reading as an Array Buffer
- let inputFileObject = inputFileList[0];
+ // Prepares a File object from the first file of the input files for reading as an Array Buffer
+ let inputFileObject = inputFileList[0];
- // Cleans the file list to avoid problems after subsequent use
- // document.getElementById("save-area-file").value = "";
+ // Cleans the file list to avoid problems after subsequent use
+ // document.getElementById("save-area-file").value = "";
- // 1. read file
- // The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
- // It is an array of bytes, often referred to in other languages as a "byte array".
+ // 1. read file
+ // The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.
+ // It is an array of bytes, often referred to in other languages as a "byte array".
- // new FileReader()
- let inputReader = new FileReader();
- // readAsArrayBuffer(file)
- inputReader.readAsArrayBuffer(inputFileObject);
- // addEventListener("load", function) - to decode the file when loaded
- inputReader.addEventListener("load", ProcessFileObject);
+ // new FileReader()
+ let inputReader = new FileReader();
+ // readAsArrayBuffer(file)
+ inputReader.readAsArrayBuffer(inputFileObject);
+ // addEventListener("load", function) - to decode the file when loaded
+ inputReader.addEventListener("load", ProcessFileObject);
}
/**
@@ -69,62 +69,62 @@ function LoadSaveFile(input, time) {
* Launches the HKReadTextArea() function automatically after pasting the string to text area
*/
function ProcessFileObject() {
- let inputArrayBuffer = this.result;
- let decodedString;
+ let inputArrayBuffer = this.result;
+ let decodedString;
- // 2. Decode file
+ // 2. Decode file
+ try {
+ // Uint8Array(ArrayBuffer) uint8_t equivalent in C
+ inputArrayBuffer = new Uint8Array(inputArrayBuffer);
+
+ // ArrayBuffer.slice()
+ // The slice() method copies up to, but not including, the byte indicated by the end parameter.
+ inputArrayBuffer.slice();
+
+ // remove C# header and LengthPrefixedString header (ArrayBuffer)
+ inputArrayBuffer = RemoveHeaders(inputArrayBuffer);
+
+ // base64 Decoding (ArrayBuffer)
+ inputArrayBuffer = Base64Decode(inputArrayBuffer);
+
+ // AES decryption (ECB) removes pkcs7 padding (ArrayBuffer)
+ inputArrayBuffer = AESDecryption(inputArrayBuffer);
+
+ // Convert ArrayBuffer to string/text TextDecoder().decode(ArrayBuffer)
+ decodedString = new TextDecoder().decode(inputArrayBuffer);
+
+ // finish and show benchmark
+ /* benchLSFEnd = new Date(); */
+ benchmarkTimes.LoadSaveFile.timeEnd = new Date();
+ /* console.info("LoadSaveFile() time (ms) =", benchLSFEnd - benchLSFBegin); */
+
+ // 4. Analyze the decoded string immediately
try {
- // Uint8Array(ArrayBuffer) uint8_t equivalent in C
- inputArrayBuffer = new Uint8Array(inputArrayBuffer);
-
- // ArrayBuffer.slice()
- // The slice() method copies up to, but not including, the byte indicated by the end parameter.
- inputArrayBuffer.slice();
-
- // remove C# header and LengthPrefixedString header (ArrayBuffer)
- inputArrayBuffer = RemoveHeaders(inputArrayBuffer);
-
- // base64 Decoding (ArrayBuffer)
- inputArrayBuffer = Base64Decode(inputArrayBuffer);
-
- // AES decryption (ECB) removes pkcs7 padding (ArrayBuffer)
- inputArrayBuffer = AESDecryption(inputArrayBuffer);
-
- // Convert ArrayBuffer to string/text TextDecoder().decode(ArrayBuffer)
- decodedString = new TextDecoder().decode(inputArrayBuffer);
-
- // finish and show benchmark
- /* benchLSFEnd = new Date(); */
- benchmarkTimes.LoadSaveFile.timeEnd = new Date();
- /* console.info("LoadSaveFile() time (ms) =", benchLSFEnd - benchLSFBegin); */
-
- // 4. Analyze the decoded string immediately
- try {
- HKCheckCompletion(JSON.parse(decodedString));
- } catch (error) {
- alert(`This seems like not a valid Hollow Knight save. ${error}`);
- console.info(`This seems like not a valid Hollow Knight save. ${error}`);
- }
-
- // 5. Paste decoded string file to text area
- (async () => {
- document.getElementById("save-area").value = "";
- document.getElementById("save-area").value = await decodedString;
- })();
-
- // finish total and show benchmark
- benchmarkTimes.Total.timeEnd = new Date();
-
- Benchmark(benchmarkTimes);
- /* console.info("Total time (ms) =", benchTotal - benchLSFBegin); */
-
- // alert(`Decoded String: ${decodedString}`);
- // alert(`Array Buffer: ${inputArrayBuffer}`);
+ HKCheckCompletion(JSON.parse(decodedString));
} catch (error) {
- alert(`The file cannot be decoded. ${error}`);
- console.info(`The file cannot be decoded. ${error}`);
+ alert(`This seems like not a valid Hollow Knight save. ${error}`);
+ console.info(`This seems like not a valid Hollow Knight save. ${error}`);
}
+
+ // 5. Paste decoded string file to text area
+ (async () => {
+ document.getElementById("save-area").value = "";
+ document.getElementById("save-area").value = await decodedString;
+ })();
+
+ // finish total and show benchmark
+ benchmarkTimes.Total.timeEnd = new Date();
+
+ Benchmark(benchmarkTimes);
+ /* console.info("Total time (ms) =", benchTotal - benchLSFBegin); */
+
+ // alert(`Decoded String: ${decodedString}`);
+ // alert(`Array Buffer: ${inputArrayBuffer}`);
+ } catch (error) {
+ alert(`The file cannot be decoded. ${error}`);
+ console.info(`The file cannot be decoded. ${error}`);
+ }
}
/**
@@ -134,19 +134,19 @@ function ProcessFileObject() {
* @returns {Uint8Array}
*/
function RemoveHeaders(buffer, csHeader = CSHARP_HEADER) {
- // Remove the fixed C# header and byte 11 at the end.
- buffer = buffer.subarray(csHeader.length, buffer.length - 1);
+ // Remove the fixed C# header and byte 11 at the end.
+ buffer = buffer.subarray(csHeader.length, buffer.length - 1);
- // Remove LengthPrefixedString header
- let lengthCount = 0;
- for (let i = 0; i < 5; i++) {
- lengthCount++;
- if ((buffer[i] & 0x80) == 0) {
- break;
- }
+ // Remove LengthPrefixedString header
+ let lengthCount = 0;
+ for (let i = 0; i < 5; i++) {
+ lengthCount++;
+ if ((buffer[i] & 0x80) == 0) {
+ break;
}
+ }
- return buffer.subarray(lengthCount);
+ return buffer.subarray(lengthCount);
}
/**
@@ -155,39 +155,39 @@ function RemoveHeaders(buffer, csHeader = CSHARP_HEADER) {
* @returns {Uint8Array}
*/
function Base64Decode(buffer) {
- buffer = new Uint8Array(buffer).slice();
- buffer = buffer.map(v => BASE64_DECODE_TABLE.get(v));
+ buffer = new Uint8Array(buffer).slice();
+ buffer = buffer.map(v => BASE64_DECODE_TABLE.get(v));
- // The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
- let p = buffer.indexOf(64);
- let end;
+ // The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
+ let p = buffer.indexOf(64);
+ let end;
- if (p != -1) {
- end = p;
- } else {
- end = buffer.length;
+ if (p != -1) {
+ end = p;
+ } else {
+ end = buffer.length;
+ }
+
+ buffer = buffer.subarray(0, end);
+
+ let output = new Uint8Array(3 * buffer.length / 4);
+ let continuous = Math.floor(buffer.length / 4) * 4;
+
+ for (let i = 0; i < continuous; i += 4) {
+ let k = 3 * i / 4;
+ output[k] = buffer[i] << 2 | buffer[i + 1] >> 4;
+ output[k + 1] = (buffer[i + 1] & 0x0F) << 4 | buffer[i + 2] >> 2;
+ output[k + 2] = (buffer[i + 2] & 0x03) << 6 | buffer[i + 3];
+ }
+ if (buffer[continuous] != undefined) {
+ let k = 3 * continuous / 4;
+ output[k] = buffer[continuous] << 2 | buffer[continuous + 1] >> 4;
+ if (buffer[continuous + 2] != undefined) {
+ output[k + 1] = (buffer[continuous + 1] & 0x0F) << 4 | buffer[continuous + 2] >> 2;
}
+ }
- buffer = buffer.subarray(0, end);
-
- let output = new Uint8Array(3 * buffer.length / 4);
- let continuous = Math.floor(buffer.length / 4) * 4;
-
- for (let i = 0; i < continuous; i += 4) {
- let k = 3 * i / 4;
- output[k] = buffer[i] << 2 | buffer[i + 1] >> 4;
- output[k + 1] = (buffer[i + 1] & 0x0F) << 4 | buffer[i + 2] >> 2;
- output[k + 2] = (buffer[i + 2] & 0x03) << 6 | buffer[i + 3];
- }
- if (buffer[continuous] != undefined) {
- let k = 3 * continuous / 4;
- output[k] = buffer[continuous] << 2 | buffer[continuous + 1] >> 4;
- if (buffer[continuous + 2] != undefined) {
- output[k + 1] = (buffer[continuous + 1] & 0x0F) << 4 | buffer[continuous + 2] >> 2;
- }
- }
-
- return output;
+ return output;
}
/**
@@ -196,18 +196,18 @@ function Base64Decode(buffer) {
* @returns {Uint8Array}
*/
function AESDecryption(buffer, cipherObject = ECB_STREAM_CIPHER) {
- let output = cipherObject.decrypt(buffer);
- return output.subarray(0, -output[output.length - 1]);
+ let output = cipherObject.decrypt(buffer);
+ return output.subarray(0, -output[output.length - 1]);
}
// Assign actions (functions) to launch when a specific element is used
document.getElementById("save-area-file").addEventListener("change", (event) => {
- LoadSaveFile(event.target, new Date());
+ LoadSaveFile(event.target, new Date());
});
document.getElementById("save-area-file").addEventListener("click", (mouseEvent) => {
- mouseEvent.target.value = "";
+ mouseEvent.target.value = "";
});
export {
- LoadSaveFile
+ LoadSaveFile
};
\ No newline at end of file
diff --git a/src/js/hk-dictionary.js b/src/js/hk-dictionary.js
index 4efc2e0..8635581 100644
--- a/src/js/hk-dictionary.js
+++ b/src/js/hk-dictionary.js
@@ -1,399 +1,399 @@
/* Huge thanks to ManicJamie for his HKTranslator: https://github.com/ManicJamie/HKTranslator */
const MAP = {
- "Tutorial_01": "King's Pass",
- "Town": "Dirtmouth",
- "Room_shop": "Sly's Shop",
- "Room_Sly_Storeroom": "Sly's Shop Basement",
- "Room_Town_Stag_Station": "Dirtmouth Stag Station",
- "Room_mapper": "Iselda's Shop",
- "Room_Bretta": "Bretta's Room",
- "Room_Bretta_Basement": "Bretta's Room Basement",
- "Room_Ouiji": "Jiji's Hut",
- "Room_Jinn": "Jinn's Hut",
- "Room_Tram_RG": "Upper Tram",
- "Room_Tram": "Lower Tram",
- "Crossroads_01": "Crossroads Well",
- "Crossroads_02": "Crossroads Outside Temple",
- "Crossroads_03": "Crossroads Outside Stag",
- "Crossroads_04": "Crossroads Gruz Mother",
- "Crossroads_05": "Crossroads Central Grub",
- "Crossroads_06": "Crossroads Outside Mound",
- "Crossroads_07": "Crossroads Gruzzer",
- "Crossroads_08": "Crossroads Aspid Arena",
- "Crossroads_09": "Crossroads Mawlek Boss",
- "Crossroads_10": "Crossroads False Knight Arena",
- "Crossroads_11_alt": "Crossroads Greenpath Entrance",
- "Crossroads_12": "Crossroads Corridor to Acid Grub",
- "Crossroads_13": "Crossroads Goam Mask Shard",
- "Crossroads_14": "Crossroads Outside Myla",
- "Crossroads_15": "Crossroads Corridor to Tram",
- "Crossroads_16": "Crossroads Above Lever",
- "Crossroads_18": "Crossroads Fungal Entrance",
- "Crossroads_19": "Crossroads Before Gruz Mother",
- "Crossroads_21": "Crossroads Outside False Knight",
- "Crossroads_22": "Crossroads Glowing Womb Arena",
- "Crossroads_25": "Crossroads Mawlek Entrance",
- "Crossroads_27": "Crossroads Outside Tram",
- "Crossroads_30": "Crossroads Hot Spring",
- "Crossroads_31": "Crossroads Spike Grub",
- "Crossroads_33": "Crossroads Cornifer",
- "Crossroads_35": "Crossroads Acid Grub",
- "Crossroads_36": "Crossroads Mawlek Middle",
- "Crossroads_37": "Crossroads Vessel Fragment",
- "Crossroads_38": "Crossroads Grubfather",
- "Crossroads_39": "Crossroads Corridor Right of Temple",
- "Crossroads_40": "Crossroads Corridor Right of Central Grub",
- "Crossroads_42": "Crossroads Right Of Mask Shard",
- "Crossroads_43": "Crossroads Corridor to Elevator",
- "Crossroads_45": "Crossroads Myla",
- "Crossroads_46": "Crossroads Tram",
- "Crossroads_47": "Crossroads Stag",
- "Crossroads_48": "Crossroads Guarded Grub",
- "Crossroads_49": "Crossroads Elevator",
- "Crossroads_52": "Crossroads Goam Journal",
- "Crossroads_ShamanTemple": "Crossroads Ancestral Mound",
- "Room_Mender_House": "Crossroads Menderbug",
- "Room_Charm_Shop": "Crossroads Salubra",
- "Room_ruinhouse": "Crossroads Rescue Sly",
- "Room_temple": "Crossroads Inside Temple",
- "Fungus1_01": "Greenpath Entrance",
- "Fungus1_01b": "Greenpath Waterfall Bench",
- "Fungus1_02": "Greenpath First Hornet Sighting",
- "Fungus1_03": "Greenpath Storerooms",
- "Fungus1_04": "Greenpath Hornet",
- "Fungus1_05": "Greenpath Outside Thorns",
- "Fungus1_06": "Greenpath Cornifer",
- "Fungus1_07": "Greenpath Outside Hunter",
- "Fungus1_08": "Greenpath Hunter",
- "Fungus1_09": "Greenpath Sheo Gauntlet",
- "Fungus1_10": "Greenpath Acid Bridge",
- "Fungus1_11": "Greenpath Above Fog Canyon",
- "Fungus1_12": "Greenpath MMC Corridor",
- "Fungus1_13": "Greenpath Whispering Root",
- "Fungus1_14": "Greenpath Thorns of Agony",
- "Fungus1_15": "Greenpath Outside Sheo",
- "Fungus1_16_alt": "Greenpath Stag",
- "Fungus1_17": "Greenpath Charger Corridor",
- "Fungus1_19": "Greenpath Above Sanctuary Bench",
- "Fungus1_20_v02": "Greenpath Vengefly King",
- "Fungus1_21": "Greenpath Outside Hornet",
- "Fungus1_22": "Greenpath Outside Stag",
- "Fungus1_25": "Greenpath Corridor to Unn",
- "Fungus1_26": "Greenpath Lake Of Unn",
- "Fungus1_29": "Greenpath Massive Moss Charger",
- "Fungus1_30": "Greenpath Below Toll Bench",
- "Fungus1_31": "Greenpath Toll",
- "Fungus1_32": "Greenpath Moss Knight Arena",
- "Fungus1_34": "Greenpath Stone Sanctuary Entrance",
- "Fungus1_35": "Greenpath Stone Sanctuary",
- "Fungus1_36": "Greenpath Stone Sanctuary Mask Shard",
- "Fungus1_37": "Greenpath Sanctuary Bench",
- "Fungus1_Slug": "Greenpath Unn",
- "Room_nailmaster_02": "Greenpath Sheo",
- "Room_Slug_Shrine": "Greenpath Unn Bench",
- "Deepnest_01": "Fungal_Deepnest_Fall",
- "Fungus2_01": "Fungal_Queen's_Station",
- "Fungus2_02": "Fungal_Queen's_Stag",
- "Fungus2_03": "Fungal_Outside_Queen's",
- "Fungus2_04": "Fungal_Below_Ogres",
- "Fungus2_05": "Fungal_Shrumal_Ogres",
- "Fungus2_06": "Fungal_Outside_Leg_Eater",
- "Fungus2_07": "Fungal_Shrumal_Warrior_Acid_Bridge",
- "Fungus2_08": "Fungal_Outside_Elder_Hu",
- "Fungus2_09": "Fungal_Cloth_Corridor",
- "Fungus2_10": "Fungal_Left_Of_Pilgrim's_Way",
- "Fungus2_11": "Fungal_Right_of_Bouncy_Grub",
- "Fungus2_12": "Fungal_Mantis_Corridor",
- "Fungus2_13": "Fungal_Bretta_Bench",
- "Fungus2_14": "Fungal_Mantis_Village",
- "Fungus2_15": "Fungal_Mantis_Lords",
- "Fungus2_17": "Fungal_Above_Mantis_Village",
- "Fungus2_18": "Fungal_Cornifer",
- "Fungus2_19": "Fungal_Right_Of_Spore_Shroom",
- "Fungus2_20": "Fungal_Spore_Shroom",
- "Fungus2_21": "Fungal_Pilgrim's_Way",
- "Fungus2_23": "Fungal_Dashmaster",
- "Fungus2_26": "Fungal_Leg_Eater",
- "Fungus2_28": "Fungal_Shrumal_Warrior_Loop",
- "Fungus2_29": "Fungal_Core_Upper",
- "Fungus2_30": "Fungal_Core_Lower",
- "Fungus2_31": "Fungal_Mantis_Rewards",
- "Fungus2_32": "Fungal_Elder_Hu",
- "Fungus2_33": "Fungal_Leg_Eater_Root",
- "Fungus2_34": "Fungal_Willoh",
- "Fungus3_01": "Fog_Upper_West_Tall",
- "Fungus3_02": "Fog_Lower_West_Tall",
- "Fungus3_03": "Fog_Queen's_Gardens_Acid_Entrance",
- "Fungus3_24": "Fog_Corridor_to_Overgrown_Mound",
- "Fungus3_25": "Fog_Cornifer",
- "Fungus3_25b": "Fog_Corridor_to_Cornifer",
- "Fungus3_26": "Fog_East_Tall",
- "Fungus3_27": "Fog_Corridor_to_Archives",
- "Fungus3_28": "Fog_Charm_Notch",
- "Fungus3_30": "Fog_Lifeblood",
- "Fungus3_35": "Fog_Millibelle",
- "Fungus3_44": "Fog_Overgrown_Mound_Entrance",
- "Fungus3_47": "Fog_Archives_Entrance",
- "Fungus3_archive": "Fog_Archives_Bench",
- "Fungus3_archive_02": "Fog_Uumuu_Arena",
- "Room_Fungus_Shaman": "Fog_Overgrown_Mound",
- "Cliffs_01": "Cliffs_Main",
- "Cliffs_02": "Cliffs_Gorb",
- "Cliffs_03": "Cliffs_Stag_Nest",
- "Cliffs_04": "Cliffs_Joni's_Dark",
- "Cliffs_05": "Cliffs_Joni's_Pickup",
- "Cliffs_06": "Cliffs_Grimm_Lantern",
- "Fungus1_28": "Cliffs_Baldur's_Shell",
- "Room_nailmaster": "Cliffs_Mato",
- "Mines_01": "Crystal_Dive_Entrance",
- "Mines_02": "Crystal_Dark_Entrance",
- "Mines_03": "Crystal_Spike_Grub",
- "Mines_04": "Crystal_Entrance_Conveyors",
- "Mines_05": "Crystal_Above_Spike_Grub",
- "Mines_06": "Crystal_Deep_Focus_Gauntlet",
- "Mines_07": "Crystal_Dark_Room",
- "Mines_10": "Crystal_Elevator_Entrance",
- "Mines_11": "Crystal_Left_Of_Guardian",
- "Mines_13": "Crystal_Top_Corridor",
- "Mines_16": "Crystal_Mimic",
- "Mines_17": "Crystal_Corridor_to_Spike_Grub",
- "Mines_18": "Crystal_Guardian_Bench",
- "Mines_19": "Crystal_Grub_Crushers",
- "Mines_20": "Crystal_East_Tall",
- "Mines_23": "Crystal_Crown_Whispering_Root",
- "Mines_24": "Crystal_Crown_Grub",
- "Mines_25": "Crystal_Crown_Climb",
- "Mines_28": "Crystal_Outside_Mound",
- "Mines_29": "Crystal_Dark_Bench",
- "Mines_30": "Crystal_Cornifer",
- "Mines_31": "Crystal_Crystal_Heart_Gauntlet",
- "Mines_32": "Crystal_Enraged_Guardian_Arena",
- "Mines_33": "Crossroads_Peak_Dark_Toll",
- "Mines_34": "Crystal_Crown_Peak",
- "Mines_35": "Crystal_Mound",
- "Mines_36": "Crystal_Deep_Focus",
- "Mines_37": "Crystal_Chest_Crushers",
- "Abyss_02": "Basin_Broken_Bridge",
- "Abyss_03": "Basin_Tram",
- "Abyss_04": "Basin_Fountain",
- "Abyss_05": "Basin_Palace_Grounds",
- "Abyss_17": "Basin_Cloth",
- "Abyss_18": "Basin_Corridor_to_Broken_Vessel",
- "Abyss_19": "Basin_Broken_Vessel_Grub",
- "Abyss_20": "Basin_Simple_Key",
- "Abyss_21": "Basin_Monarch_Wings",
- "Abyss_22": "Basin_Hidden_Station",
- "Abyss_06_Core": "Abyss_Core",
- "Abyss_08": "Abyss_Lifeblood_Core",
- "Abyss_09": "Abyss_Lighthouse_Climb",
- "Abyss_10": "Abyss_Shade_Cloak",
- "Abyss_12": "Abyss_Shriek",
- "Abyss_15": "Abyss_Birthplace",
- "Abyss_16": "Abyss_Corridor_to_Lighthouse",
- "Abyss_Lighthouse_room": "Abyss_Lighthouse",
- "Crossroads_46b": "Grounds_Tram",
- "Crossroads_50": "Grounds_Blue_Lake",
- "RestingGrounds_02": "Grounds_Xero",
- "RestingGrounds_04": "Grounds_Dream_Nail_Entrance",
- "RestingGrounds_05": "Grounds_Whispering_Root",
- "RestingGrounds_06": "Grounds_Corridor_Below_Xero",
- "RestingGrounds_07": "Grounds_Seer",
- "RestingGrounds_08": "Grounds_Spirit's_Glade",
- "RestingGrounds_09": "Grounds_Stag",
- "RestingGrounds_10": "Grounds_Crypts",
- "RestingGrounds_12": "Grounds_Outside_Grey_Mourner",
- "RestingGrounds_17": "Grounds_Dreamshield",
- "Room_Mansion": "Grounds_Grey_Mourner",
- "Ruins2_10": "Grounds_Elevator",
- "Abyss_03_c": "Edge_Tram",
- "Deepnest_East_01": "Edge_Left_Of_Hive",
- "Deepnest_East_02": "Edge_Above_Hive",
- "Deepnest_East_03": "Edge_Entrance",
- "Deepnest_East_04": "Edge_Bardoon",
- "Deepnest_East_06": "Edge_Outside_Oro",
- "Deepnest_East_07": "Edge_Whispering_Root",
- "Deepnest_East_08": "Edge_Great_Hopper_Idol",
- "Deepnest_East_09": "Edge_Corridor_Outside_Colosseum",
- "Deepnest_East_10": "Edge_Markoth_Arena",
- "Deepnest_East_11": "Edge_Below_Camp_Bench",
- "Deepnest_East_12": "Edge_Hornet_Sentinel_Corridor",
- "Deepnest_East_13": "Edge_Camp_Bench",
- "Deepnest_East_14": "Edge_Below_Oro",
- "Deepnest_East_14b": "Edge_Quick_Slash",
- "Deepnest_East_15": "Edge_Lifeblood",
- "Deepnest_East_16": "Edge_Oro_Scarecrow",
- "Deepnest_East_17": "Edge_420_Geo_Rock",
- "Deepnest_East_18": "Edge_Outside_Markoth",
- "Deepnest_East_Hornet": "Edge_Hornet_Sentinel_Arena",
- "GG_Lurker": "Edge_Pale_Lurker",
- "Room_Colosseum_01": "Edge_Colo_Entrance",
- "Room_Colosseum_02": "Edge_Colo_Bench",
- "Room_Colosseum_Bronze": "Edge_Colo_1_Arena",
- "Room_Colosseum_Gold": "Edge_Colo_3_Arena",
- "Room_Colosseum_Silver": "Edge_Colo_2_Arena",
- "Room_Colosseum_Spectate": "Edge_Colo_Spectate",
- "Room_nailmaster_03": "Edge_Oro",
- "Room_Wyrm": "Edge_Cast-Off_Shell",
- "Abyss_01": "City_Broken_Elevator",
- "Crossroads_49b": "City_Left_Elevator",
- "Room_nailsmith": "City_Nailsmith",
- "Ruins_Bathhouse": "City_Pleasure_House_Bench",
- "Ruins_Elevator": "City_Pleasure_House_Elevator",
- "Ruins_House_01": "City_Guarded_Grub",
- "Ruins_House_02": "City_Gorgeous_Husk",
- "Ruins_House_03": "City_Emilitia",
- "Ruins1_01": "City_Pilgrim's_Entrance",
- "Ruins1_02": "City_Quirrel_Bench",
- "Ruins1_03": "City_Rafters",
- "Ruins1_04": "City_Outside_Nailsmith",
- "Ruins1_05": "City_Grub_Above_Lemm",
- "Ruins1_05b": "City_Lemm",
- "Ruins1_05c": "City_Egg_Above_Lemm",
- "Ruins1_06": "City_Corridor_to_Storerooms",
- "Ruins1_09": "City_Soul_Twister_Arena",
- "Ruins1_17": "City_Whispering_Root",
- "Ruins1_18": "City_Corridor_to_Spire",
- "Ruins1_23": "City_Sanctum_Entrance",
- "Ruins1_24": "City_Soul_Master_Arena",
- "Ruins1_25": "City_Sanctum_East_Elevators",
- "Ruins1_27": "City_Hollow_Knight_Fountain",
- "Ruins1_28": "City_Storerooms",
- "Ruins1_29": "City_Storerooms_Stag",
- "Ruins1_30": "City_Sanctum_Spell_Twister",
- "Ruins1_31": "City_Toll_Bench",
- "Ruins1_31b": "City_Shade_Soul_Arena",
- "Ruins1_32": "City_Soul_Master_Rewards",
- "Ruins2_01": "City_Spire_Second_Floor",
- "Ruins2_01_b": "City_Spire_First_Floor",
- "Ruins2_03": "City_Spire_Fourth_Floor",
- "Ruins2_03b": "City_Spire_Third_Floor",
- "Ruins2_04": "City_Right_Hub",
- "Ruins2_05": "City_Above_King's",
- "Ruins2_06": "City_King's_Station",
- "Ruins2_07": "City_Grub_Below_King's",
- "Ruins2_08": "City_King's_Stag",
- "Ruins2_09": "City_King's_Vessel_Fragment",
- "Ruins2_10b": "City_Right_Elevator",
- "Ruins2_11": "City_Collector_Arena",
- "Ruins2_11_b": "City_Tower_of_Love",
- "Ruins2_Watcher_Room": "City_Lurien_Elevator",
- "Hive_01": "Hive_Entrance",
- "Hive_02": "Hive_Whispering_Root",
- "Hive_03": "Hive_Outside_Grub",
- "Hive_03_c": "Hive_Outside_Shortcut",
- "Hive_04": "Hive_Mask_Shard",
- "Hive_05": "Hive_Knight_Arena",
- "GG_Pipeway": "Waterways_Flukemunga_Corridor",
- "GG_Waterways": "Waterways_Junk_Pit",
- "Room_GG_Shortcut": "Waterways_Fluke_Hermit",
- "Waterways_01": "Waterways_Entrance",
- "Waterways_02": "Waterways_Main_Bench",
- "Waterways_03": "Waterways_Tuk",
- "Waterways_04": "Waterways_Hidden_Grub",
- "Waterways_04b": "Waterways_Mask_Shard",
- "Waterways_05": "Waterways_Dung_Defender_Arena",
- "Waterways_06": "Waterways_Corridor_to_Broken_Elevator",
- "Waterways_07": "Waterways_Left_Of_Isma's_Grove",
- "Waterways_08": "Waterways_Outside_Flukemarm",
- "Waterways_09": "Waterways_Cornifer",
- "Waterways_12": "Waterways_Flukemarm_Arena",
- "Waterways_13": "Waterways_Isma's_Grove",
- "Waterways_14": "Waterways_Edge_Acid_Corridor",
- "Waterways_15": "Waterways_Dung_Defender's_Cave",
- "Abyss_03_b": "Deepnest_Tram",
- "Deepnest_01b": "Deepnest_Upper_Cornifer",
- "Deepnest_02": "Deepnest_Outside_Mimics",
- "Deepnest_03": "Deepnest_Left_Of_Hot_Spring",
- "Deepnest_09": "Deepnest_Distant_Village_Stag",
- "Deepnest_10": "Deepnest_Distant_Village",
- "Deepnest_14": "Deepnest_Failed_Tramway_Bench",
- "Deepnest_16": "Deepnest_After_Lower_Cornifer",
- "Deepnest_17": "Deepnest_Garpede_Corridor_Below_Cornifer",
- "Deepnest_26": "Deepnest_Failed_Tramway_Lifeblood",
- "Deepnest_26b": "Deepnest_Tram_Pass",
- "Deepnest_30": "Deepnest_Hot_Spring",
- "Deepnest_31": "Deepnest_Nosk_Corridor",
- "Deepnest_32": "Deepnest_Nosk_Arena",
- "Deepnest_33": "Deepnest_Zote_Arena",
- "Deepnest_34": "Deepnest_First_Devout",
- "Deepnest_35": "Deepnest_Outside_Galien",
- "Deepnest_36": "Deepnest_Mimics",
- "Deepnest_37": "Deepnest_Corridor_to_Tram",
- "Deepnest_38": "Deepnest_Vessel_Fragment",
- "Deepnest_39": "Deepnest_Whispering_Root",
- "Deepnest_40": "Deepnest_Galien_Arena",
- "Deepnest_41": "Deepnest_Midwife",
- "Deepnest_42": "Deepnest_Outside_Mask_Maker",
- "Deepnest_44": "Deepnest_Sharp_Shadow",
- "Deepnest_45_v02": "Deepnest_Weaver's_Den",
- "Deepnest_Spider_Town": "Deepnest_Beast's_Den",
- "Fungus2_25": "Deepnest_Lower_Cornifer",
- "Room_Mask_Maker": "Deepnest_Mask_Maker",
- "Room_spider_small": "Deepnest_Brumm",
- "Deepnest_43": "Gardens_Corridor_To_Deepnest",
- "Fungus1_23": "Gardens_First_Loodle_Corridor",
- "Fungus1_24": "Gardens_Cornifer",
- "Fungus3_04": "Gardens_Before_Petra_Arena",
- "Fungus3_05": "Gardens_Petra_Arena",
- "Fungus3_08": "Gardens_Lower_Petra_Corridor",
- "Fungus3_10": "Gardens_Main_Arena",
- "Fungus3_11": "Gardens_Whispering_Root",
- "Fungus3_13": "Gardens_Outside_Stag",
- "Fungus3_21": "Gardens_Corridor_to_Traitor_Lord",
- "Fungus3_22": "Gardens_Upper_Grub",
- "Fungus3_23": "Gardens_Traitor_Lord_Arena",
- "Fungus3_34": "Gardens_Entrance",
- "Fungus3_39": "Gardens_Moss_Prophet",
- "Fungus3_49": "Gardens_Traitor's_Child's_Grave",
- "Fungus3_40": "Gardens_Gardens_Stag",
- "Fungus3_48": "Gardens_Outside_White_Lady",
- "Fungus3_50": "Gardens_Toll_Bench",
- "Room_Queen": "Gardens_White_Lady",
- "White_Palace_01": "Palace_Entrance",
- "White_Palace_02": "Palace_First_Mold",
- "White_Palace_03_hub": "Palace_Hub",
- "White_Palace_04": "Palace_Left_Of_Hub",
- "White_Palace_05": "Palace_Saw_Room",
- "White_Palace_06": "Palace_Balcony",
- "White_Palace_07": "Palace_Lamp_Pogo",
- "White_Palace_08": "Palace_Workshop",
- "White_Palace_09": "Palace_Throne",
- "White_Palace_11": "Palace_Outside",
- "White_Palace_12": "Palace_Spike_Drop",
- "White_Palace_13": "Palace_Thorn_Jump",
- "White_Palace_14": "Palace_Hell_Corridor",
- "White_Palace_15": "Palace_Caged_Lever",
- "White_Palace_16": "Palace_Saw_Climb",
- "White_Palace_17": "POP_Lever",
- "White_Palace_18": "POP_Entrance",
- "White_Palace_19": "POP_Vertical",
- "White_Palace_20": "POP_Final",
- "Dream_Final_Boss": "Egg_Radiance",
- "Room_Final_Boss_Atrium": "Egg_Bench",
- "Room_Final_Boss_Core": "Egg_Hollow_Knight",
- "Grimm_Divine": "Grimm_Divine",
- "Grimm_Main_Tent": "Grimm_Tent",
- "Grimm_Nightmare": "Grimm_NKG",
- "Dream_01_False_Knight": "Dream_Failed_Champion",
- "Dream_02_Mage_Lord": "Dream_Soul_Tyrant",
- "Dream_03_Infected_Knight": "Dream_Lost_Kin",
- "Dream_04_White_Defender": "Dream_White_Defender",
- "Dream_Abyss": "Dream_Abyss",
- "Dream_Backer_Shrine": "Dream_Outside_Shrine",
- "Dream_Guardian_Hegemol": "Dream_Herrah",
- "Dream_Guardian_Lurien": "Dream_Lurien",
- "Dream_Guardian_Monomon": "Dream_Monomon",
- "Dream_Mighty_Zote": "Dream_Grey_Prince_Zote",
- "Dream_Nailcollection": "Dream_Nail",
- "Dream_Room_Believer_Shrine": "Dream_Shrine_of_Believers",
- "GG_Atrium": "Godhome_Atrium",
- "GG_Atrium_Roof": "Godhome_Roof",
- "GG_Blue_Room": "Godhome_Lifeblood",
- "GG_Land_Of_Storms": "Godhome_Land_Of_Storms",
- "GG_Mighty_Zote": "GG_Enchanting_Vigorous_Diligent_Overwhelming_Gorgeous_Passionate_Terrifying_Beautiful_Zote",
- "GG_Unlock_Wastes": "Godhome_Godtuner",
- "GG_Workshop": "Godhome_Hall_Of_Gods"
+ "Tutorial_01": "King's Pass",
+ "Town": "Dirtmouth",
+ "Room_shop": "Sly's Shop",
+ "Room_Sly_Storeroom": "Sly's Shop Basement",
+ "Room_Town_Stag_Station": "Dirtmouth Stag Station",
+ "Room_mapper": "Iselda's Shop",
+ "Room_Bretta": "Bretta's Room",
+ "Room_Bretta_Basement": "Bretta's Room Basement",
+ "Room_Ouiji": "Jiji's Hut",
+ "Room_Jinn": "Jinn's Hut",
+ "Room_Tram_RG": "Upper Tram",
+ "Room_Tram": "Lower Tram",
+ "Crossroads_01": "Crossroads Well",
+ "Crossroads_02": "Crossroads Outside Temple",
+ "Crossroads_03": "Crossroads Outside Stag",
+ "Crossroads_04": "Crossroads Gruz Mother",
+ "Crossroads_05": "Crossroads Central Grub",
+ "Crossroads_06": "Crossroads Outside Mound",
+ "Crossroads_07": "Crossroads Gruzzer",
+ "Crossroads_08": "Crossroads Aspid Arena",
+ "Crossroads_09": "Crossroads Mawlek Boss",
+ "Crossroads_10": "Crossroads False Knight Arena",
+ "Crossroads_11_alt": "Crossroads Greenpath Entrance",
+ "Crossroads_12": "Crossroads Corridor to Acid Grub",
+ "Crossroads_13": "Crossroads Goam Mask Shard",
+ "Crossroads_14": "Crossroads Outside Myla",
+ "Crossroads_15": "Crossroads Corridor to Tram",
+ "Crossroads_16": "Crossroads Above Lever",
+ "Crossroads_18": "Crossroads Fungal Entrance",
+ "Crossroads_19": "Crossroads Before Gruz Mother",
+ "Crossroads_21": "Crossroads Outside False Knight",
+ "Crossroads_22": "Crossroads Glowing Womb Arena",
+ "Crossroads_25": "Crossroads Mawlek Entrance",
+ "Crossroads_27": "Crossroads Outside Tram",
+ "Crossroads_30": "Crossroads Hot Spring",
+ "Crossroads_31": "Crossroads Spike Grub",
+ "Crossroads_33": "Crossroads Cornifer",
+ "Crossroads_35": "Crossroads Acid Grub",
+ "Crossroads_36": "Crossroads Mawlek Middle",
+ "Crossroads_37": "Crossroads Vessel Fragment",
+ "Crossroads_38": "Crossroads Grubfather",
+ "Crossroads_39": "Crossroads Corridor Right of Temple",
+ "Crossroads_40": "Crossroads Corridor Right of Central Grub",
+ "Crossroads_42": "Crossroads Right Of Mask Shard",
+ "Crossroads_43": "Crossroads Corridor to Elevator",
+ "Crossroads_45": "Crossroads Myla",
+ "Crossroads_46": "Crossroads Tram",
+ "Crossroads_47": "Crossroads Stag",
+ "Crossroads_48": "Crossroads Guarded Grub",
+ "Crossroads_49": "Crossroads Elevator",
+ "Crossroads_52": "Crossroads Goam Journal",
+ "Crossroads_ShamanTemple": "Crossroads Ancestral Mound",
+ "Room_Mender_House": "Crossroads Menderbug",
+ "Room_Charm_Shop": "Crossroads Salubra",
+ "Room_ruinhouse": "Crossroads Rescue Sly",
+ "Room_temple": "Crossroads Inside Temple",
+ "Fungus1_01": "Greenpath Entrance",
+ "Fungus1_01b": "Greenpath Waterfall Bench",
+ "Fungus1_02": "Greenpath First Hornet Sighting",
+ "Fungus1_03": "Greenpath Storerooms",
+ "Fungus1_04": "Greenpath Hornet",
+ "Fungus1_05": "Greenpath Outside Thorns",
+ "Fungus1_06": "Greenpath Cornifer",
+ "Fungus1_07": "Greenpath Outside Hunter",
+ "Fungus1_08": "Greenpath Hunter",
+ "Fungus1_09": "Greenpath Sheo Gauntlet",
+ "Fungus1_10": "Greenpath Acid Bridge",
+ "Fungus1_11": "Greenpath Above Fog Canyon",
+ "Fungus1_12": "Greenpath MMC Corridor",
+ "Fungus1_13": "Greenpath Whispering Root",
+ "Fungus1_14": "Greenpath Thorns of Agony",
+ "Fungus1_15": "Greenpath Outside Sheo",
+ "Fungus1_16_alt": "Greenpath Stag",
+ "Fungus1_17": "Greenpath Charger Corridor",
+ "Fungus1_19": "Greenpath Above Sanctuary Bench",
+ "Fungus1_20_v02": "Greenpath Vengefly King",
+ "Fungus1_21": "Greenpath Outside Hornet",
+ "Fungus1_22": "Greenpath Outside Stag",
+ "Fungus1_25": "Greenpath Corridor to Unn",
+ "Fungus1_26": "Greenpath Lake Of Unn",
+ "Fungus1_29": "Greenpath Massive Moss Charger",
+ "Fungus1_30": "Greenpath Below Toll Bench",
+ "Fungus1_31": "Greenpath Toll",
+ "Fungus1_32": "Greenpath Moss Knight Arena",
+ "Fungus1_34": "Greenpath Stone Sanctuary Entrance",
+ "Fungus1_35": "Greenpath Stone Sanctuary",
+ "Fungus1_36": "Greenpath Stone Sanctuary Mask Shard",
+ "Fungus1_37": "Greenpath Sanctuary Bench",
+ "Fungus1_Slug": "Greenpath Unn",
+ "Room_nailmaster_02": "Greenpath Sheo",
+ "Room_Slug_Shrine": "Greenpath Unn Bench",
+ "Deepnest_01": "Fungal_Deepnest_Fall",
+ "Fungus2_01": "Fungal_Queen's_Station",
+ "Fungus2_02": "Fungal_Queen's_Stag",
+ "Fungus2_03": "Fungal_Outside_Queen's",
+ "Fungus2_04": "Fungal_Below_Ogres",
+ "Fungus2_05": "Fungal_Shrumal_Ogres",
+ "Fungus2_06": "Fungal_Outside_Leg_Eater",
+ "Fungus2_07": "Fungal_Shrumal_Warrior_Acid_Bridge",
+ "Fungus2_08": "Fungal_Outside_Elder_Hu",
+ "Fungus2_09": "Fungal_Cloth_Corridor",
+ "Fungus2_10": "Fungal_Left_Of_Pilgrim's_Way",
+ "Fungus2_11": "Fungal_Right_of_Bouncy_Grub",
+ "Fungus2_12": "Fungal_Mantis_Corridor",
+ "Fungus2_13": "Fungal_Bretta_Bench",
+ "Fungus2_14": "Fungal_Mantis_Village",
+ "Fungus2_15": "Fungal_Mantis_Lords",
+ "Fungus2_17": "Fungal_Above_Mantis_Village",
+ "Fungus2_18": "Fungal_Cornifer",
+ "Fungus2_19": "Fungal_Right_Of_Spore_Shroom",
+ "Fungus2_20": "Fungal_Spore_Shroom",
+ "Fungus2_21": "Fungal_Pilgrim's_Way",
+ "Fungus2_23": "Fungal_Dashmaster",
+ "Fungus2_26": "Fungal_Leg_Eater",
+ "Fungus2_28": "Fungal_Shrumal_Warrior_Loop",
+ "Fungus2_29": "Fungal_Core_Upper",
+ "Fungus2_30": "Fungal_Core_Lower",
+ "Fungus2_31": "Fungal_Mantis_Rewards",
+ "Fungus2_32": "Fungal_Elder_Hu",
+ "Fungus2_33": "Fungal_Leg_Eater_Root",
+ "Fungus2_34": "Fungal_Willoh",
+ "Fungus3_01": "Fog_Upper_West_Tall",
+ "Fungus3_02": "Fog_Lower_West_Tall",
+ "Fungus3_03": "Fog_Queen's_Gardens_Acid_Entrance",
+ "Fungus3_24": "Fog_Corridor_to_Overgrown_Mound",
+ "Fungus3_25": "Fog_Cornifer",
+ "Fungus3_25b": "Fog_Corridor_to_Cornifer",
+ "Fungus3_26": "Fog_East_Tall",
+ "Fungus3_27": "Fog_Corridor_to_Archives",
+ "Fungus3_28": "Fog_Charm_Notch",
+ "Fungus3_30": "Fog_Lifeblood",
+ "Fungus3_35": "Fog_Millibelle",
+ "Fungus3_44": "Fog_Overgrown_Mound_Entrance",
+ "Fungus3_47": "Fog_Archives_Entrance",
+ "Fungus3_archive": "Fog_Archives_Bench",
+ "Fungus3_archive_02": "Fog_Uumuu_Arena",
+ "Room_Fungus_Shaman": "Fog_Overgrown_Mound",
+ "Cliffs_01": "Cliffs_Main",
+ "Cliffs_02": "Cliffs_Gorb",
+ "Cliffs_03": "Cliffs_Stag_Nest",
+ "Cliffs_04": "Cliffs_Joni's_Dark",
+ "Cliffs_05": "Cliffs_Joni's_Pickup",
+ "Cliffs_06": "Cliffs_Grimm_Lantern",
+ "Fungus1_28": "Cliffs_Baldur's_Shell",
+ "Room_nailmaster": "Cliffs_Mato",
+ "Mines_01": "Crystal_Dive_Entrance",
+ "Mines_02": "Crystal_Dark_Entrance",
+ "Mines_03": "Crystal_Spike_Grub",
+ "Mines_04": "Crystal_Entrance_Conveyors",
+ "Mines_05": "Crystal_Above_Spike_Grub",
+ "Mines_06": "Crystal_Deep_Focus_Gauntlet",
+ "Mines_07": "Crystal_Dark_Room",
+ "Mines_10": "Crystal_Elevator_Entrance",
+ "Mines_11": "Crystal_Left_Of_Guardian",
+ "Mines_13": "Crystal_Top_Corridor",
+ "Mines_16": "Crystal_Mimic",
+ "Mines_17": "Crystal_Corridor_to_Spike_Grub",
+ "Mines_18": "Crystal_Guardian_Bench",
+ "Mines_19": "Crystal_Grub_Crushers",
+ "Mines_20": "Crystal_East_Tall",
+ "Mines_23": "Crystal_Crown_Whispering_Root",
+ "Mines_24": "Crystal_Crown_Grub",
+ "Mines_25": "Crystal_Crown_Climb",
+ "Mines_28": "Crystal_Outside_Mound",
+ "Mines_29": "Crystal_Dark_Bench",
+ "Mines_30": "Crystal_Cornifer",
+ "Mines_31": "Crystal_Crystal_Heart_Gauntlet",
+ "Mines_32": "Crystal_Enraged_Guardian_Arena",
+ "Mines_33": "Crossroads_Peak_Dark_Toll",
+ "Mines_34": "Crystal_Crown_Peak",
+ "Mines_35": "Crystal_Mound",
+ "Mines_36": "Crystal_Deep_Focus",
+ "Mines_37": "Crystal_Chest_Crushers",
+ "Abyss_02": "Basin_Broken_Bridge",
+ "Abyss_03": "Basin_Tram",
+ "Abyss_04": "Basin_Fountain",
+ "Abyss_05": "Basin_Palace_Grounds",
+ "Abyss_17": "Basin_Cloth",
+ "Abyss_18": "Basin_Corridor_to_Broken_Vessel",
+ "Abyss_19": "Basin_Broken_Vessel_Grub",
+ "Abyss_20": "Basin_Simple_Key",
+ "Abyss_21": "Basin_Monarch_Wings",
+ "Abyss_22": "Basin_Hidden_Station",
+ "Abyss_06_Core": "Abyss_Core",
+ "Abyss_08": "Abyss_Lifeblood_Core",
+ "Abyss_09": "Abyss_Lighthouse_Climb",
+ "Abyss_10": "Abyss_Shade_Cloak",
+ "Abyss_12": "Abyss_Shriek",
+ "Abyss_15": "Abyss_Birthplace",
+ "Abyss_16": "Abyss_Corridor_to_Lighthouse",
+ "Abyss_Lighthouse_room": "Abyss_Lighthouse",
+ "Crossroads_46b": "Grounds_Tram",
+ "Crossroads_50": "Grounds_Blue_Lake",
+ "RestingGrounds_02": "Grounds_Xero",
+ "RestingGrounds_04": "Grounds_Dream_Nail_Entrance",
+ "RestingGrounds_05": "Grounds_Whispering_Root",
+ "RestingGrounds_06": "Grounds_Corridor_Below_Xero",
+ "RestingGrounds_07": "Grounds_Seer",
+ "RestingGrounds_08": "Grounds_Spirit's_Glade",
+ "RestingGrounds_09": "Grounds_Stag",
+ "RestingGrounds_10": "Grounds_Crypts",
+ "RestingGrounds_12": "Grounds_Outside_Grey_Mourner",
+ "RestingGrounds_17": "Grounds_Dreamshield",
+ "Room_Mansion": "Grounds_Grey_Mourner",
+ "Ruins2_10": "Grounds_Elevator",
+ "Abyss_03_c": "Edge_Tram",
+ "Deepnest_East_01": "Edge_Left_Of_Hive",
+ "Deepnest_East_02": "Edge_Above_Hive",
+ "Deepnest_East_03": "Edge_Entrance",
+ "Deepnest_East_04": "Edge_Bardoon",
+ "Deepnest_East_06": "Edge_Outside_Oro",
+ "Deepnest_East_07": "Edge_Whispering_Root",
+ "Deepnest_East_08": "Edge_Great_Hopper_Idol",
+ "Deepnest_East_09": "Edge_Corridor_Outside_Colosseum",
+ "Deepnest_East_10": "Edge_Markoth_Arena",
+ "Deepnest_East_11": "Edge_Below_Camp_Bench",
+ "Deepnest_East_12": "Edge_Hornet_Sentinel_Corridor",
+ "Deepnest_East_13": "Edge_Camp_Bench",
+ "Deepnest_East_14": "Edge_Below_Oro",
+ "Deepnest_East_14b": "Edge_Quick_Slash",
+ "Deepnest_East_15": "Edge_Lifeblood",
+ "Deepnest_East_16": "Edge_Oro_Scarecrow",
+ "Deepnest_East_17": "Edge_420_Geo_Rock",
+ "Deepnest_East_18": "Edge_Outside_Markoth",
+ "Deepnest_East_Hornet": "Edge_Hornet_Sentinel_Arena",
+ "GG_Lurker": "Edge_Pale_Lurker",
+ "Room_Colosseum_01": "Edge_Colo_Entrance",
+ "Room_Colosseum_02": "Edge_Colo_Bench",
+ "Room_Colosseum_Bronze": "Edge_Colo_1_Arena",
+ "Room_Colosseum_Gold": "Edge_Colo_3_Arena",
+ "Room_Colosseum_Silver": "Edge_Colo_2_Arena",
+ "Room_Colosseum_Spectate": "Edge_Colo_Spectate",
+ "Room_nailmaster_03": "Edge_Oro",
+ "Room_Wyrm": "Edge_Cast-Off_Shell",
+ "Abyss_01": "City_Broken_Elevator",
+ "Crossroads_49b": "City_Left_Elevator",
+ "Room_nailsmith": "City_Nailsmith",
+ "Ruins_Bathhouse": "City_Pleasure_House_Bench",
+ "Ruins_Elevator": "City_Pleasure_House_Elevator",
+ "Ruins_House_01": "City_Guarded_Grub",
+ "Ruins_House_02": "City_Gorgeous_Husk",
+ "Ruins_House_03": "City_Emilitia",
+ "Ruins1_01": "City_Pilgrim's_Entrance",
+ "Ruins1_02": "City_Quirrel_Bench",
+ "Ruins1_03": "City_Rafters",
+ "Ruins1_04": "City_Outside_Nailsmith",
+ "Ruins1_05": "City_Grub_Above_Lemm",
+ "Ruins1_05b": "City_Lemm",
+ "Ruins1_05c": "City_Egg_Above_Lemm",
+ "Ruins1_06": "City_Corridor_to_Storerooms",
+ "Ruins1_09": "City_Soul_Twister_Arena",
+ "Ruins1_17": "City_Whispering_Root",
+ "Ruins1_18": "City_Corridor_to_Spire",
+ "Ruins1_23": "City_Sanctum_Entrance",
+ "Ruins1_24": "City_Soul_Master_Arena",
+ "Ruins1_25": "City_Sanctum_East_Elevators",
+ "Ruins1_27": "City_Hollow_Knight_Fountain",
+ "Ruins1_28": "City_Storerooms",
+ "Ruins1_29": "City_Storerooms_Stag",
+ "Ruins1_30": "City_Sanctum_Spell_Twister",
+ "Ruins1_31": "City_Toll_Bench",
+ "Ruins1_31b": "City_Shade_Soul_Arena",
+ "Ruins1_32": "City_Soul_Master_Rewards",
+ "Ruins2_01": "City_Spire_Second_Floor",
+ "Ruins2_01_b": "City_Spire_First_Floor",
+ "Ruins2_03": "City_Spire_Fourth_Floor",
+ "Ruins2_03b": "City_Spire_Third_Floor",
+ "Ruins2_04": "City_Right_Hub",
+ "Ruins2_05": "City_Above_King's",
+ "Ruins2_06": "City_King's_Station",
+ "Ruins2_07": "City_Grub_Below_King's",
+ "Ruins2_08": "City_King's_Stag",
+ "Ruins2_09": "City_King's_Vessel_Fragment",
+ "Ruins2_10b": "City_Right_Elevator",
+ "Ruins2_11": "City_Collector_Arena",
+ "Ruins2_11_b": "City_Tower_of_Love",
+ "Ruins2_Watcher_Room": "City_Lurien_Elevator",
+ "Hive_01": "Hive_Entrance",
+ "Hive_02": "Hive_Whispering_Root",
+ "Hive_03": "Hive_Outside_Grub",
+ "Hive_03_c": "Hive_Outside_Shortcut",
+ "Hive_04": "Hive_Mask_Shard",
+ "Hive_05": "Hive_Knight_Arena",
+ "GG_Pipeway": "Waterways_Flukemunga_Corridor",
+ "GG_Waterways": "Waterways_Junk_Pit",
+ "Room_GG_Shortcut": "Waterways_Fluke_Hermit",
+ "Waterways_01": "Waterways_Entrance",
+ "Waterways_02": "Waterways_Main_Bench",
+ "Waterways_03": "Waterways_Tuk",
+ "Waterways_04": "Waterways_Hidden_Grub",
+ "Waterways_04b": "Waterways_Mask_Shard",
+ "Waterways_05": "Waterways_Dung_Defender_Arena",
+ "Waterways_06": "Waterways_Corridor_to_Broken_Elevator",
+ "Waterways_07": "Waterways_Left_Of_Isma's_Grove",
+ "Waterways_08": "Waterways_Outside_Flukemarm",
+ "Waterways_09": "Waterways_Cornifer",
+ "Waterways_12": "Waterways_Flukemarm_Arena",
+ "Waterways_13": "Waterways_Isma's_Grove",
+ "Waterways_14": "Waterways_Edge_Acid_Corridor",
+ "Waterways_15": "Waterways_Dung_Defender's_Cave",
+ "Abyss_03_b": "Deepnest_Tram",
+ "Deepnest_01b": "Deepnest_Upper_Cornifer",
+ "Deepnest_02": "Deepnest_Outside_Mimics",
+ "Deepnest_03": "Deepnest_Left_Of_Hot_Spring",
+ "Deepnest_09": "Deepnest_Distant_Village_Stag",
+ "Deepnest_10": "Deepnest_Distant_Village",
+ "Deepnest_14": "Deepnest_Failed_Tramway_Bench",
+ "Deepnest_16": "Deepnest_After_Lower_Cornifer",
+ "Deepnest_17": "Deepnest_Garpede_Corridor_Below_Cornifer",
+ "Deepnest_26": "Deepnest_Failed_Tramway_Lifeblood",
+ "Deepnest_26b": "Deepnest_Tram_Pass",
+ "Deepnest_30": "Deepnest_Hot_Spring",
+ "Deepnest_31": "Deepnest_Nosk_Corridor",
+ "Deepnest_32": "Deepnest_Nosk_Arena",
+ "Deepnest_33": "Deepnest_Zote_Arena",
+ "Deepnest_34": "Deepnest_First_Devout",
+ "Deepnest_35": "Deepnest_Outside_Galien",
+ "Deepnest_36": "Deepnest_Mimics",
+ "Deepnest_37": "Deepnest_Corridor_to_Tram",
+ "Deepnest_38": "Deepnest_Vessel_Fragment",
+ "Deepnest_39": "Deepnest_Whispering_Root",
+ "Deepnest_40": "Deepnest_Galien_Arena",
+ "Deepnest_41": "Deepnest_Midwife",
+ "Deepnest_42": "Deepnest_Outside_Mask_Maker",
+ "Deepnest_44": "Deepnest_Sharp_Shadow",
+ "Deepnest_45_v02": "Deepnest_Weaver's_Den",
+ "Deepnest_Spider_Town": "Deepnest_Beast's_Den",
+ "Fungus2_25": "Deepnest_Lower_Cornifer",
+ "Room_Mask_Maker": "Deepnest_Mask_Maker",
+ "Room_spider_small": "Deepnest_Brumm",
+ "Deepnest_43": "Gardens_Corridor_To_Deepnest",
+ "Fungus1_23": "Gardens_First_Loodle_Corridor",
+ "Fungus1_24": "Gardens_Cornifer",
+ "Fungus3_04": "Gardens_Before_Petra_Arena",
+ "Fungus3_05": "Gardens_Petra_Arena",
+ "Fungus3_08": "Gardens_Lower_Petra_Corridor",
+ "Fungus3_10": "Gardens_Main_Arena",
+ "Fungus3_11": "Gardens_Whispering_Root",
+ "Fungus3_13": "Gardens_Outside_Stag",
+ "Fungus3_21": "Gardens_Corridor_to_Traitor_Lord",
+ "Fungus3_22": "Gardens_Upper_Grub",
+ "Fungus3_23": "Gardens_Traitor_Lord_Arena",
+ "Fungus3_34": "Gardens_Entrance",
+ "Fungus3_39": "Gardens_Moss_Prophet",
+ "Fungus3_49": "Gardens_Traitor's_Child's_Grave",
+ "Fungus3_40": "Gardens_Gardens_Stag",
+ "Fungus3_48": "Gardens_Outside_White_Lady",
+ "Fungus3_50": "Gardens_Toll_Bench",
+ "Room_Queen": "Gardens_White_Lady",
+ "White_Palace_01": "Palace_Entrance",
+ "White_Palace_02": "Palace_First_Mold",
+ "White_Palace_03_hub": "Palace_Hub",
+ "White_Palace_04": "Palace_Left_Of_Hub",
+ "White_Palace_05": "Palace_Saw_Room",
+ "White_Palace_06": "Palace_Balcony",
+ "White_Palace_07": "Palace_Lamp_Pogo",
+ "White_Palace_08": "Palace_Workshop",
+ "White_Palace_09": "Palace_Throne",
+ "White_Palace_11": "Palace_Outside",
+ "White_Palace_12": "Palace_Spike_Drop",
+ "White_Palace_13": "Palace_Thorn_Jump",
+ "White_Palace_14": "Palace_Hell_Corridor",
+ "White_Palace_15": "Palace_Caged_Lever",
+ "White_Palace_16": "Palace_Saw_Climb",
+ "White_Palace_17": "POP_Lever",
+ "White_Palace_18": "POP_Entrance",
+ "White_Palace_19": "POP_Vertical",
+ "White_Palace_20": "POP_Final",
+ "Dream_Final_Boss": "Egg_Radiance",
+ "Room_Final_Boss_Atrium": "Egg_Bench",
+ "Room_Final_Boss_Core": "Egg_Hollow_Knight",
+ "Grimm_Divine": "Grimm_Divine",
+ "Grimm_Main_Tent": "Grimm_Tent",
+ "Grimm_Nightmare": "Grimm_NKG",
+ "Dream_01_False_Knight": "Dream_Failed_Champion",
+ "Dream_02_Mage_Lord": "Dream_Soul_Tyrant",
+ "Dream_03_Infected_Knight": "Dream_Lost_Kin",
+ "Dream_04_White_Defender": "Dream_White_Defender",
+ "Dream_Abyss": "Dream_Abyss",
+ "Dream_Backer_Shrine": "Dream_Outside_Shrine",
+ "Dream_Guardian_Hegemol": "Dream_Herrah",
+ "Dream_Guardian_Lurien": "Dream_Lurien",
+ "Dream_Guardian_Monomon": "Dream_Monomon",
+ "Dream_Mighty_Zote": "Dream_Grey_Prince_Zote",
+ "Dream_Nailcollection": "Dream_Nail",
+ "Dream_Room_Believer_Shrine": "Dream_Shrine_of_Believers",
+ "GG_Atrium": "Godhome_Atrium",
+ "GG_Atrium_Roof": "Godhome_Roof",
+ "GG_Blue_Room": "Godhome_Lifeblood",
+ "GG_Land_Of_Storms": "Godhome_Land_Of_Storms",
+ "GG_Mighty_Zote": "GG_Enchanting_Vigorous_Diligent_Overwhelming_Gorgeous_Passionate_Terrifying_Beautiful_Zote",
+ "GG_Unlock_Wastes": "Godhome_Godtuner",
+ "GG_Workshop": "Godhome_Hall_Of_Gods"
};
export default MAP;
\ No newline at end of file
diff --git a/src/js/hk-functions.js b/src/js/hk-functions.js
index c66436a..e63dd52 100644
--- a/src/js/hk-functions.js
+++ b/src/js/hk-functions.js
@@ -10,13 +10,13 @@ import MAP from "./hk-dictionary.js";
* @return {number} length of the Object
*/
function ObjectLength(object) {
- let length = 0;
- for (let key in object) {
- if (object.hasOwnProperty(key)) {
- ++length;
- }
+ let length = 0;
+ for (let key in object) {
+ if (object.hasOwnProperty(key)) {
+ ++length;
}
- return length;
+ }
+ return length;
}
/**
@@ -26,15 +26,15 @@ function ObjectLength(object) {
*/
function TranslateMapName(mapCode, dictionary = MAP) {
- let translation = mapCode;
- if (dictionary.hasOwnProperty(mapCode)) translation = dictionary[mapCode];
+ let translation = mapCode;
+ if (dictionary.hasOwnProperty(mapCode)) translation = dictionary[mapCode];
- return translation;
+ return translation;
}
/* ------------------------- Exports ------------------------------- */
export {
- ObjectLength,
- TranslateMapName
+ ObjectLength,
+ TranslateMapName
};
\ No newline at end of file
diff --git a/src/js/page-functions.js b/src/js/page-functions.js
index 8b6c199..2055421 100644
--- a/src/js/page-functions.js
+++ b/src/js/page-functions.js
@@ -1,9 +1,9 @@
import {
- benchmarkTimes
+ benchmarkTimes
} from "./HKCheckCompletion.js";
import {
- LoadSaveFile
+ LoadSaveFile
} from "./LoadSaveFile.js";
// ---------------- Load image files (necessary for Webpack) ----------------- //
@@ -38,39 +38,39 @@ const SCROLL_BUTTON = document.querySelector(".scroll-up-button");
function ScrollToElement(element) {
- /* Scroll to the element top */
- element.scrollTo({
- top: 0,
- behavior: "smooth"
- });
+ /* Scroll to the element top */
+ element.scrollTo({
+ top: 0,
+ behavior: "smooth"
+ });
}
function ShowElement(element) {
- element.classList.add("visible-block");
- element.classList.add("opacity-full");
- element.classList.remove("hidden");
+ element.classList.add("visible-block");
+ element.classList.add("opacity-full");
+ element.classList.remove("hidden");
}
function HideElement(element) {
- element.classList.remove("visible-block");
- element.classList.remove("opacity-full");
- element.classList.add("hidden");
+ element.classList.remove("visible-block");
+ element.classList.remove("opacity-full");
+ element.classList.add("hidden");
}
function TogglePageScrollElement(root, element, ratio) {
- /* Maximum number of pixels that can be scrolled by the user */
- let scrollTotal = root.scrollHeight - root.clientHeight;
+ /* Maximum number of pixels that can be scrolled by the user */
+ let scrollTotal = root.scrollHeight - root.clientHeight;
- if ((root.scrollTop / scrollTotal) > ratio) {
- /* Show button */
- ShowElement(element);
- } else {
- /* Hide button */
- HideElement(element);
- }
+ if ((root.scrollTop / scrollTotal) > ratio) {
+ /* Show button */
+ ShowElement(element);
+ } else {
+ /* Hide button */
+ HideElement(element);
+ }
}
/**
@@ -80,56 +80,56 @@ function TogglePageScrollElement(root, element, ratio) {
*/
function CompletionHTML(jsObj, hkGameCompletion) {
- let h2 = "";
- let h2id = "";
- let cl = "";
- let clGreen = "box-green";
- let clRed = "box-red";
- let cp = 0; // current Percent
- let mp = 0; // max Percent
- let fillText = "";
+ let h2 = "";
+ let h2id = "";
+ let cl = "";
+ let clGreen = "box-green";
+ let clRed = "box-red";
+ let cp = 0; // current Percent
+ let mp = 0; // max Percent
+ let fillText = "";
- for (let i in jsObj) {
- h2 = jsObj[i].h2;
- h2id = "h2-" + jsObj[i].id;
+ for (let i in jsObj) {
+ h2 = jsObj[i].h2;
+ h2id = "h2-" + jsObj[i].id;
- (jsObj[i].hasOwnProperty("percent")) ? cp = jsObj[i].percent: cp = 0;
- if (i === "intro") cp = hkGameCompletion;
+ (jsObj[i].hasOwnProperty("percent")) ? cp = jsObj[i].percent: cp = 0;
+ if (i === "intro") cp = hkGameCompletion;
- // Don't use percent-box for Essentials, Achievements, Statistics
- if (!jsObj[i].hasOwnProperty("maxPercent")) {
- fillText = "";
- }
- // otherwise use percent-box with values cp/mp%
- else {
-
- mp = jsObj[i].maxPercent;
-
- if (i === "maskShards") {
- let perc = jsObj[i].percent;
- (perc % 4) ? cp = Math.floor(perc / 4): cp = perc / 4;
- } else if (i === "vesselFragments") {
- let perc = jsObj[i].percent;
- (perc % 3) ? cp = Math.floor(perc / 3): cp = perc / 3;
- }
-
- // switches the box to red when a section (h2) is 0
- if (cp === 0) {
- cl = ` ${clRed}`;
- }
- // switches the box to green when a section (h2) is completed
- else if (cp === mp) {
- cl = ` ${clGreen}`;
- }
- // default is blue (partially completed and starting value)
- else cl = "";
-
- // needed for Game Status to show percentage properly (adds a slash for all boxes except the Game Status one)
- if (jsObj[i].id != "hk-intro") cp += "/";
-
- fillText = `${(i === "intro") ? cp: cp + jsObj[i].maxPercent}%
`;
- }
+ // Don't use percent-box for Essentials, Achievements, Statistics
+ if (!jsObj[i].hasOwnProperty("maxPercent")) {
+ fillText = "";
}
+ // otherwise use percent-box with values cp/mp%
+ else {
+
+ mp = jsObj[i].maxPercent;
+
+ if (i === "maskShards") {
+ let perc = jsObj[i].percent;
+ (perc % 4) ? cp = Math.floor(perc / 4): cp = perc / 4;
+ } else if (i === "vesselFragments") {
+ let perc = jsObj[i].percent;
+ (perc % 3) ? cp = Math.floor(perc / 3): cp = perc / 3;
+ }
+
+ // switches the box to red when a section (h2) is 0
+ if (cp === 0) {
+ cl = ` ${clRed}`;
+ }
+ // switches the box to green when a section (h2) is completed
+ else if (cp === mp) {
+ cl = ` ${clGreen}`;
+ }
+ // default is blue (partially completed and starting value)
+ else cl = "";
+
+ // needed for Game Status to show percentage properly (adds a slash for all boxes except the Game Status one)
+ if (jsObj[i].id != "hk-intro") cp += "/";
+
+ fillText = `${(i === "intro") ? cp: cp + jsObj[i].maxPercent}%
`;
+ }
+ }
}
@@ -138,376 +138,376 @@ function CompletionHTML(jsObj, hkGameCompletion) {
function GenerateInnerHTML(db) {
- // start benchmarking
- benchmarkTimes.GenerateInnerHTML.timeStart = new Date();
-
- let sections = db.sections;
-
- /* console.log(sections); */
-
- let entries = {};
- let obj = {
- icon: "",
- iconClass: "",
- textPrefix: "",
- textSuffix: "",
- wiki: "",
- div: ``,
- b: ["
", ""],
- p: "
",
- span: ["", ""],
- spoiler: ["", ""],
- spoilerAfter: "",
- };
-
- let iconGreen = SYMBOL_TRUE;
- let iconRed = SYMBOL_FALSE;
- let iconClock = SYMBOL_CLOCK;
- let iconNull = SYMBOL_EMPTY;
-
- let finalHTMLFill = "";
- let textFill = "";
-
- let Img = "";
- let maskNormal = `

`;
- let maskSteel = `

`;
- let soulNormal = `

`;
- let notchNormalImage = `

`;
- let notchFilledImage = `

`;
- let notchOvercharmedImage = `

`;
- let geoNormalImage = `

`;
- let geoShadeImage = `

`;
- let div = `
`;
- let divFlex = `
`;
-
-
- /* ############################## create all main entries ############################## */
-
-
- for (let section in sections) {
-
- entries = sections[section].entries;
-
- /* starts a new
with the current section id */
- textFill = SectionStart(sections[section]);
-
- /* creates a
tag for the current section and fills with current%/max%
- If the save file was not analyzed, then fill only max% on blue background */
- if (db.saveAnalyzed === true) {
- textFill += CompletionFill(sections[section]);
- } else {
- textFill += CompletionFillNoSave(sections[section]);
- }
-
-
- /* #################### Different behaviour depending on the section ####################### */
-
-
- switch (section) {
-
- /* ############### Game Status (intro) ################ */
-
- case "intro":
-
- /* ############## Create each single entry (intro) ############### */
-
- for (let entry in entries) {
-
- obj.b = ["", ""];
- obj.p = "";
- obj.span = ["", ""];
- obj.div = div;
-
- /* -------- Icons (next to each entry) --------- */
- if (entries[entry].hasOwnProperty("icon")) {
-
- switch (entries[entry].icon) {
-
- case "clock":
- obj.icon = iconClock;
- break;
- case "green":
- obj.icon = iconGreen;
- break;
- case "red":
- obj.icon = iconRed;
- break;
- default:
- obj.icon = iconNull;
- }
- } else {
- obj.icon = iconRed;
- }
-
- obj.textPrefix = entries[entry].name;
- obj.textSuffix = entries[entry].spoiler;
- obj.spoilerAfter = "";
-
- /* Different text and images for each entry in the "Game Status" (intro) section */
-
- switch (entry) {
- case "gameCompletion":
- obj.textSuffix = `${obj.textSuffix} %`;
- obj.spoilerAfter = ` ${entries[entry].spoilerAfter}`;
- obj.span[1] = "";
-
- break;
-
- case "gameCompletionExtended":
- obj.spoilerAfter = ` ${entries[entry].spoilerAfter}`;
- obj.span[1] = "";
-
- break;
-
- case "health":
-
- /* ----------------- Horizontal Line after save version ---------------- */
- textFill += FLEUR_DIVIDE;
-
- obj.div = divFlex;
- obj.span = ["", ""];
-
- (entries[entry].permadeathMode) ? Img = maskSteel: Img = maskNormal;
-
- for (let i = 0, total = entries[entry].amountTotal; i < total; i++) {
- obj.textSuffix += Img;
- }
-
- obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;
-
- obj.p = "";
- break;
-
- case "soul":
- obj.div = divFlex;
- obj.span = ["", ""];
- Img = soulNormal;
-
- for (let i = 0, total = Math.round(entries[entry].amountTotal / 33); i < total; i++) {
- obj.textSuffix += Img;
- }
-
- obj.textSuffix += `${obj.p}(${Math.round(entries[entry].amountTotal / 33)})`;
-
- obj.p = "";
- break;
-
- case "notches":
- obj.div = divFlex;
- obj.span = ["", ""];
-
- /* First, check filled (used) notches and fill them (skips if no filled notches) */
- if (entries[entry].amountFilled > 0) {
- for (let i = 0, total = entries[entry].amountFilled; i < total; i++) {
- obj.textSuffix += notchFilledImage;
- }
- }
-
- /* Second, check overcharmed notches and fill them (skips if player is not overcharmed) */
- if (entries[entry].amountOvercharmed > 0) {
- for (let i = 0, total = entries[entry].amountOvercharmed; i < total; i++) {
- obj.textSuffix += notchOvercharmedImage;
- }
- }
-
- /* Last, fill all unused notches */
- if (entries[entry].amountUnused > 0) {
- for (let i = 0, total = entries[entry].amountUnused; i < total; i++) {
- obj.textSuffix += notchNormalImage;
- }
- }
-
- obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;
-
- break;
-
- case "geo":
- obj.div = divFlex;
- obj.span = ["", ""];
-
- obj.textSuffix += `${geoNormalImage}${entries[entry].amount}`;
- // Show Shade Geo value and image only if Shade has at least 1 Geo on it
- if (entries[entry].amountShade > 0) obj.textSuffix += `${obj.p}+${geoShadeImage}${entries[entry].amountShade}`;
-
- // Show also total Geo (Geo + Shade Geo) if player has at least 1 geo alongside the shade geo
- if (entries[entry].amount > 0 && entries[entry].amountShade > 0) {
- obj.textSuffix += `${obj.p}=${obj.p}${entries[entry].amountTotal}`;
- }
-
- obj.p = "";
- break;
-
- default:
- }
-
- textFill += SingleEntryFill(obj);
- }
-
- break;
-
- /* #################### Hints (hints) #################### */
-
- case "hints":
- obj.b = ["", ""];
- obj.span = ["", ""];
- obj.icon = "";
- obj.textPrefix = "";
- obj.div = div;
-
- /* display only one (current) hint */
- obj.textSuffix = entries[sections[section].current].spoiler;
-
- textFill += SingleEntryFill(obj);
-
- break;
-
- /* ###################### Create all other sections ##################### */
-
- default:
-
- /* ###################### Create section descriptions under each H2 title ##################### */
-
- if (sections[section].hasOwnProperty("description")) {
- textFill += SectionDescription(sections[section]);
- }
-
- /* ###################### Create each single entry (from all other sections) ##################### */
-
- for (let entry in entries) {
-
- obj.p = "";
- obj.span = ["", ""];
- obj.spoiler = ["", ""];
- obj.div = div;
- obj.textPrefix = entries[entry].name;
- obj.textSuffix = `— ${entries[entry].spoiler}`;
- obj.wiki = entries[entry].wiki;
-
- /* -------- Icons (next to each entry) --------- */
- if (entries[entry].hasOwnProperty("icon")) {
-
- switch (entries[entry].icon) {
-
- case "clock":
- obj.icon = iconClock;
- break;
-
- case "green":
- obj.icon = iconGreen;
-
- /* -------- Prevents blurring when a player has already completed the entry --------- */
- obj.span[0] = "";
- break;
-
- case "red":
- obj.icon = iconRed;
- break;
-
- default:
- obj.icon = iconNull;
- }
- } else {
- obj.icon = iconRed;
- }
-
- /* assign the appropriate spoiler class name depending on the completion check (for blurring names) */
- if (entries[entry].hasOwnProperty("icon")) {
- switch (entries[entry].icon) {
-
- case "red":
- case "none":
- obj.iconClass = " spoiler-red blurred";
- break;
-
- default:
- obj.iconClass = "";
- }
- } else {
- obj.iconClass = "";
- }
-
- obj.b = [``, ""];
-
- if (entries[entry].hasOwnProperty("amount")) {
- if (entries[entry].hasOwnProperty("disabled")) {
- if (entries[entry].disabled !== true) {
- obj.textPrefix += `: ${entries[entry].amount}`;
- }
- } else {
- obj.textPrefix += `: ${entries[entry].amount}`;
- }
- }
-
- if (entries[entry].hasOwnProperty("amountTotal")) {
- obj.textPrefix += ` / ${entries[entry].amountTotal}`;
- }
-
- if (entries[entry].hasOwnProperty("id")) {
-
- switch (entries[entry].id) {
-
- case "geoRocks":
- case "itemsDiscovered":
- obj.textPrefix += `: ${entries[entry].notActivated} | ${entries[entry].activated} | ${entries[entry].discoveredTotal}`;
-
- break;
-
- default:
- }
- }
-
- if (entries[entry].hasOwnProperty("disabled")) {
- if (entries[entry].disabled === true) {
- obj.textPrefix = `${obj.textPrefix}`;
- }
- }
-
- if (obj.textPrefix.includes("")) obj.textSuffix = `${obj.textSuffix}`;
-
-
-
- /* textFill += SingleEntryFill(section, entries[entry]); */
- textFill += SingleEntryFill(obj);
-
- /* ##################### Horizontal lines ####################### */
-
- switch (entry) {
- case "pantheonKnight":
- case "killedHollowKnightPrime":
- case "bossDoorStateTier5":
- textFill += FLEUR_DIVIDE;
-
- break;
-
- default:
- }
- }
- }
-
- /* Cumulate all section texts into one variable for final HTML filling. End section div tag */
- finalHTMLFill += `${textFill}\n
\n\n`;
-
+ // start benchmarking
+ benchmarkTimes.GenerateInnerHTML.timeStart = new Date();
+
+ let sections = db.sections;
+
+ /* console.log(sections); */
+
+ let entries = {};
+ let obj = {
+ icon: "",
+ iconClass: "",
+ textPrefix: "",
+ textSuffix: "",
+ wiki: "",
+ div: `
`,
+ b: ["
", ""],
+ p: "
",
+ span: ["", ""],
+ spoiler: ["", ""],
+ spoilerAfter: "",
+ };
+
+ let iconGreen = SYMBOL_TRUE;
+ let iconRed = SYMBOL_FALSE;
+ let iconClock = SYMBOL_CLOCK;
+ let iconNull = SYMBOL_EMPTY;
+
+ let finalHTMLFill = "";
+ let textFill = "";
+
+ let Img = "";
+ let maskNormal = `

`;
+ let maskSteel = `

`;
+ let soulNormal = `

`;
+ let notchNormalImage = `

`;
+ let notchFilledImage = `

`;
+ let notchOvercharmedImage = `

`;
+ let geoNormalImage = `

`;
+ let geoShadeImage = `

`;
+ let div = `
`;
+ let divFlex = `
`;
+
+
+ /* ############################## create all main entries ############################## */
+
+
+ for (let section in sections) {
+
+ entries = sections[section].entries;
+
+ /* starts a new
with the current section id */
+ textFill = SectionStart(sections[section]);
+
+ /* creates a
tag for the current section and fills with current%/max%
+ If the save file was not analyzed, then fill only max% on blue background */
+ if (db.saveAnalyzed === true) {
+ textFill += CompletionFill(sections[section]);
+ } else {
+ textFill += CompletionFillNoSave(sections[section]);
}
- /* console.groupCollapsed("finalHTMLFill");
- console.log(finalHTMLFill);
- console.groupEnd(); */
- /* Final single HTML access and fill here */
- document.getElementById("generated").innerHTML = finalHTMLFill;
+ /* #################### Different behaviour depending on the section ####################### */
- // finish benchmarking
- benchmarkTimes.GenerateInnerHTML.timeEnd = new Date();
+
+ switch (section) {
+
+ /* ############### Game Status (intro) ################ */
+
+ case "intro":
+
+ /* ############## Create each single entry (intro) ############### */
+
+ for (let entry in entries) {
+
+ obj.b = ["", ""];
+ obj.p = "";
+ obj.span = ["", ""];
+ obj.div = div;
+
+ /* -------- Icons (next to each entry) --------- */
+ if (entries[entry].hasOwnProperty("icon")) {
+
+ switch (entries[entry].icon) {
+
+ case "clock":
+ obj.icon = iconClock;
+ break;
+ case "green":
+ obj.icon = iconGreen;
+ break;
+ case "red":
+ obj.icon = iconRed;
+ break;
+ default:
+ obj.icon = iconNull;
+ }
+ } else {
+ obj.icon = iconRed;
+ }
+
+ obj.textPrefix = entries[entry].name;
+ obj.textSuffix = entries[entry].spoiler;
+ obj.spoilerAfter = "";
+
+ /* Different text and images for each entry in the "Game Status" (intro) section */
+
+ switch (entry) {
+ case "gameCompletion":
+ obj.textSuffix = `${obj.textSuffix} %`;
+ obj.spoilerAfter = ` ${entries[entry].spoilerAfter}`;
+ obj.span[1] = "";
+
+ break;
+
+ case "gameCompletionExtended":
+ obj.spoilerAfter = ` ${entries[entry].spoilerAfter}`;
+ obj.span[1] = "";
+
+ break;
+
+ case "health":
+
+ /* ----------------- Horizontal Line after save version ---------------- */
+ textFill += FLEUR_DIVIDE;
+
+ obj.div = divFlex;
+ obj.span = ["", ""];
+
+ (entries[entry].permadeathMode) ? Img = maskSteel: Img = maskNormal;
+
+ for (let i = 0, total = entries[entry].amountTotal; i < total; i++) {
+ obj.textSuffix += Img;
+ }
+
+ obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;
+
+ obj.p = "";
+ break;
+
+ case "soul":
+ obj.div = divFlex;
+ obj.span = ["", ""];
+ Img = soulNormal;
+
+ for (let i = 0, total = Math.round(entries[entry].amountTotal / 33); i < total; i++) {
+ obj.textSuffix += Img;
+ }
+
+ obj.textSuffix += `${obj.p}(${Math.round(entries[entry].amountTotal / 33)})`;
+
+ obj.p = "";
+ break;
+
+ case "notches":
+ obj.div = divFlex;
+ obj.span = ["", ""];
+
+ /* First, check filled (used) notches and fill them (skips if no filled notches) */
+ if (entries[entry].amountFilled > 0) {
+ for (let i = 0, total = entries[entry].amountFilled; i < total; i++) {
+ obj.textSuffix += notchFilledImage;
+ }
+ }
+
+ /* Second, check overcharmed notches and fill them (skips if player is not overcharmed) */
+ if (entries[entry].amountOvercharmed > 0) {
+ for (let i = 0, total = entries[entry].amountOvercharmed; i < total; i++) {
+ obj.textSuffix += notchOvercharmedImage;
+ }
+ }
+
+ /* Last, fill all unused notches */
+ if (entries[entry].amountUnused > 0) {
+ for (let i = 0, total = entries[entry].amountUnused; i < total; i++) {
+ obj.textSuffix += notchNormalImage;
+ }
+ }
+
+ obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;
+
+ break;
+
+ case "geo":
+ obj.div = divFlex;
+ obj.span = ["", ""];
+
+ obj.textSuffix += `${geoNormalImage}${entries[entry].amount}`;
+ // Show Shade Geo value and image only if Shade has at least 1 Geo on it
+ if (entries[entry].amountShade > 0) obj.textSuffix += `${obj.p}+${geoShadeImage}${entries[entry].amountShade}`;
+
+ // Show also total Geo (Geo + Shade Geo) if player has at least 1 geo alongside the shade geo
+ if (entries[entry].amount > 0 && entries[entry].amountShade > 0) {
+ obj.textSuffix += `${obj.p}=${obj.p}${entries[entry].amountTotal}`;
+ }
+
+ obj.p = "";
+ break;
+
+ default:
+ }
+
+ textFill += SingleEntryFill(obj);
+ }
+
+ break;
+
+ /* #################### Hints (hints) #################### */
+
+ case "hints":
+ obj.b = ["", ""];
+ obj.span = ["", ""];
+ obj.icon = "";
+ obj.textPrefix = "";
+ obj.div = div;
+
+ /* display only one (current) hint */
+ obj.textSuffix = entries[sections[section].current].spoiler;
+
+ textFill += SingleEntryFill(obj);
+
+ break;
+
+ /* ###################### Create all other sections ##################### */
+
+ default:
+
+ /* ###################### Create section descriptions under each H2 title ##################### */
+
+ if (sections[section].hasOwnProperty("description")) {
+ textFill += SectionDescription(sections[section]);
+ }
+
+ /* ###################### Create each single entry (from all other sections) ##################### */
+
+ for (let entry in entries) {
+
+ obj.p = "";
+ obj.span = ["", ""];
+ obj.spoiler = ["", ""];
+ obj.div = div;
+ obj.textPrefix = entries[entry].name;
+ obj.textSuffix = `— ${entries[entry].spoiler}`;
+ obj.wiki = entries[entry].wiki;
+
+ /* -------- Icons (next to each entry) --------- */
+ if (entries[entry].hasOwnProperty("icon")) {
+
+ switch (entries[entry].icon) {
+
+ case "clock":
+ obj.icon = iconClock;
+ break;
+
+ case "green":
+ obj.icon = iconGreen;
+
+ /* -------- Prevents blurring when a player has already completed the entry --------- */
+ obj.span[0] = "";
+ break;
+
+ case "red":
+ obj.icon = iconRed;
+ break;
+
+ default:
+ obj.icon = iconNull;
+ }
+ } else {
+ obj.icon = iconRed;
+ }
+
+ /* assign the appropriate spoiler class name depending on the completion check (for blurring names) */
+ if (entries[entry].hasOwnProperty("icon")) {
+ switch (entries[entry].icon) {
+
+ case "red":
+ case "none":
+ obj.iconClass = " spoiler-red blurred";
+ break;
+
+ default:
+ obj.iconClass = "";
+ }
+ } else {
+ obj.iconClass = "";
+ }
+
+ obj.b = [``, ""];
+
+ if (entries[entry].hasOwnProperty("amount")) {
+ if (entries[entry].hasOwnProperty("disabled")) {
+ if (entries[entry].disabled !== true) {
+ obj.textPrefix += `: ${entries[entry].amount}`;
+ }
+ } else {
+ obj.textPrefix += `: ${entries[entry].amount}`;
+ }
+ }
+
+ if (entries[entry].hasOwnProperty("amountTotal")) {
+ obj.textPrefix += ` / ${entries[entry].amountTotal}`;
+ }
+
+ if (entries[entry].hasOwnProperty("id")) {
+
+ switch (entries[entry].id) {
+
+ case "geoRocks":
+ case "itemsDiscovered":
+ obj.textPrefix += `: ${entries[entry].notActivated} | ${entries[entry].activated} | ${entries[entry].discoveredTotal}`;
+
+ break;
+
+ default:
+ }
+ }
+
+ if (entries[entry].hasOwnProperty("disabled")) {
+ if (entries[entry].disabled === true) {
+ obj.textPrefix = `${obj.textPrefix}`;
+ }
+ }
+
+ if (obj.textPrefix.includes("")) obj.textSuffix = `${obj.textSuffix}`;
+
+
+
+ /* textFill += SingleEntryFill(section, entries[entry]); */
+ textFill += SingleEntryFill(obj);
+
+ /* ##################### Horizontal lines ####################### */
+
+ switch (entry) {
+ case "pantheonKnight":
+ case "killedHollowKnightPrime":
+ case "bossDoorStateTier5":
+ textFill += FLEUR_DIVIDE;
+
+ break;
+
+ default:
+ }
+ }
+ }
+
+ /* Cumulate all section texts into one variable for final HTML filling. End section div tag */
+ finalHTMLFill += `${textFill}\n
\n\n`;
+
+ }
+
+ /* console.groupCollapsed("finalHTMLFill");
+ console.log(finalHTMLFill);
+ console.groupEnd(); */
+
+ /* Final single HTML access and fill here */
+ document.getElementById("generated").innerHTML = finalHTMLFill;
+
+ // finish benchmarking
+ benchmarkTimes.GenerateInnerHTML.timeEnd = new Date();
}
function SectionDescription(section) {
- return `
${section.description}
`;
+ return `
${section.description}
`;
}
function SectionStart(section) {
- return `
\n`;
+ return `
\n`;
}
/**
@@ -515,25 +515,25 @@ function SectionStart(section) {
*/
function CompletionFillNoSave(section) {
- let id = "";
- let h2 = "";
- let h2id = "";
- let mp = ""; // max Percent
- // let cl = ""; // class
+ let id = "";
+ let h2 = "";
+ let h2id = "";
+ let mp = ""; // max Percent
+ // let cl = ""; // class
- id = section.id;
- h2 = section.h2;
- h2id = "h2-" + section.id;
+ id = section.id;
+ h2 = section.h2;
+ h2id = "h2-" + section.id;
- mp = `
${(id === "hk-intro") ? 0: section.maxPercent}%
`;
- if (!section.hasOwnProperty("maxPercent")) mp = "";
+ mp = `
${(id === "hk-intro") ? 0: section.maxPercent}%
`;
+ if (!section.hasOwnProperty("maxPercent")) mp = "";
- /* return [
- `
`,
- `
${h2}${mp}
`,
- "\n"
- ].join(""); */
- return `
${h2}${mp}
`;
+ /* return [
+ `
`,
+ `
${h2}${mp}
`,
+ "\n"
+ ].join(""); */
+ return `
${h2}${mp}
`;
}
/**
@@ -541,279 +541,279 @@ function CompletionFillNoSave(section) {
*/
function CompletionFill(section) {
- let h2 = section.h2;
- let h2id = `
`;
- let cl = "";
- let clGreen = "box-green";
- let clRed = "box-red";
- let cp = 0; // current Percent
- let mp = 0; // max Percent
- let fillText = "";
+ let h2 = section.h2;
+ let h2id = ``;
+ let cl = "";
+ let clGreen = "box-green";
+ let clRed = "box-red";
+ let cp = 0; // current Percent
+ let mp = 0; // max Percent
+ let fillText = "";
- (section.hasOwnProperty("percent")) ? cp = section.percent: cp = 0;
+ (section.hasOwnProperty("percent")) ? cp = section.percent: cp = 0;
- // Don't use percent-box for Essentials, Achievements, Statistics
- if (!section.hasOwnProperty("maxPercent")) {
- fillText = "";
- }
- // otherwise use percent-box with values cp/mp%
- else {
+ // Don't use percent-box for Essentials, Achievements, Statistics
+ if (!section.hasOwnProperty("maxPercent")) {
+ fillText = "";
+ }
+ // otherwise use percent-box with values cp/mp%
+ else {
- mp = section.maxPercent;
+ mp = section.maxPercent;
- if (section.id === "hk-maskshards") {
- let perc = section.percent;
- (perc % 4) ? cp = Math.floor(perc / 4): cp = perc / 4;
- } else if (section.id === "hk-vesselfragments") {
- let perc = section.percent;
- (perc % 3) ? cp = Math.floor(perc / 3): cp = perc / 3;
- }
-
- // switches the box to red when a section (h2) is 0
- if (cp === 0) {
- cl = ` ${clRed}`;
- }
- // switches the box to green when a section (h2) is completed
- else if (cp === mp) {
- cl = ` ${clGreen}`;
- }
- // default is blue (partially completed and starting value)
- else cl = "";
-
- // needed for Game Status to show percentage properly (adds a slash for all boxes except the Game Status one)
- if (section.id != "hk-intro") cp += "/";
-
- fillText = `
${(section.id === "hk-intro") ? cp: `${cp}${section.maxPercent}`}%
`;
+ if (section.id === "hk-maskshards") {
+ let perc = section.percent;
+ (perc % 4) ? cp = Math.floor(perc / 4): cp = perc / 4;
+ } else if (section.id === "hk-vesselfragments") {
+ let perc = section.percent;
+ (perc % 3) ? cp = Math.floor(perc / 3): cp = perc / 3;
}
- return `\t${h2id}${h2}${fillText}\n`;
+ // switches the box to red when a section (h2) is 0
+ if (cp === 0) {
+ cl = ` ${clRed}`;
+ }
+ // switches the box to green when a section (h2) is completed
+ else if (cp === mp) {
+ cl = ` ${clGreen}`;
+ }
+ // default is blue (partially completed and starting value)
+ else cl = "";
+
+ // needed for Game Status to show percentage properly (adds a slash for all boxes except the Game Status one)
+ if (section.id != "hk-intro") cp += "/";
+
+ fillText = `${(section.id === "hk-intro") ? cp: `${cp}${section.maxPercent}`}%
`;
+ }
+
+ return `\t${h2id}${h2}${fillText}\n`;
}
/* function SingleEntryFill(section, entry) { */
function SingleEntryFill(obj) {
- /*
- let icon = "";
- let iconGreen = SYMBOL_TRUE;
- let iconRed = SYMBOL_FALSE;
- let iconClock = SYMBOL_CLOCK;
- let iconNull = SYMBOL_EMPTY;
+ /*
+ let icon = "";
+ let iconGreen = SYMBOL_TRUE;
+ let iconRed = SYMBOL_FALSE;
+ let iconClock = SYMBOL_CLOCK;
+ let iconNull = SYMBOL_EMPTY;
- let textPrefix = "";
- let textSuffix = "";
- let textFill = "";
- let Img = "";
- let maskNormal = `

`;
- let maskSteel = `

`;
- let soulNormal = `

`;
- let notchNormalImage = `

`;
- let notchFilledImage = `

`;
- let notchOvercharmedImage = `

`;
- let geoNormalImage = `

`;
- let geoShadeImage = `

`;
- let wiki = "";
+ let textPrefix = "";
+ let textSuffix = "";
+ let textFill = "";
+ let Img = "";
+ let maskNormal = `

`;
+ let maskSteel = `

`;
+ let soulNormal = `

`;
+ let notchNormalImage = `

`;
+ let notchFilledImage = `

`;
+ let notchOvercharmedImage = `

`;
+ let geoNormalImage = `

`;
+ let geoShadeImage = `

`;
+ let wiki = "";
- let div = `
`;
- let divFlex = `
`;
- let b = ["
", ""];
- let p = "
";
- let span = ["", ""];
- let spoiler = ["", ""];
- let spoilerAfter = "";
-
- if (entry.hasOwnProperty("icon")) {
-
- switch (entry.icon) {
+ let div = `
`;
+ let divFlex = `
`;
+ let b = ["
", ""];
+ let p = "
";
+ let span = ["", ""];
+ let spoiler = ["", ""];
+ let spoilerAfter = "";
+
+ if (entry.hasOwnProperty("icon")) {
+
+ switch (entry.icon) {
- case "clock":
- icon = iconClock;
- break;
- case "green":
- icon = iconGreen;
- break;
- case "red":
- icon = iconRed;
- break;
- default:
- icon = iconNull;
- }
- } else {
- icon = iconRed;
- }
+ case "clock":
+ icon = iconClock;
+ break;
+ case "green":
+ icon = iconGreen;
+ break;
+ case "red":
+ icon = iconRed;
+ break;
+ default:
+ icon = iconNull;
+ }
+ } else {
+ icon = iconRed;
+ }
- if (entry.hasOwnProperty("name")) {
- textPrefix = entry.name;
- }
+ if (entry.hasOwnProperty("name")) {
+ textPrefix = entry.name;
+ }
- if (entry.hasOwnProperty("spoiler")) {
- textSuffix = entry.spoiler;
- }
+ if (entry.hasOwnProperty("spoiler")) {
+ textSuffix = entry.spoiler;
+ }
- if (entry.hasOwnProperty("wiki")) {
- wiki = entry.wiki;
- }
+ if (entry.hasOwnProperty("wiki")) {
+ wiki = entry.wiki;
+ }
- if (!textPrefix.length) b = ["", ""];
- if (wiki.length) b = [`
`, ""];
+ if (!textPrefix.length) b = ["", ""];
+ if (wiki.length) b = [`
`, ""];
- // #################### Different behaviour depending on the section #######################
+ // #################### Different behaviour depending on the section #######################
- switch (section) {
+ switch (section) {
- case "intro":
- b = ["", ""];
- span = ["
", ""];
+ case "intro":
+ b = ["", ""];
+ span = ["
", ""];
- // Different text and images for each entry in the "Game Status" section
+ // Different text and images for each entry in the "Game Status" section
- switch (entry.id) {
- case "gameCompletion":
- textSuffix = `${entry.spoiler} %`;
+ switch (entry.id) {
+ case "gameCompletion":
+ textSuffix = `${entry.spoiler} %`;
- break;
+ break;
- case "health":
- div = divFlex;
- span = ["", ""];
+ case "health":
+ div = divFlex;
+ span = ["", ""];
- (entry.permadeathMode) ? Img = maskSteel: Img = maskNormal;
+ (entry.permadeathMode) ? Img = maskSteel: Img = maskNormal;
- for (let i = 0, total = entry.amountTotal; i < total; i++) {
- textSuffix += Img;
- }
+ for (let i = 0, total = entry.amountTotal; i < total; i++) {
+ textSuffix += Img;
+ }
- textSuffix += `${p}
(${entry.amountTotal})`;
+ textSuffix += `${p}
(${entry.amountTotal})`;
- p = "";
- break;
+ p = "";
+ break;
- case "soul":
- div = divFlex;
- span = ["", ""];
- Img = soulNormal;
+ case "soul":
+ div = divFlex;
+ span = ["", ""];
+ Img = soulNormal;
- for (let i = 0, total = Math.round(entry.amountTotal / 33); i < total; i++) {
- textSuffix += Img;
- }
+ for (let i = 0, total = Math.round(entry.amountTotal / 33); i < total; i++) {
+ textSuffix += Img;
+ }
- textSuffix += `${p}
(${Math.round(entry.amountTotal / 33)})`;
+ textSuffix += `${p}
(${Math.round(entry.amountTotal / 33)})`;
- p = "";
- break;
+ p = "";
+ break;
- case "notches":
- div = divFlex;
- span = ["", ""];
+ case "notches":
+ div = divFlex;
+ span = ["", ""];
- // First, check filled (used) notches and fill them (skips if no filled notches)
- if (entry.amountFilled > 0) {
- for (let i = 0, total = entry.amountFilled; i < total; i++) {
- textSuffix += notchFilledImage;
- }
- }
+ // First, check filled (used) notches and fill them (skips if no filled notches)
+ if (entry.amountFilled > 0) {
+ for (let i = 0, total = entry.amountFilled; i < total; i++) {
+ textSuffix += notchFilledImage;
+ }
+ }
- // Second, check overcharmed notches and fill them (skips if player is not overcharmed)
- if (entry.amountOvercharmed > 0) {
- for (let i = 0, total = entry.amountOvercharmed; i < total; i++) {
- textSuffix += notchOvercharmedImage;
- }
- }
+ // Second, check overcharmed notches and fill them (skips if player is not overcharmed)
+ if (entry.amountOvercharmed > 0) {
+ for (let i = 0, total = entry.amountOvercharmed; i < total; i++) {
+ textSuffix += notchOvercharmedImage;
+ }
+ }
- // Last, fill all unused notches
- if (entry.amountUnused > 0) {
- for (let i = 0, total = entry.amountUnused; i < total; i++) {
- textSuffix += notchNormalImage;
- }
- }
+ // Last, fill all unused notches
+ if (entry.amountUnused > 0) {
+ for (let i = 0, total = entry.amountUnused; i < total; i++) {
+ textSuffix += notchNormalImage;
+ }
+ }
- textSuffix += `${p}
(${entry.amountTotal})`;
+ textSuffix += `${p}
(${entry.amountTotal})`;
- break;
+ break;
- case "geo":
- div = divFlex;
- span = ["", ""];
+ case "geo":
+ div = divFlex;
+ span = ["", ""];
- textSuffix += `${geoNormalImage}
${entry.amount}`;
- // Show Shade Geo value and image only if Shade has at least 1 Geo on it
- if (entry.amountShade > 0) textSuffix += `${p}+${geoShadeImage}
${entry.amountShade}`;
+ textSuffix += `${geoNormalImage}
${entry.amount}`;
+ // Show Shade Geo value and image only if Shade has at least 1 Geo on it
+ if (entry.amountShade > 0) textSuffix += `${p}+${geoShadeImage}
${entry.amountShade}`;
- // Show also total Geo (Geo + Shade Geo) if player has at least 1 geo alongside the shade geo
- if (entry.amount > 0 && entry.amountShade > 0) textSuffix += `${p}=${p}
${entry.amountTotal}`;
-
- p = "";
- break;
+ // Show also total Geo (Geo + Shade Geo) if player has at least 1 geo alongside the shade geo
+ if (entry.amount > 0 && entry.amountShade > 0) textSuffix += `${p}=${p}
${entry.amountTotal}`;
+
+ p = "";
+ break;
- default:
- }
+ default:
+ }
- // Optimized only for the "intro" section!
- if (entry.hasOwnProperty("spoilerAfter")) {
- spoilerAfter = ` ${entry.spoilerAfter}`;
- span[1] = "";
- }
- break;
+ // Optimized only for the "intro" section!
+ if (entry.hasOwnProperty("spoilerAfter")) {
+ spoilerAfter = ` ${entry.spoilerAfter}`;
+ span[1] = "";
+ }
+ break;
- case "hints":
- b = ["", ""];
- span = ["
", ""];
- icon = iconNull;
- break;
-
- default:
+ case "hints":
+ b = ["", ""];
+ span = ["
", ""];
+ icon = iconNull;
+ break;
+
+ default:
- span = ["
", ""];
- spoiler = ["
", ""];
+ span = ["
", ""];
+ spoiler = ["
", ""];
- if (entry.hasOwnProperty("amount")) {
- if (entry.hasOwnProperty("disabled")) {
- if (entry.disabled !== true) {
- textPrefix += `: ${entry.amount}`;
- }
- } else {
- textPrefix += `: ${entry.amount}`;
- }
- }
+ if (entry.hasOwnProperty("amount")) {
+ if (entry.hasOwnProperty("disabled")) {
+ if (entry.disabled !== true) {
+ textPrefix += `: ${entry.amount}`;
+ }
+ } else {
+ textPrefix += `: ${entry.amount}`;
+ }
+ }
- if (entry.hasOwnProperty("amountTotal")) {
- textPrefix += ` / ${entry.amountTotal}`;
- }
+ if (entry.hasOwnProperty("amountTotal")) {
+ textPrefix += ` / ${entry.amountTotal}`;
+ }
- if (entry.hasOwnProperty("id")) {
+ if (entry.hasOwnProperty("id")) {
- switch (entry.id) {
+ switch (entry.id) {
- case "geoRocks":
- case "itemsDiscovered":
- textPrefix += `: ${entry.notActivated} | ${entry.activated} | ${entry.discoveredTotal}`;
+ case "geoRocks":
+ case "itemsDiscovered":
+ textPrefix += `: ${entry.notActivated} | ${entry.activated} | ${entry.discoveredTotal}`;
- break;
+ break;
- case "zoteStatus":
- case "nailsmithStatus":
- if (entry.hasOwnProperty("currentName") && entry.hasOwnProperty("currentSpoiler")) {
- textPrefix = entry[entry.currentName];
- textSuffix = entry[entry.currentSpoiler];
- }
+ case "zoteStatus":
+ case "nailsmithStatus":
+ if (entry.hasOwnProperty("currentName") && entry.hasOwnProperty("currentSpoiler")) {
+ textPrefix = entry[entry.currentName];
+ textSuffix = entry[entry.currentSpoiler];
+ }
- break;
+ break;
- default:
- }
- }
+ default:
+ }
+ }
- if (entry.hasOwnProperty("disabled")) {
- if (entry.disabled === true) {
- textPrefix = `
${textPrefix}`;
- }
- }
-
- if (textSuffix.length && textPrefix.length) textSuffix = `— ${textSuffix}`;
- if (textPrefix.includes("
")) textSuffix = `${textSuffix}`;
- }
+ if (entry.hasOwnProperty("disabled")) {
+ if (entry.disabled === true) {
+ textPrefix = `${textPrefix}`;
+ }
+ }
+
+ if (textSuffix.length && textPrefix.length) textSuffix = `— ${textSuffix}`;
+ if (textPrefix.includes("")) textSuffix = `${textSuffix}`;
+ }
- */
- /* return [
+ */
+ /* return [
div,
icon,
`${b[0]}${textPrefix}${b[1]}`,
@@ -827,18 +827,18 @@ function SingleEntryFill(obj) {
].join("");
*/
- return [
- obj.div,
- obj.icon,
- `${obj.b[0]}${obj.textPrefix}${obj.b[1]}`,
- obj.span[0],
- obj.p,
- obj.spoiler[0],
- `${obj.textSuffix}${obj.spoilerAfter}`,
- obj.spoiler[1],
- obj.span[1],
- "\n"
- ].join("");
+ return [
+ obj.div,
+ obj.icon,
+ `${obj.b[0]}${obj.textPrefix}${obj.b[1]}`,
+ obj.span[0],
+ obj.p,
+ obj.spoiler[0],
+ `${obj.textSuffix}${obj.spoilerAfter}`,
+ obj.spoiler[1],
+ obj.span[1],
+ "
\n"
+ ].join("");
}
@@ -848,7 +848,7 @@ function SingleEntryFill(obj) {
* @param {string} content HTML contents to append
*/
function AppendHTML(divId, content) {
- document.getElementById(divId.id).innerHTML += "\n" + content;
+ document.getElementById(divId.id).innerHTML += "\n" + content;
}
/**
@@ -856,51 +856,51 @@ function AppendHTML(divId, content) {
* @param {string} param "hide", "show" or none (optional)
*/
function CheckboxHintsToggle(param = "none") {
- let checkboxId = document.getElementById("checkbox-hints");
+ let checkboxId = document.getElementById("checkbox-hints");
- switch (param) {
- case "hide":
- document.getElementById("hk-hints").classList.add("hidden");
- checkboxId.value = "hints-off";
- checkboxId.checked = false;
+ switch (param) {
+ case "hide":
+ document.getElementById("hk-hints").classList.add("hidden");
+ checkboxId.value = "hints-off";
+ checkboxId.checked = false;
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxHints", "unchecked");
- }
- break;
- case "show":
- document.getElementById("hk-hints").classList.remove("hidden");
- checkboxId.value = "hints-on";
- checkboxId.checked = true;
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxHints", "unchecked");
+ }
+ break;
+ case "show":
+ document.getElementById("hk-hints").classList.remove("hidden");
+ checkboxId.value = "hints-on";
+ checkboxId.checked = true;
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxHints", "checked");
- }
- break;
- default:
- // This runs when the checkbox is not checked
- if (checkboxId.checked === false) {
- document.getElementById("hk-hints").classList.add("hidden");
- checkboxId.value = "hints-off";
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxHints", "checked");
+ }
+ break;
+ default:
+ // This runs when the checkbox is not checked
+ if (checkboxId.checked === false) {
+ document.getElementById("hk-hints").classList.add("hidden");
+ checkboxId.value = "hints-off";
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxHints", "unchecked");
- }
- }
- // This runs when the checkbox is checked
- else {
- document.getElementById("hk-hints").classList.remove("hidden");
- checkboxId.value = "hints-on";
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxHints", "unchecked");
+ }
+ }
+ // This runs when the checkbox is checked
+ else {
+ document.getElementById("hk-hints").classList.remove("hidden");
+ checkboxId.value = "hints-on";
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxHints", "checked");
- }
- }
- }
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxHints", "checked");
+ }
+ }
+ }
}
/**
@@ -909,87 +909,87 @@ function CheckboxHintsToggle(param = "none") {
*/
function CheckboxSpoilersToggle(param = "none") {
- let checkboxId = document.getElementById("checkbox-spoilers");
- let allClassElements = document.querySelectorAll(".spoiler-span");
- let allClassElementsRed = document.querySelectorAll(".spoiler-red");
- let length = allClassElements.length;
- let lengthRed = allClassElementsRed.length;
+ let checkboxId = document.getElementById("checkbox-spoilers");
+ let allClassElements = document.querySelectorAll(".spoiler-span");
+ let allClassElementsRed = document.querySelectorAll(".spoiler-red");
+ let length = allClassElements.length;
+ let lengthRed = allClassElementsRed.length;
- switch (param) {
- case "hide":
- for (let i = 0; i < length; i++) {
- allClassElements[i].classList.add("blurred");
- }
+ switch (param) {
+ case "hide":
+ for (let i = 0; i < length; i++) {
+ allClassElements[i].classList.add("blurred");
+ }
- for (let i = 0; i < lengthRed; i++) {
- allClassElementsRed[i].classList.add("blurred");
- }
+ for (let i = 0; i < lengthRed; i++) {
+ allClassElementsRed[i].classList.add("blurred");
+ }
- checkboxId.value = "spoilers-off";
- checkboxId.checked = false;
+ checkboxId.value = "spoilers-off";
+ checkboxId.checked = false;
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxSpoilers", "unchecked");
- }
- break;
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxSpoilers", "unchecked");
+ }
+ break;
- case "show":
- for (let i = 0; i < length; i++) {
- allClassElements[i].classList.remove("blurred");
- }
+ case "show":
+ for (let i = 0; i < length; i++) {
+ allClassElements[i].classList.remove("blurred");
+ }
- for (let i = 0; i < lengthRed; i++) {
- allClassElementsRed[i].classList.remove("blurred");
- }
+ for (let i = 0; i < lengthRed; i++) {
+ allClassElementsRed[i].classList.remove("blurred");
+ }
- checkboxId.value = "spoilers-on";
- checkboxId.checked = true;
+ checkboxId.value = "spoilers-on";
+ checkboxId.checked = true;
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxSpoilers", "checked");
- }
- break;
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxSpoilers", "checked");
+ }
+ break;
- default:
- // This runs when the checkbox is not checked
- if (checkboxId.checked === false) {
+ default:
+ // This runs when the checkbox is not checked
+ if (checkboxId.checked === false) {
- for (let i = 0; i < length; i++) {
- allClassElements[i].classList.add("blurred");
- }
+ for (let i = 0; i < length; i++) {
+ allClassElements[i].classList.add("blurred");
+ }
- for (let i = 0; i < lengthRed; i++) {
- allClassElementsRed[i].classList.add("blurred");
- }
+ for (let i = 0; i < lengthRed; i++) {
+ allClassElementsRed[i].classList.add("blurred");
+ }
- checkboxId.value = "spoilers-off";
+ checkboxId.value = "spoilers-off";
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxSpoilers", "unchecked");
- }
- break;
- }
- // This runs when the checkbox is checked
- else {
- for (let i = 0; i < length; i++) {
- allClassElements[i].classList.remove("blurred");
- }
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxSpoilers", "unchecked");
+ }
+ break;
+ }
+ // This runs when the checkbox is checked
+ else {
+ for (let i = 0; i < length; i++) {
+ allClassElements[i].classList.remove("blurred");
+ }
- for (let i = 0; i < lengthRed; i++) {
- allClassElementsRed[i].classList.remove("blurred");
- }
+ for (let i = 0; i < lengthRed; i++) {
+ allClassElementsRed[i].classList.remove("blurred");
+ }
- checkboxId.value = "spoilers-on";
+ checkboxId.value = "spoilers-on";
- // remember this choice for subsequent page visits and browser restarts
- if (StorageAvailable('localStorage')) {
- localStorage.setItem("hkCheckboxSpoilers", "checked");
- }
- }
- }
+ // remember this choice for subsequent page visits and browser restarts
+ if (StorageAvailable('localStorage')) {
+ localStorage.setItem("hkCheckboxSpoilers", "checked");
+ }
+ }
+ }
}
/**
@@ -999,27 +999,27 @@ function CheckboxSpoilersToggle(param = "none") {
* @returns {Boolean}
*/
function StorageAvailable(type) {
- var storage;
- try {
- storage = window[type];
- var x = '__storage_test__';
- storage.setItem(x, x);
- storage.removeItem(x);
- return true;
- } catch (e) {
- return e instanceof DOMException && (
- // everything except Firefox
- e.code === 22 ||
- // Firefox
- e.code === 1014 ||
- // test name field too, because code might not be present
- // everything except Firefox
- e.name === 'QuotaExceededError' ||
- // Firefox
- e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
- // acknowledge QuotaExceededError only if there's something already stored
- (storage && storage.length !== 0);
- }
+ var storage;
+ try {
+ storage = window[type];
+ var x = '__storage_test__';
+ storage.setItem(x, x);
+ storage.removeItem(x);
+ return true;
+ } catch (e) {
+ return e instanceof DOMException && (
+ // everything except Firefox
+ e.code === 22 ||
+ // Firefox
+ e.code === 1014 ||
+ // test name field too, because code might not be present
+ // everything except Firefox
+ e.name === 'QuotaExceededError' ||
+ // Firefox
+ e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
+ // acknowledge QuotaExceededError only if there's something already stored
+ (storage && storage.length !== 0);
+ }
}
/**
@@ -1029,8 +1029,8 @@ function StorageAvailable(type) {
*/
function FillInnerHTML(elementId, textFill) {
- const element = document.getElementById(elementId);
- element.innerHTML = textFill;
+ const element = document.getElementById(elementId);
+ element.innerHTML = textFill;
}
/**
@@ -1041,22 +1041,22 @@ function FillInnerHTML(elementId, textFill) {
*/
function SelectCopyInputText(mouseEvent, tooltipId = "", tooltipFill = "") {
- const element = document.getElementById(mouseEvent.target.id);
+ const element = document.getElementById(mouseEvent.target.id);
- // this prevents the un-selected effect after clicking the second time (clears all selection first)
- if (window.getSelection) {
- window.getSelection().removeAllRanges();
- }
+ // this prevents the un-selected effect after clicking the second time (clears all selection first)
+ if (window.getSelection) {
+ window.getSelection().removeAllRanges();
+ }
- element.focus(); // best to focus the element first before selecting
- element.select();
- element.setSelectionRange(0, 99999); // for mobile devices
+ element.focus(); // best to focus the element first before selecting
+ element.select();
+ element.setSelectionRange(0, 99999); // for mobile devices
- // Copy the text inside the text field to clipboard
- document.execCommand("copy");
+ // Copy the text inside the text field to clipboard
+ document.execCommand("copy");
- // optional tooltip showing
- if (tooltipFill.length && tooltipId.length) FillInnerHTML(tooltipId, tooltipFill);
+ // optional tooltip showing
+ if (tooltipFill.length && tooltipId.length) FillInnerHTML(tooltipId, tooltipFill);
}
/* ========================== Event Listeners ========================== */
@@ -1065,33 +1065,33 @@ function SelectCopyInputText(mouseEvent, tooltipId = "", tooltipFill = "") {
document.addEventListener("scroll", () => {
- TogglePageScrollElement(
- /* the document element root () */
- ROOT,
- /* Which element to toggle visibility */
- SCROLL_BUTTON,
- /* How far the user has to scroll to show the element */
- 0.1);
+ TogglePageScrollElement(
+ /* the document element root () */
+ ROOT,
+ /* Which element to toggle visibility */
+ SCROLL_BUTTON,
+ /* How far the user has to scroll to show the element */
+ 0.1);
});
/* ---------------- Scroll to top when clicked ------------------- */
SCROLL_BUTTON.addEventListener("click", () => {
- ScrollToElement(ROOT);
+ ScrollToElement(ROOT);
});
/* ------------- Auto select & copy to clipboard when the save file location input text is clicked once ------------- */
document.getElementById("save-location-input").addEventListener("click", (e) => {
- SelectCopyInputText(e, "save-location-input-tooltip", "Copied save location to clipboard");
+ SelectCopyInputText(e, "save-location-input-tooltip", "Copied save location to clipboard");
}, false);
/* -------------- Switch text back to the default on mouse out -------------- */
document.getElementById("save-location-input").addEventListener("mouseout", () => {
- FillInnerHTML("save-location-input-tooltip", "Click once to copy to clipboard");
+ FillInnerHTML("save-location-input-tooltip", "Click once to copy to clipboard");
}, false);
/* ------------- Checkbox functions ---------------------- */
@@ -1103,81 +1103,81 @@ document.getElementById("checkbox-spoilers").addEventListener("click", CheckboxS
window.addEventListener('dragover', (event) => {
- event.stopPropagation();
- event.preventDefault();
+ event.stopPropagation();
+ event.preventDefault();
- // Style the drag-and-drop as a "copy file" operation.
- event.dataTransfer.dropEffect = 'copy';
+ // Style the drag-and-drop as a "copy file" operation.
+ event.dataTransfer.dropEffect = 'copy';
});
window.addEventListener('drop', (event) => {
- event.stopPropagation();
- event.preventDefault();
+ event.stopPropagation();
+ event.preventDefault();
- const dt = event.dataTransfer;
+ const dt = event.dataTransfer;
- /* Launch save file analyzing */
- LoadSaveFile(dt, new Date());
+ /* Launch save file analyzing */
+ LoadSaveFile(dt, new Date());
});
/* ---------- Monitor file input change and show the file name when file is loaded ----------- */
document.getElementById("save-area-file").addEventListener("change", (event) => {
- var label = document.getElementById("save-area-file").nextElementSibling;
- var labelInitialText = label.innerHTML;
+ var label = document.getElementById("save-area-file").nextElementSibling;
+ var labelInitialText = label.innerHTML;
- var fileName = event.target.files[0].name;
+ var fileName = event.target.files[0].name;
- /* Shorten the file name if too long */
- if (fileName.length > 16) {
+ /* Shorten the file name if too long */
+ if (fileName.length > 16) {
- let begin = fileName.slice(0, 10); // take 10 characters from the beginning (0)
- let end = fileName.slice(-4); // take 4 characters from the end (-)
- fileName = `${begin}..${end}`;
- }
+ let begin = fileName.slice(0, 10); // take 10 characters from the beginning (0)
+ let end = fileName.slice(-4); // take 4 characters from the end (-)
+ fileName = `${begin}..${end}`;
+ }
- var fileDate = new Date(event.target.files[0].lastModified);
+ var fileDate = new Date(event.target.files[0].lastModified);
- var year = fileDate.getFullYear();
- var month = fileDate.getMonth() + 1;
- var day = fileDate.getDate();
- var hour = fileDate.getHours();
- var minutes = fileDate.getMinutes();
- var seconds = fileDate.getSeconds();
+ var year = fileDate.getFullYear();
+ var month = fileDate.getMonth() + 1;
+ var day = fileDate.getDate();
+ var hour = fileDate.getHours();
+ var minutes = fileDate.getMinutes();
+ var seconds = fileDate.getSeconds();
- if (month < 10) month = "0" + month;
- if (day < 10) day = "0" + day;
- if (hour < 10) hour = "0" + hour;
- if (minutes < 10) minutes = "0" + minutes;
- if (seconds < 10) seconds = "0" + seconds;
+ if (month < 10) month = "0" + month;
+ if (day < 10) day = "0" + day;
+ if (hour < 10) hour = "0" + hour;
+ if (minutes < 10) minutes = "0" + minutes;
+ if (seconds < 10) seconds = "0" + seconds;
- var fileDateFormat = `${year}.${month}.${day} ${hour}:${minutes}:${seconds}`;
+ var fileDateFormat = `${year}.${month}.${day} ${hour}:${minutes}:${seconds}`;
- if (fileName) {
- label.innerHTML = `${SYMBOL_FILE}${fileName} ${fileDateFormat}`;
- } else {
- label.innerHTML = labelInitialText;
- }
+ if (fileName) {
+ label.innerHTML = `${SYMBOL_FILE}${fileName} ${fileDateFormat}`;
+ } else {
+ label.innerHTML = labelInitialText;
+ }
});
/* -------- Clean the text area and file input from leftover save file if present (Firefox especially) -------- */
document.addEventListener("DOMContentLoaded", () => {
- (async () => {
- document.getElementById("save-area").value = "";
- document.getElementById("save-area-file").value = "";
- })();
+ (async () => {
+ document.getElementById("save-area").value = "";
+ document.getElementById("save-area-file").value = "";
+ })();
});
/* ------------------------- Exports ------------------------------- */
export {
- GenerateInnerHTML,
- AppendHTML,
- CheckboxHintsToggle,
- CheckboxSpoilersToggle,
- StorageAvailable
+ GenerateInnerHTML,
+ AppendHTML,
+ CheckboxHintsToggle,
+ CheckboxSpoilersToggle,
+ StorageAvailable
};
\ No newline at end of file