`;\r\n\r\n break;*/\r\n\r\n /* Statistics */\r\n /*case \"statistics\":\r\n\r\n textFill += `
`;\r\n\r\n break;*/\r\n\r\n /* Godmaster */\r\n /*case \"godhomeStatistics\":\r\n\r\n textFill += `
`;*/\r\n\r\n break;\r\n }\r\n\r\n entries = sections[section].entries;\r\n\r\n /* ####################### Section div id start ########################## */\r\n\r\n /* starts a new
with the current section id */\r\n textFill += SectionStart(sections[section]);\r\n\r\n /* creates a
tag for the current section and fills with current%/max%\r\n If the save file was not analyzed, then fill only max% on blue background */\r\n if (db.saveAnalyzed === true) {\r\n textFill += CompletionFill(sections[section]);\r\n } else {\r\n textFill += CompletionFillNoSave(sections[section]);\r\n }\r\n\r\n\r\n /* ######################## Different behaviour depending on the section ###################################################### */\r\n\r\n\r\n switch (section) {\r\n\r\n /* ############### Game Status (intro) ################ */\r\n\r\n case \"intro\":\r\n\r\n /* ############## Create each single entry (intro) ############### */\r\n\r\n for (let entry in entries) {\r\n\r\n obj.b = [\"\", \"\"];\r\n obj.p = \"\";\r\n obj.span = [\"\", \"\"];\r\n obj.div = div;\r\n\r\n /* -------- Icons (next to each entry) --------- */\r\n if (entries[entry].hasOwnProperty(\"icon\")) {\r\n\r\n switch (entries[entry].icon) {\r\n\r\n case \"clock\":\r\n obj.icon = SYMBOL_CLOCK;\r\n break;\r\n case \"green\":\r\n obj.icon = SYMBOL_TRUE;\r\n break;\r\n case \"partial\":\r\n obj.icon = SYMBOL_PARTIAL;\r\n break;\r\n case \"revealed\":\r\n obj.icon = SYMBOL_EMPTY;\r\n break;\r\n case \"red\":\r\n obj.icon = SYMBOL_FALSE;\r\n break;\r\n default:\r\n obj.icon = SYMBOL_EMPTY;\r\n }\r\n } else {\r\n obj.icon = SYMBOL_FALSE;\r\n }\r\n\r\n obj.textPrefix = entries[entry].name;\r\n obj.textSuffix = entries[entry].spoiler;\r\n obj.spoilerAfter = \"\";\r\n\r\n /* Different text and images for each entry in the \"Game Status\" (intro) section */\r\n\r\n switch (entry) {\r\n case \"gameCompletion\":\r\n obj.textSuffix = `${obj.textSuffix} %`;\r\n obj.spoilerAfter = ` ${entries[entry].spoilerAfter}`;\r\n obj.span[1] = \"\";\r\n\r\n break;\r\n\r\n case \"gameCompletionExtended\":\r\n obj.spoilerAfter = ` ${entries[entry].spoilerAfter}`;\r\n obj.span[1] = \"\";\r\n\r\n break;\r\n\r\n case \"health\":\r\n\r\n /* ----------------- Horizontal Line after save version ---------------- */\r\n textFill += FLEUR_DIVIDE;\r\n\r\n obj.div = divFlex;\r\n obj.span = [\"\", \"\"];\r\n\r\n (entries[entry].permadeathMode) ? Img = maskSteel: Img = maskNormal;\r\n\r\n for (let i = 0, total = entries[entry].amountTotal; i < total; i++) {\r\n obj.textSuffix += Img;\r\n }\r\n\r\n obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;\r\n\r\n obj.p = \"\";\r\n break;\r\n\r\n case \"silk\":\r\n obj.div = divFlex;\r\n obj.span = [\"\", \"\"];\r\n Img = silkBarMiddle;\r\n\r\n obj.textSuffix += silkBarLeft;\r\n\r\n for (let i = 0, total = entries[entry].amountTotal; i < total; i++) {\r\n obj.textSuffix += Img;\r\n }\r\n obj.textSuffix += silkBarRight\r\n\r\n\r\n obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;\r\n\r\n obj.p = \"\";\r\n break;\r\n\r\n case \"crests\":\r\n obj.div = divFlex;\r\n obj.span = [\"\", \"\"];\r\n\r\n /* First, check filled (used) notches and fill them (skips if no filled notches) */\r\n /*if (entries[entry].amountFilled > 0) {\r\n for (let i = 0, total = entries[entry].amountTotal; i < total; i++) {\r\n obj.textSuffix += notchFilledImage;\r\n }\r\n }*/\r\n\r\n /* Second, check overcharmed notches and fill them (skips if player is not overcharmed) */\r\n /*if (entries[entry].amountOvercharmed > 0) {\r\n for (let i = 0, total = entries[entry].amountOvercharmed; i < total; i++) {\r\n obj.textSuffix += notchOvercharmedImage;\r\n }\r\n }*/\r\n\r\n /* Last, fill all unused notches */\r\n /*if (entries[entry].amountUnused > 0) {\r\n for (let i = 0, total = entries[entry].amountUnused; i < total; i++) {\r\n obj.textSuffix += notchNormalImage;\r\n }\r\n }*/\r\n \r\n /*for (let i = 0, total = entries[entry].amountTotal; i < total; i++) {\r\n obj.textSuffix += notchNormalImage;\r\n }*/\r\n\r\n if (entries[entry].hunter) obj.textSuffix += hunterCrestImage;\r\n if (entries[entry].toolmaster) obj.textSuffix += architectCrestImage ;\r\n if (entries[entry].beast) obj.textSuffix += beastCrestImage ;\r\n if (entries[entry].reaper) obj.textSuffix += reaperCrestImage ;\r\n if (entries[entry].shaman) obj.textSuffix += shamanCrestImage ;\r\n if (entries[entry].wanderer) obj.textSuffix += wandererCrestImage ;\r\n if (entries[entry].witch) obj.textSuffix += witchCrestImage ;\r\n\r\n\r\n obj.textSuffix += `${obj.p}(${entries[entry].amountTotal})`;\r\n\r\n break;\r\n\r\n case \"rosaries\":\r\n obj.div = divFlex;\r\n obj.span = [\"\", \"\"];\r\n\r\n obj.textSuffix += `${rosariesNormalImage}${entries[entry].amount}`;\r\n // Show Shade Rosaries value and image only if Shade has at least 1 Rosary on it\r\n if (entries[entry].amountShade > 0) obj.textSuffix += `${obj.p}+${rosariesShadeImage}${entries[entry].amountShade}`;\r\n\r\n // Show also total Rosaries (Rosaries + Shade Rosaries) if player has at least 1 Rosary alongside the shade rosaries\r\n if (entries[entry].amount > 0 && entries[entry].amountShade > 0) {\r\n obj.textSuffix += `${obj.p}=${obj.p}${entries[entry].amountTotal}`;\r\n }\r\n\r\n obj.p = \"\";\r\n break;\r\n \r\n case \"shellShards\":\r\n obj.div = divFlex;\r\n obj.span = [\"\", \"\"];\r\n\r\n obj.textSuffix += `${shellShardsImage}${entries[entry].amount}`;\r\n\r\n obj.p = \"\";\r\n break;\r\n\r\n default:\r\n }\r\n\r\n textFill += SingleEntryFill(obj);\r\n }\r\n\r\n break;\r\n\r\n /* #################### Hints (hints) #################### */\r\n\r\n case \"hints\":\r\n obj.b = [\"\", \"\"];\r\n obj.span = [\"\", \"\"];\r\n obj.icon = \"\";\r\n obj.textPrefix = \"\";\r\n obj.div = div;\r\n\r\n /* display only one (current) hint */\r\n obj.textSuffix = entries[sections[section].current].spoiler;\r\n\r\n textFill += SingleEntryFill(obj);\r\n\r\n break;\r\n\r\n /* ######################### Create all other sections ################################################################## */\r\n\r\n default:\r\n\r\n /* ###################### Create section descriptions under each H2 title ##################### */\r\n\r\n if (sections[section].hasOwnProperty(\"description\")) {\r\n textFill += SectionDescription(sections[section]);\r\n }\r\n\r\n /* ###################### Create each single entry (from all other sections) ##################### */\r\n\r\n for (let entry in entries) {\r\n\r\n /* obj.p = \"\"; */\r\n obj.p = \"\";\r\n obj.span = [\"\", \"\"];\r\n obj.spoiler = [\"\", \"\"];\r\n obj.div = div;\r\n obj.textPrefix = entries[entry].name;\r\n obj.textSuffix = `— ${entries[entry].spoiler}`;\r\n obj.wiki = entries[entry].wiki;\r\n\r\n /* -------- Icons (next to each entry) --------- */\r\n if (entries[entry].hasOwnProperty(\"icon\")) {\r\n\r\n switch (entries[entry].icon) {\r\n\r\n case \"clock\":\r\n obj.icon = SYMBOL_CLOCK;\r\n break;\r\n\r\n case \"green\":\r\n obj.icon = SYMBOL_TRUE;\r\n\r\n /* -------- Prevents hiding as spoiler when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n\r\n case \"partial\":\r\n obj.icon = SYMBOL_PARTIAL;\r\n break;\r\n\r\n case \"revealed\":\r\n obj.icon = SYMBOL_EMPTY;\r\n /* -------- Prevents textSuffix blurring when a player has already discovered the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n\r\n case \"partialJournal\":\r\n obj.icon = SYMBOL_PARTIAL;\r\n\r\n /* -------- Prevents textSuffix blurring when a player has already discovered the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n\r\n case \"bindingNail\":\r\n obj.icon = SYMBOL_BINDING_NAIL;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"bindingShell\":\r\n obj.icon = SYMBOL_BINDING_SHELL;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"bindingCharms\":\r\n obj.icon = SYMBOL_BINDING_CHARMS;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"bindingSoul\":\r\n obj.icon = SYMBOL_BINDING_SOUL;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"bindingAll\":\r\n obj.icon = SYMBOL_BINDING_ALL;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"attuned\":\r\n obj.icon = SYMBOL_ATTUNED;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"ascended\":\r\n obj.icon = SYMBOL_ASCENDED;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"radiant\":\r\n obj.icon = SYMBOL_RADIANT;\r\n\r\n /* -------- Prevents blurring when a player has already completed the entry --------- */\r\n obj.span[0] = \"\";\r\n break;\r\n \r\n case \"red\":\r\n obj.icon = SYMBOL_FALSE;\r\n break;\r\n\r\n default:\r\n obj.icon = SYMBOL_EMPTY;\r\n }\r\n } else {\r\n obj.icon = SYMBOL_FALSE;\r\n }\r\n\r\n /* assign the appropriate spoiler class name depending on the completion check (for blurring names) */\r\n if (entries[entry].hasOwnProperty(\"icon\")) {\r\n switch (entries[entry].icon) {\r\n\r\n case \"red\":\r\n case \"none\":\r\n obj.iconClass = \" spoiler-red blurred\";\r\n break;\r\n\r\n default:\r\n /* -------- Prevents TextPrefix blurring when a player has already discovered the entry --------- */\r\n obj.iconClass = \"\";\r\n }\r\n } else {\r\n obj.iconClass = \"\";\r\n }\r\n\r\n obj.b = [``, \"\"];\r\n\r\n if (entries[entry].hasOwnProperty(\"amount\")) {\r\n if (entries[entry].hasOwnProperty(\"disabled\")) {\r\n if (entries[entry].disabled !== true) {\r\n obj.textPrefix += `: ${entries[entry].amount}`;\r\n }\r\n } else {\r\n obj.textPrefix += `: ${entries[entry].amount}`;\r\n }\r\n }\r\n\r\n if (entries[entry].hasOwnProperty(\"amountTotal\")) {\r\n obj.textPrefix += ` / ${entries[entry].amountTotal}`;\r\n }\r\n\r\n if (entries[entry].hasOwnProperty(\"id\")) {\r\n\r\n switch (entries[entry].id) {\r\n\r\n case \"geoRocks\":\r\n case \"itemsDiscovered\":\r\n obj.textPrefix += `: ${entries[entry].notActivated} | ${entries[entry].activated} | ${entries[entry].discoveredTotal}`;\r\n\r\n break;\r\n\r\n default:\r\n }\r\n }\r\n\r\n if (entries[entry].hasOwnProperty(\"disabled\")) {\r\n if (entries[entry].disabled === true) {\r\n obj.textPrefix = `${obj.textPrefix}`;\r\n }\r\n }\r\n\r\n if (obj.textPrefix.includes(\"\")) obj.textSuffix = `${obj.textSuffix}`;\r\n\r\n /* textFill += SingleEntryFill(section, entries[entry]); */\r\n textFill += SingleEntryFill(obj);\r\n\r\n } /* end for (let entry in entries) */\r\n } /* end switch (section) - central */\r\n\r\n /* ############# Cumulate all section texts into one variable for final HTML filling. End section div tag ############### */\r\n\r\n finalHTMLFill += `${textFill}\\n
\\n\\n`;\r\n\r\n /* ################## End the Tab divs (must be after section ending div) ################# */\r\n\r\n switch (section) {\r\n\r\n /* ending the tabs */\r\n case \"toolPouchUpgrades\": // Main %\r\n case \"huntersJournal\": // Journal\r\n case \"flea\": // Collectibles\r\n case \"essentialsKeys\": // Essentials %\r\n\r\n /*case \"toolPouchUpgrades\": // Main %\r\n case \"achievementsBosses\": // Essentials %\r\n case \"huntersJournal\": // Journal\r\n case \"items\": // Collectibles\r\n case \"geoRocks\": // Geo Caches\r\n case \"corniferNotes\": // Secrets\r\n case \"statistics\": // Statistics\r\n case \"hallOfGods\": // Godmaster*/\r\n\r\n finalHTMLFill += `
`;\r\n\r\n break;\r\n\r\n }\r\n\r\n } /* end for (let section in sections) */\r\n\r\n /* console.groupCollapsed(\"finalHTMLFill\");\r\n console.log(finalHTMLFill);\r\n console.groupEnd(); */\r\n\r\n /* ################################## Horizontal line ############################################################################# */\r\n\r\n finalHTMLFill += FLEUR_DIVIDE;\r\n\r\n /* --------------- Final single HTML access and fill here ------------------ */\r\n\r\n document.getElementById(\"generated\").innerHTML = finalHTMLFill;\r\n\r\n /* make tab switch buttons working (on click) - must run after inner HTML generation is finished */\r\n\r\n document.querySelectorAll(\".tab-switch\").forEach((button) => {\r\n\r\n button.addEventListener(\"click\", (e) => {\r\n PageSwitchTab(e.target.name);\r\n });\r\n });\r\n\r\n /* Check local storage first, and set the last selected Tab on the page (remembers last clicked tab) */\r\n\r\n if (StorageAvailable('localStorage')) {\r\n\r\n if (localStorage.getItem(\"hkTabActive\")) {\r\n PageSwitchTab(localStorage.getItem(\"hkTabActive\"));\r\n } else {\r\n PageSwitchTab(\"main\");\r\n }\r\n }\r\n\r\n // finish benchmarking\r\n benchmarkTimes.GenerateInnerHTML.timeEnd = performance.now();\r\n}\r\n\r\nfunction SectionDescription(section) {\r\n\r\n return `
${section.description}
`;\r\n}\r\n\r\nfunction SectionStart(section) {\r\n\r\n return `
\\n`;\r\n}\r\n\r\n/**\r\n * Replaces the h2 titles with max percent values as read from the database\r\n */\r\nfunction CompletionFillNoSave(section) {\r\n\r\n let id = \"\";\r\n let h2 = \"\";\r\n let h2id = \"\";\r\n let percentBox = \"\"; // Percent Box\r\n let symbol = \"\";\r\n let fullString = \"\";\r\n\r\n id = section.id;\r\n h2 = section.h2;\r\n h2id = \"h2-\" + section.id;\r\n\r\n /* Display % only when showing Main Game Completion % sections */\r\n switch (section.id) {\r\n\r\n case \"hk-intro\":\r\n case \"hk-crests\":\r\n case \"hk-Needleupgrades\":\r\n case \"hk-redTools\":\r\n case \"hk-blueTools\":\r\n case \"hk-yellowTools\":\r\n case \"hk-equipment\":\r\n case \"hk-skills\":\r\n case \"hk-silkHeart\":\r\n case \"hk-miscellaneous\":\r\n case \"hk-spoolFragments\":\r\n case \"hk-maskshards\":\r\n case \"hk-craftingKitUpgrades\":\r\n case \"hk-toolPouchUpgrades\":\r\n\r\n /*case \"hk-charms\":\r\n case \"hk-bosses\":\r\n case \"hk-nailupgrades\":\r\n case \"hk-nailarts\":\r\n case \"hk-spells\":\r\n case \"hk-vesselfragments\":\r\n case \"hk-dreamnail\":\r\n case \"hk-warriordreams\":\r\n case \"hk-dreamers\":\r\n case \"hk-colosseum\":\r\n case \"hk-grimmtroupe\":\r\n case \"hk-lifeblood\":\r\n case \"hk-godmaster\":*/\r\n\r\n symbol = \"%\";\r\n\r\n break;\r\n\r\n default:\r\n\r\n symbol = \"\";\r\n }\r\n\r\n percentBox = `
${(id === \"hk-intro\") ? 0: section.maxPercent}${symbol}
`;\r\n if (!section.hasOwnProperty(\"maxPercent\")) percentBox = \"\";\r\n\r\n fullString += `
${h2}${percentBox}
`;\r\n\r\n // ----------------- add True Completion h2 title ---------------- //\r\n switch (id) {\r\n\r\n case \"hk-intro\":\r\n fullString += `
True Completion
0.00%
`;\r\n break;\r\n default:\r\n }\r\n\r\n return fullString;\r\n}\r\n\r\n/**\r\n * Replaces the h2 titles with a current percent/max percent values as read from the database\r\n */\r\nfunction CompletionFill(section) {\r\n\r\n let h2 = section.h2;\r\n let h2id = `
`;\r\n let cl = \"\";\r\n let clGreen = \"box-green\";\r\n let clRed = \"box-red\";\r\n let cp = 0; // current Percent\r\n let midP = 0; // middle Percent\r\n let mp = 0; // max Percent\r\n let trueCompletionCurrent = 0;\r\n let trueCompletionTotal = 0;\r\n let trueCompletionPercent = 0; // True Completion %\r\n let symbol = \"\";\r\n let percentBox = \"\";\r\n let fullString = \"\";\r\n\r\n (section.hasOwnProperty(\"percent\")) ? cp = section.percent: cp = 0;\r\n\r\n (section.hasOwnProperty(\"midPercent\")) ? midP = section.midPercent: midP = 0;\r\n\r\n // Don't use percent-box for Essentials, Achievements, Statistics etc.\r\n if (!section.hasOwnProperty(\"maxPercent\")) {\r\n percentBox = \"\";\r\n }\r\n // otherwise use percent-box with values cp/mp%\r\n else {\r\n\r\n mp = section.maxPercent;\r\n\r\n // Shards and Fragments correct calculations\r\n if (section.id === \"hk-maskshards\") {\r\n let perc = section.percent;\r\n (perc % 4) ? cp = Math.floor(perc / 4): cp = perc / 4;\r\n } else if (section.id === \"hk-spoolFragments\") {\r\n let perc = section.percent;\r\n (perc % 2) ? cp = Math.floor(perc / 2): cp = perc / 2;\r\n }\r\n\r\n // switches the box to red when a section (h2) is 0\r\n if (cp === 0) {\r\n cl = ` ${clRed}`;\r\n }\r\n // switches the box to green when a section (h2) is completed\r\n else if (cp === mp) {\r\n cl = ` ${clGreen}`;\r\n }\r\n // default is blue (partially completed and starting value)\r\n else cl = \"\";\r\n\r\n // Select which symbol or text to display (/ or something else depending on the section)\r\n switch (section.id) {\r\n\r\n // needed for Game Status to show percentage properly (adds a slash for all boxes except the Game Status one)\r\n case \"hk-intro\":\r\n break;\r\n\r\n // Hunter's Journal entries, Completed/Encountered of Total, e.g. 23/134 of 146\r\n case \"hk-journal\":\r\n cp = `${cp}/${midP} of `;\r\n break;\r\n\r\n default:\r\n cp += \"/\";\r\n }\r\n\r\n /* Display % only when showing Main Game Completion % sections */\r\n switch (section.id) {\r\n\r\n case \"hk-intro\":\r\n\r\n // True Completion % reading and calculation for percent-box and box colors\r\n trueCompletionCurrent = section.extendedCompletionDone;\r\n trueCompletionTotal = section.extendedCompletionTotal;\r\n trueCompletionPercent = (trueCompletionCurrent / trueCompletionTotal) * 100;\r\n symbol = \"%\";\r\n\r\n break;\r\n case \"hk-intro\":\r\n case \"hk-crests\":\r\n case \"hk-Needleupgrades\":\r\n case \"hk-redTools\":\r\n case \"hk-blueTools\":\r\n case \"hk-yellowTools\":\r\n case \"hk-equipment\":\r\n case \"hk-skills\":\r\n case \"hk-silkHeart\":\r\n case \"hk-miscellaneous\":\r\n case \"hk-spoolFragments\":\r\n case \"hk-maskshards\":\r\n case \"hk-craftingKitUpgrades\":\r\n case \"hk-toolPouchUpgrades\":\r\n\r\n /*case \"hk-charms\":\r\n case \"hk-bosses\":\r\n case \"hk-nailupgrades\":\r\n case \"hk-nailarts\":\r\n case \"hk-spells\":\r\n case \"hk-vesselfragments\":\r\n case \"hk-dreamnail\":\r\n case \"hk-warriordreams\":\r\n case \"hk-dreamers\":\r\n case \"hk-colosseum\":\r\n case \"hk-grimmtroupe\":\r\n case \"hk-lifeblood\":\r\n case \"hk-godmaster\":*/\r\n\r\n symbol = \"%\";\r\n\r\n break;\r\n\r\n default:\r\n\r\n symbol = \"\";\r\n }\r\n\r\n percentBox = `
${(section.id === \"hk-intro\") ? cp: `${cp}${section.maxPercent}`}${symbol}
`;\r\n }\r\n\r\n fullString += `\\t${h2id}${h2}${percentBox}\\n`;\r\n\r\n // ----------------- add True Completion h2 title ---------------- //\r\n switch (section.id) {\r\n\r\n case \"hk-intro\":\r\n\r\n // switches the box to red when True Completion is 0\r\n if (trueCompletionCurrent === 0) {\r\n cl = ` ${clRed}`;\r\n }\r\n // switches the box to green when True Completion is 100.00%\r\n else if (trueCompletionCurrent === trueCompletionTotal) {\r\n cl = ` ${clGreen}`;\r\n }\r\n // default is blue (partially completed and starting value)\r\n else cl = \"\";\r\n\r\n fullString += `
\r\n True Completion
${trueCompletionPercent.toFixed(2)}${symbol}
\r\n `;\r\n break;\r\n default:\r\n }\r\n\r\n return fullString;\r\n}\r\n\r\n/* function SingleEntryFill(section, entry) { */\r\nfunction SingleEntryFill(obj) {\r\n\r\n return [\r\n obj.div,\r\n obj.icon,\r\n `${obj.b[0]}${obj.textPrefix}${obj.b[1]}`,\r\n obj.span[0],\r\n obj.p,\r\n obj.spoiler[0],\r\n `${obj.textSuffix}${obj.spoilerAfter}`,\r\n obj.spoiler[1],\r\n obj.span[1],\r\n \"
\\n\"\r\n ].join(\"\");\r\n\r\n}\r\n\r\n/**\r\n * Adds HTML string to an element with a given ID.\r\n * @param {object} divId object containing div ID of the HTML element to append to\r\n * @param {string} content HTML contents to append\r\n */\r\nfunction AppendHTML(divId, content) {\r\n document.getElementById(divId.id).innerHTML += \"\\n\" + content;\r\n}\r\n\r\nfunction ToggleSaveModeSwitch() {\r\n\r\n let mode = this.value;\r\n\r\n let chooseFileButtonLabel = document.getElementById(\"file-input-label\");\r\n let analyzeTextButton = document.getElementById(\"save-area-read\");\r\n let saveTextArea = document.getElementById(\"save-area\");\r\n\r\n if (mode === \"modeText\") {\r\n this.value = \"modeFile\";\r\n\r\n chooseFileButtonLabel.classList.remove(\"hidden\");\r\n analyzeTextButton.classList.add(\"hidden\");\r\n saveTextArea.classList.add(\"hidden\");\r\n /* alert(this.value); */\r\n } else {\r\n this.value = \"modeText\";\r\n\r\n chooseFileButtonLabel.classList.add(\"hidden\");\r\n analyzeTextButton.classList.remove(\"hidden\");\r\n saveTextArea.classList.remove(\"hidden\");\r\n /* Warning! focus() somehow makes the textarea text offset to the left */\r\n /* saveTextArea.focus(); */\r\n /* alert(this.value); */\r\n }\r\n}\r\n\r\n/**\r\n * Toggles display of \"hk-hints\". On click with no parameters or on demand when called with a parameter\r\n * @param {string} param \"hide\", \"show\" or none (optional)\r\n */\r\nfunction CheckboxHintsToggle(param = \"none\") {\r\n let checkboxId = document.getElementById(\"checkbox-hints\");\r\n\r\n switch (param) {\r\n case \"hide\":\r\n document.getElementById(\"hk-hints\").classList.add(\"hidden\");\r\n checkboxId.value = \"hints-off\";\r\n checkboxId.checked = false;\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxHints\", \"unchecked\");\r\n }\r\n break;\r\n case \"show\":\r\n document.getElementById(\"hk-hints\").classList.remove(\"hidden\");\r\n checkboxId.value = \"hints-on\";\r\n checkboxId.checked = true;\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxHints\", \"checked\");\r\n }\r\n break;\r\n default:\r\n // This runs when the checkbox is not checked\r\n if (checkboxId.checked === false) {\r\n document.getElementById(\"hk-hints\").classList.add(\"hidden\");\r\n checkboxId.value = \"hints-off\";\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxHints\", \"unchecked\");\r\n }\r\n }\r\n // This runs when the checkbox is checked\r\n else {\r\n document.getElementById(\"hk-hints\").classList.remove(\"hidden\");\r\n checkboxId.value = \"hints-on\";\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxHints\", \"checked\");\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Toggles display of \".spoiler-span\" class. On click with no parameters or on demand when called with a parameter\r\n * @param {string} param \"hide\", \"show\" or none (optional)\r\n */\r\nfunction CheckboxSpoilersToggle(param = \"none\") {\r\n\r\n let checkboxId = document.getElementById(\"checkbox-spoilers\");\r\n let allClassElements = document.querySelectorAll(\".spoiler-span\");\r\n let allClassElementsRed = document.querySelectorAll(\".spoiler-red\");\r\n let length = allClassElements.length;\r\n let lengthRed = allClassElementsRed.length;\r\n\r\n switch (param) {\r\n case \"hide\":\r\n for (let i = 0; i < length; i++) {\r\n allClassElements[i].classList.add(\"blurred\");\r\n }\r\n\r\n for (let i = 0; i < lengthRed; i++) {\r\n allClassElementsRed[i].classList.add(\"blurred\");\r\n }\r\n\r\n checkboxId.value = \"spoilers-off\";\r\n checkboxId.checked = false;\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxSpoilers\", \"unchecked\");\r\n }\r\n break;\r\n\r\n case \"show\":\r\n for (let i = 0; i < length; i++) {\r\n allClassElements[i].classList.remove(\"blurred\");\r\n }\r\n\r\n for (let i = 0; i < lengthRed; i++) {\r\n allClassElementsRed[i].classList.remove(\"blurred\");\r\n }\r\n\r\n checkboxId.value = \"spoilers-on\";\r\n checkboxId.checked = true;\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxSpoilers\", \"checked\");\r\n }\r\n break;\r\n\r\n default:\r\n // This runs when the checkbox is not checked\r\n if (checkboxId.checked === false) {\r\n\r\n for (let i = 0; i < length; i++) {\r\n allClassElements[i].classList.add(\"blurred\");\r\n }\r\n\r\n for (let i = 0; i < lengthRed; i++) {\r\n allClassElementsRed[i].classList.add(\"blurred\");\r\n }\r\n\r\n checkboxId.value = \"spoilers-off\";\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxSpoilers\", \"unchecked\");\r\n }\r\n break;\r\n }\r\n // This runs when the checkbox is checked\r\n else {\r\n for (let i = 0; i < length; i++) {\r\n allClassElements[i].classList.remove(\"blurred\");\r\n }\r\n\r\n for (let i = 0; i < lengthRed; i++) {\r\n allClassElementsRed[i].classList.remove(\"blurred\");\r\n }\r\n\r\n checkboxId.value = \"spoilers-on\";\r\n\r\n // remember this choice for subsequent page visits and browser restarts\r\n if (StorageAvailable('localStorage')) {\r\n localStorage.setItem(\"hkCheckboxSpoilers\", \"checked\");\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Hides all other tabs, except the one which button was clicked (shows only the chosen tab)\r\n * @param {String} clickedButton The click target (button clicked)\r\n */\r\nfunction PageSwitchTab(clickedButton) {\r\n\r\n let sectionList = document.querySelectorAll(\".large-section\");\r\n let buttonList = document.querySelectorAll(\".tab-switch\");\r\n\r\n /* Make Active Tab Visible */\r\n for (let i = 0, length = sectionList.length; i < length; i++) {\r\n\r\n /* Other tabs except the clicked one */\r\n if (sectionList[i].id !== `tab-${clickedButton}`) {\r\n\r\n if (!sectionList[i].classList.contains(\"hidden\")) {\r\n sectionList[i].classList.add(\"hidden\");\r\n }\r\n }\r\n /* The clicked tab */\r\n else {\r\n\r\n if (sectionList[i].classList.contains(\"hidden\")) {\r\n sectionList[i].classList.remove(\"hidden\");\r\n }\r\n }\r\n }\r\n\r\n /* Make Active Button stand out */\r\n for (let i = 0, length = buttonList.length; i < length; i++) {\r\n\r\n /* Other buttons except the clicked one */\r\n if (buttonList[i].id !== `button-switch-${clickedButton}`) {\r\n\r\n if (buttonList[i].classList.contains(\"tab-active\")) {\r\n buttonList[i].classList.remove(\"tab-active\");\r\n }\r\n }\r\n /* The clicked button */\r\n else {\r\n\r\n if (!buttonList[i].classList.contains(\"tab-active\")) {\r\n buttonList[i].classList.add(\"tab-active\");\r\n }\r\n }\r\n }\r\n\r\n /* remember this choice for subsequent page visits and browser restarts */\r\n if (StorageAvailable('localStorage')) {\r\n\r\n if (clickedButton) {\r\n localStorage.setItem(\"hkTabActive\", clickedButton);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Detects whether Storage is both supported and available.\r\n * MDN WebDocs https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#feature-detecting_localstorage\r\n * @param {Storage} type type of storage. Ex. \"localStorage\" or \"sessionStorage\"\r\n * @returns {Boolean}\r\n */\r\nfunction StorageAvailable(type) {\r\n var storage;\r\n try {\r\n storage = window[type];\r\n var x = '__storage_test__';\r\n storage.setItem(x, x);\r\n storage.removeItem(x);\r\n return true;\r\n } catch (e) {\r\n return e instanceof DOMException && (\r\n // everything except Firefox\r\n e.code === 22 ||\r\n // Firefox\r\n e.code === 1014 ||\r\n // test name field too, because code might not be present\r\n // everything except Firefox\r\n e.name === 'QuotaExceededError' ||\r\n // Firefox\r\n e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&\r\n // acknowledge QuotaExceededError only if there's something already stored\r\n (storage && storage.length !== 0);\r\n }\r\n}\r\n\r\n/**\r\n * Fills the innerHTML of a given HTML Element with provided contents\r\n * @param {string} elementId Element ID to update\r\n * @param {string} textFill Updated contents (innerHTML)\r\n */\r\nfunction FillInnerHTML(elementId, textFill) {\r\n\r\n const element = document.getElementById(elementId);\r\n element.innerHTML = textFill;\r\n}\r\n\r\n/**\r\n * Focuses, selects and copies to clipboard contents inside a clicked element. Includes optional tooltip update after the copying is done.\r\n * @param {MouseEvent} mouseEvent from the clicked element (AddEventListener)\r\n * @param {string} tooltipId Element ID of the tooltip to update\r\n * @param {string} tooltipFill Updated contents of the tooltip\r\n */\r\nfunction SelectCopyInputText(mouseEvent, tooltipId = \"\", tooltipFill = \"\") {\r\n\r\n const element = document.getElementById(mouseEvent.target.id);\r\n\r\n // this prevents the un-selected effect after clicking the second time (clears all selection first)\r\n if (window.getSelection) {\r\n window.getSelection().removeAllRanges();\r\n }\r\n\r\n element.focus(); // best to focus the element first before selecting\r\n element.select();\r\n element.setSelectionRange(0, 99999); // for mobile devices\r\n\r\n // Copy the text inside the text field to clipboard\r\n document.execCommand(\"copy\");\r\n\r\n // optional tooltip showing\r\n if (tooltipFill.length && tooltipId.length) FillInnerHTML(tooltipId, tooltipFill);\r\n}\r\n\r\nfunction FileNameFormat(file, nameLength, beginLength, endLength) {\r\n\r\n var fileName = file.name;\r\n\r\n /* Shorten the file name if too long */\r\n if (fileName.length > nameLength) {\r\n\r\n let begin = fileName.slice(0, beginLength); // take X characters from the beginning (0)\r\n let end = fileName.slice(-endLength); // take X characters from the end (-)\r\n fileName = `${begin}..${end}`;\r\n }\r\n\r\n return fileName;\r\n}\r\n\r\nfunction FileDateFormat(file) {\r\n\r\n var fileDate = new Date(file.lastModified);\r\n\r\n var year = fileDate.getFullYear();\r\n var month = fileDate.getMonth() + 1;\r\n var day = fileDate.getDate();\r\n var hour = fileDate.getHours();\r\n var minutes = fileDate.getMinutes();\r\n /* var seconds = fileDate.getSeconds(); */\r\n\r\n if (month < 10) month = \"0\" + month;\r\n if (day < 10) day = \"0\" + day;\r\n if (hour < 10) hour = \"0\" + hour;\r\n if (minutes < 10) minutes = \"0\" + minutes;\r\n /* if (seconds < 10) seconds = \"0\" + seconds; */\r\n\r\n return `${year}.${month}.${day} ${hour}:${minutes}`;\r\n}\r\n\r\n/* ========================== Event Listeners ========================== */\r\n\r\n/* --------------- Toggle visibility of scroll arrow ------------------ */\r\n\r\ndocument.addEventListener(\"scroll\", () => {\r\n\r\n TogglePageScrollElement(\r\n /* the document element root () */\r\n ROOT,\r\n /* Which element to toggle visibility */\r\n SCROLL_BUTTON,\r\n /* How far the user has to scroll to show the element */\r\n 0.1);\r\n});\r\n\r\n/* ---------------- Scroll to top when clicked ------------------- */\r\n\r\nSCROLL_BUTTON.addEventListener(\"click\", () => {\r\n ScrollToElement(ROOT);\r\n});\r\n\r\n/* ------------- Auto select & copy to clipboard when the save file location input text is clicked once ------------- */\r\n\r\ndocument.getElementById(\"save-location-input\").addEventListener(\"click\", (e) => {\r\n\r\n let tooltip = document.getElementById(\"save-location-input-tooltip\");\r\n\r\n SelectCopyInputText(e, \"save-location-input-tooltip\", \"Copied save files location to clipboard\");\r\n\r\n /* make sure that the tooltip is centered */\r\n tooltip.style.marginLeft = `-${tooltip.offsetWidth / 2}px`;\r\n}, false);\r\n\r\n/* -------------- Switch text back to the default on mouse out -------------- */\r\n\r\ndocument.getElementById(\"save-location-input\").addEventListener(\"mouseout\", () => {\r\n\r\n let tooltip = document.getElementById(\"save-location-input-tooltip\");\r\n\r\n /* change the text and center only when the text was different */\r\n if (tooltip.innerHTML !== \"Click once to copy to clipboard\") {\r\n\r\n FillInnerHTML(\"save-location-input-tooltip\", \"Click once to copy to clipboard\");\r\n\r\n /* make sure that the tooltip is centered */\r\n tooltip.style.marginLeft = `-${tooltip.offsetWidth / 2}px`;\r\n }\r\n}, false);\r\n\r\n/* ------------ Toggle Save Mode Switch: Text Mode or File Mode -------------- */\r\n\r\ndocument.getElementById(\"toggle-mode\").addEventListener(\"click\", ToggleSaveModeSwitch, false);\r\n\r\n/* ------------- Checkbox functions ---------------------- */\r\n\r\ndocument.getElementById(\"checkbox-hints\").addEventListener(\"click\", CheckboxHintsToggle, false);\r\ndocument.getElementById(\"checkbox-spoilers\").addEventListener(\"click\", CheckboxSpoilersToggle, false);\r\n\r\n/* ------------ Drag & drop file to the window -------------- */\r\n\r\nwindow.addEventListener('dragover', (event) => {\r\n\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n // Style the drag-and-drop as a \"copy file\" operation.\r\n event.dataTransfer.dropEffect = 'copy';\r\n});\r\n\r\nwindow.addEventListener('drop', (event) => {\r\n\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n const dt = event.dataTransfer;\r\n\r\n /* Launch save file analyzing */\r\n LoadSaveFile(dt, performance.now());\r\n\r\n var label = document.getElementById(\"save-area-file\").nextElementSibling;\r\n var labelInitialText = label.innerHTML;\r\n\r\n /* Shorten the file name if longer than 16 characters. Display first 10 characters and last 4. */\r\n var fileName = FileNameFormat(dt.files[0], 16, 10, 4);\r\n\r\n /* Display a custom formatted last modified date. */\r\n var fileDate = FileDateFormat(dt.files[0]);\r\n\r\n /* Display the save file name and date on the button */\r\n if (fileName) {\r\n label.innerHTML = `${SYMBOL_FILE}${fileName}
${fileDate}
`;\r\n } else {\r\n label.innerHTML = labelInitialText;\r\n }\r\n});\r\n\r\n/* ---------- Monitor file input change and show the file name when file is loaded ----------- */\r\n\r\ndocument.getElementById(\"save-area-file\").addEventListener(\"change\", (event) => {\r\n\r\n var label = document.getElementById(\"save-area-file\").nextElementSibling;\r\n var labelInitialText = label.innerHTML;\r\n\r\n /* Shorten the file name if longer than 16 characters. Display first 10 characters and last 4. */\r\n var fileName = FileNameFormat(event.target.files[0], 16, 10, 4);\r\n\r\n /* Display a custom formatted last modified date. */\r\n var fileDate = FileDateFormat(event.target.files[0]);\r\n\r\n if (fileName) {\r\n label.innerHTML = `${SYMBOL_FILE}${fileName}
${fileDate}
`;\r\n } else {\r\n label.innerHTML = labelInitialText;\r\n }\r\n});\r\n\r\n/* -------- Clean the text area and file input from leftover save file if present (Firefox especially) -------- */\r\n\r\ndocument.addEventListener(\"DOMContentLoaded\", () => {\r\n\r\n (async () => {\r\n document.getElementById(\"save-area\").value = \"\";\r\n document.getElementById(\"save-area-file\").value = \"\";\r\n })();\r\n});\r\n\r\n/* ------------------------- Exports ------------------------------- */\r\n\r\nexport {\r\n GenerateInnerHTML,\r\n AppendHTML,\r\n CheckboxHintsToggle,\r\n CheckboxSpoilersToggle,\r\n StorageAvailable,\r\n Benchmark,\r\n benchmarkTimes\r\n};","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","var scriptUrl;\nif (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + \"\";\nvar document = __webpack_require__.g.document;\nif (!scriptUrl && document) {\n\tif (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT')\n\t\tscriptUrl = document.currentScript.src;\n\tif (!scriptUrl) {\n\t\tvar scripts = document.getElementsByTagName(\"script\");\n\t\tif(scripts.length) {\n\t\t\tvar i = scripts.length - 1;\n\t\t\twhile (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src;\n\t\t}\n\t}\n}\n// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration\n// or pass an empty string (\"\") and set the __webpack_public_path__ variable from your code to use your own logic.\nif (!scriptUrl) throw new Error(\"Automatic publicPath is not supported in this browser\");\nscriptUrl = scriptUrl.replace(/^blob:/, \"\").replace(/#.*$/, \"\").replace(/\\?.*$/, \"\").replace(/\\/[^\\/]+$/, \"/\");\n__webpack_require__.p = scriptUrl;","// Handle cookies\r\n// require(\"./cookies.js\");\r\n\r\n// CSS\r\n// require(\"../css/cookieconsent.css\");\r\nrequire(\"../css/fontello.css\");\r\nrequire(\"../css/simpleicon.css\");\r\nrequire(\"../css/reznoricon.css\");\r\nrequire(\"../css/style.css\");\r\n\r\n// required for meta tags (social) to be visible by Webpack\r\nrequire(\"../img/thumbnail1200x628.jpg\");\r\n\r\nimport \"core-js\";\r\nimport \"regenerator-runtime/runtime.js\";\r\n\r\nrequire(\"./page-functions.js\");\r\n\r\n// Instantly load test save file from .json (fast Debugging script)\r\n// require(\"./LoadJson.js\");\r\n\r\n// Main script for analyzing the decoded save file and generating the page on the fly\r\nrequire(\"./HKCheckCompletion.js\");\r\n\r\n// Load Save File for opening files, decoding, decryption\r\nrequire(\"./LoadSaveFile.js\");"],"names":["HK","GenerateInnerHTML","AppendHTML","CheckboxHintsToggle","CheckboxSpoilersToggle","StorageAvailable","Benchmark","benchmarkTimes","SetIconGreen","SetIconPartial","SetIconPartialJournal","SetIconRed","SetIconNone","SetIcon","ObjectLength","TranslateMapName","GenerateDatabaseEntries","SYMBOL_FALSE","SYMBOL_TRUE","SYMBOL_CLOCK","SYMBOL_EMPTY","FLEUR_DIVIDE","WIKI_LINK","completionSymbol","divStart","join","divStartCenter","divEnd","pSpan","HKCheckCompletion","jsonObject","benchStart","arguments","length","undefined","performance","now","CheckCompletion","timeStart","HKPlayerData","HKWorldItems","HKSceneData","hasOwnProperty","playerData","saveAnalyzed","sceneData","persistentBools","saveDataChecker","DataChecker","ResetCompletion","CheckPlayTime","sections","intro","playTime","CheckCompletionPercent","CheckSaveFileVersion","version","CheckHealthMasks","maxHealthBase","permadeathMode","CheckSilkBar","silkMax","CheckCrests","CheckRosary","geo","HeroCorpseMoneyPool","CheckshellShards","ShellShards","CheckIfDataTrue","crests","entries","CheckNeedleUpgrades","NeedleUpgrades","silkHeart","redTools","Tools","savedData","blueTools","yellowTools","equipment","skills","miscellaneous","maskShards","spoolFragments","craftingKitUpgrades","toolPouchUpgrades","essentialsMemoryLocket","essentialsCraftmetal","essentialsKeys","flea","CheckHuntersJournal","CheckHintsTrue","hints","CheckExtendedCompletion","timeEnd","PrepareHTMLString","section","textPrefix","textSuffix","wiki","icon","b","concat","span","spoilerSpan","id","includes","seconds","Math","floor","minutes","hours","sec","timePlayed","timeH","timeM","timeS","textFill","spoiler","completionPercentage","round","maxPercent","maxPercentDefault","gameCompletion","spoilerAfter","spoilerAfterDefault","percent","maxPercentBaseGame","spoilerAfterBaseGame","db","gameCompletionExtended","amount","max","entry","extendedCompletionTotal","charms","gotCharm_9","extendedCompletionDone","disabled","toFixed","saveVersion","masks","health","amountTotal","totalSilk","silk","geoValue","geoPoolValue","rosaries","amountShade","shellShardsValue","shellShards","PlayerData","reaper","completedMemory_reaper","wanderer","completedMemory_wanderer","beast","completedMemory_beast","witch","completedMemory_witch","toolmaster","completedMemory_toolmaster","shaman","completedMemory_shaman","dataObject","worldData","checkText","_loop","i","foundArchitect","find","Name","foundForge","foundWeaver","Data","IsUnlocked","foundClaws","foundClawsUpgrade","foundMosscreep","foundMosscreepUpgrade","foundDazzle","foundDazzleUpgrade","foundBombNormal","foundBombSteel","foundData","exist","scenesVisited","indexOf","wishList","QuestCompletionData","foundWish","sceneName","IsCompleted","scenel","serializedList","CraftPickupToolitem","SceneName","ID","Value","pinGalleriesCompleted","sceneList","sceneInfo","CheckSpellLevel","fireballLevel","quakeLevel","screamLevel","CheckWarriorDreams","sFillText","name","CheckGodmasterDoors","property","completed","Needle","map","element","nailUpgrades","WorldDataActivated","idText","sceneNameText","activated","CheckAdditionalThings","saveFile","persistentBoolItems","_","countTotal","total","notActivated","discoveredTotal","CountWorldItem","journalEntriesTotal","spoilerDefault","zoteRescuedBuzzer","hasWalljump","destroyedNightmareLantern","killedFlameBearerLarge","grubsCollected","zoteDead","abs","xunFlowerGiven","bankerAccountPurchased","bankerTheft","bankerBalance","CountItems","hasSlykey","gaveSlykey","hasWhiteKey","usedWhiteKey","hasLoveKey","openedLoveDoor","dreamReward3","FindWorldItem","grimmChildLevel","nameHeld","nameSold","bossDoorStateTier5","killedVoidIdol_2","killedVoidIdol_3","nameDefault","nameNeglect","spoilerNeglect","killedZote","nameRivalry","spoilerRivalry","nameTrappedVengefly","spoilerTrappedVengefly","nameNotRescuedVengefly","spoilerNotRescuedVengefly","zoteRescuedDeepnest","nameTrappedDeepnest","spoilerTrappedDeepnest","nameColosseum","spoilerColosseum","nailsmithKilled","namePurity","spoilerPurity","nailsmithConvoArt","nameHappyCouple","spoilerHappyCouple","nailsmithSpared","nameSheoHutWaiting","spoilerSheoHutWaiting","nameUpgradeNail","spoilerUpgradeNail","CheckMrMushroomState","stagStationsOpened","areaMaps","itemId","arrayLength","mode","itemsLog","semiPersistent","push","console","log","groupCollapsed","groupEnd","mrMushroomState","state","sectionName","amountKillsLeft","journalPlayerList","EnemyJournalKillData","list","_loop2","MonsterInfo","databaseName","Record","Kills","killRequire","gameName","CheckPantheon","CheckHallOfGods","hallOfGods","check","isUnlocked","killedHollowKnight","current","GruzMotherDefeated","k","defeatedDungDefender","hornetOutskirtsDefeated","hasAcidArmour","hasKingsBrand","hasShadowDash","HKReadTextArea","textAreaId","contents","document","getElementById","value","InitializeHTMLPopulation","JSON","parse","result","info","error","alert","localStorage","getItem","checked","midPercent","maxDefault","_classCallCheck","boolData","geoRocksData","geoRocks","_createClass","key","_FindItem","_FindGeoRock","hitsLeft","checkItems","grub32","spoilerSteelSoul","idPlayerData","spoilerNormal","checkGeoRocks","addEventListener","e","t","r","Symbol","n","iterator","o","toStringTag","c","prototype","Generator","u","Object","create","_regeneratorDefine2","f","p","y","G","v","a","d","bind","l","TypeError","call","done","GeneratorFunction","GeneratorFunctionPrototype","getPrototypeOf","setPrototypeOf","__proto__","displayName","_regenerator","w","m","defineProperty","_regeneratorDefine","_invoke","enumerable","configurable","writable","asyncGeneratorStep","Promise","resolve","then","_asyncToGenerator","apply","_next","_throw","aesjs","require","CSHARP_HEADER","BASE64_ARRAY","split","charCodeAt","BASE64_DECODE_TABLE","Map","ord","AES_KEY","TextEncoder","encode","ECB_STREAM_CIPHER","ModeOfOperation","ecb","LoadSaveFile","input","time","inputFileList","files","Total","inputFileObject","inputReader","FileReader","readAsArrayBuffer","ProcessFileObject","inputArrayBuffer","decodedString","Uint8Array","slice","RemoveHeaders","Base64Decode","AESDecryption","TextDecoder","decode","_callee","_context","buffer","csHeader","subarray","lengthCount","get","end","output","continuous","cipherObject","decrypt","event","target","mouseEvent","root","checkInt","parseInt","checkInts","arrayish","coerceArray","arg","copy","ArrayBuffer","isView","Array","isArray","Error","createArray","copyArray","sourceArray","targetArray","targetStart","sourceStart","sourceEnd","set","convertUtf8","toBytes","text","encodeURI","substr","fromBytes","bytes","String","fromCharCode","convertHex","Hex","numberOfRounds","rcon","S","Si","T1","T2","T3","T4","T5","T6","T7","T8","U1","U2","U3","U4","convertToInt32","AES","_prepare","rounds","_Ke","_Kd","roundKeyCount","KC","tk","index","rconpointer","tt","encrypt","plaintext","ciphertext","ModeOfOperationECB","description","_aes","block","ModeOfOperationCBC","iv","_lastCipherblock","j","ModeOfOperationCFB","segmentSize","_shiftRegister","encrypted","xorSegment","ModeOfOperationOFB","_lastPrecipher","_lastPrecipherIndex","Counter","initialValue","_counter","setValue","setBytes","increment","ModeOfOperationCTR","counter","_remainingCounter","_remainingCounterIndex","pkcs7pad","data","padder","pkcs7strip","cbc","cfb","ofb","ctr","utils","hex","utf8","padding","pkcs7","pad","strip","_arrayTest","exports","module","define","amd","_aesjs","h2","hunter","hornet1Defeated","hasDash","Crossroads_04","slyRescued","hasLantern","hasSuperDash","hasDreamNail","killedInfectedKnight","hasDoubleJump","dungDefenderOrHornet2","ismaTearOrShadeCloak","defeatedMegaJelly","monomonDefeated","hegemolDefeated","killedBlackKnight","lurienDefeated","endOfHints","startingNeedle","sharpenedNeedle","shiningNeedle","hivesteelNeedle","paleSteelNeedle","Memory_Silk_Heart_BellBeast","Memory_Silk_Heart_WardBoss","Memory_Silk_Heart_LaceTower","straightPin","triPin","stingShard","Tack","harpoon","curveClaws","shakraRing","pimpilo","conchDrill","webShot","screwAttack","cogworkSaw","cogworkFlier","rosaryCannon","lightningRod","flintstone","fleaBrew","lifebloodSyringe","mosscreepTool","lavaCharm","bellBind","poisonPouch","fracturedMask","multibind","whiteRing","brollySpike","quickbind","spoolExtender","reserveBind","DazzleBind","revengeCrystal","thiefClaw","zapImbuement","quickSling","maggotCharm","longneedle","wispLantern","fleaCharm","pinstressTool","compass","boneNecklace","rosaryMagnet","weightedAnklet","barbedWire","deadMansPurse","magnetiteDice","scuttlebrace","Wallcling","musicianCharm","sprintmaster","thiefCharm","silkSpear","threadSphere","Parry","silkCharge","silkBomb","silkBossNeedle","hasHarpoonDash","hasNeedolin","hasChargeSlash","hasSuperJump","HasSeenEvaHeal","CompletedRedMemory","PurchasedBonebottomHeartPiece","wormwayMask","deepDocksMask","farFieldsMask1","shellwoodMask","weavenestAtlaMask","MerchantEnclaveShellFragment","cogworkCoreMask","libraryMask","beastflyHuntWish","boneBuildingMask","mountFayMask","slabMask","bilewaterMask","wispThicketMask","blastedStepsMask","brightveinMask","sprintmasterRaceWish","destroyThreadCoresWish","antTrapperWish","boneBottomSpool","deepDocksSpool1","greymoorSpool","PurchasedBelltownSpoolSegment","weavenestAtlaSpool","slabSpool","grandGateSpool","UnderworksSpool1","MetCaravanTroupeLeaderJudge","whitewardSpool","cogworkCoreSpool","UnderworksSpool2","saveShermaWish","MerchantEnclaveSpoolPiece","deepDocksSpool2","highHallsSpool","MemoriumSpool","purchasedGrindleSpoolPiece","PurchasedForgeToolKit","crowFeathersWish","PurchasedArchitectToolKit","purchasedGrindleToolKit","PurchasedPilgrimsRestToolPouch","ladybugCraftPickupToolPouch","journalWish","CaravanTroupeLocation","marrowMemoryLocket","hunterMarchMemoryLocket","PurchasedPilgrimsRestMemoryLocket","greymoorMemoryLocket01","rockRollersWish","PurchasedBelltownMemoryLocket","blastedStepsMemoryLocket","wormwaysMemoryLocket","bilewaterMemoryLocket01","choralChambersMemoryLocket","underworksMemoryLocket","deepDocksMemoryLocket","whisperingVaultsMemoryLocket","sandsOfKarakMemoryLocket","greymoorMemoryLocket02","MemoriumMemoryLocket","slabMemoryLocket","BilewaterMemoryLocket02","bellhartMemoryLocket","farFieldsMemoryLocket","PurchasedBonebottomToolMetal","marrowCraftmetal","deepDocksCraftmetal","blastedStepsCraftmetal","MerchantEnclaveToolMetal","wispThicketCraftmetal","underworksCraftmetal","putrifiedDuctsCraftmetal","_defineProperty","purchasedGrindleSimpleKey","CollectedDustCageKey","MerchantEnclaveSimpleKey","bellshrineCoralSimpleKey","HasSlabKeyA","HasSlabKeyB","HasSlabKeyC","collectedWardBossKey","BelltownGreeterHouseFullDlg","BallowGivenKey","huntersJournal","mossBoneCrawler","mossBoneCrawlerFat","mossBoneFly","mossboneMother","aspidCollector","boneGoomba","boneGoombaBounceFly","boneGoombaLarge","skullKing","boneCrawler","boneFlyer","boneFlyerGiant","boneCircler","boneCirclerVicious","boneHopper","boneHopperGiant","boneSpitter","boneRoller","boneThumper","spineFloater","rockRoller","rhino","cryptWorm","boneWorm","boneBeast","pilgrim03","pilgrim01","pilgrim04","pilgrim02","pilgrimBellThrower","pilgrimFly","pilgrim05","pilgrimBellthrowerFly","pilgrimHiker","pilgrimStaffWielder","pilgrimMossSpitter","rosaryPilgrim","rosaryThief","tarSlug","tarSlugHuge","dockWorker","dockFlyer","dockBomber","shieldDockWorker","dockCharger","dockGuardThrower","smallCrab","roofCrab","fieldsFlockFlyers","fieldsGoomba","fieldsFlyer","songGolem","boneHunterTiny","boneHunterBuzzer","boneHunterChild","boneHunter","boneHunterFly","boneHunterThrow","boneHunterTrapper","boneHunterChief","hunterQueen","mite","mitefly","gnatGiant","farmerCatcher","farmerScissors","farmerCentipede","vampireGnat","wisp","farmerWisp","wispPyreEffigy","crow","crowman","crowmanDagger","crowmanJurorTiny","crowmanJuror","crowmanDaggerJuror","crawfather","maggots","dustroachPollywog","dustroach","bloatRoach","roachfeederShort","roachfeederTall","roachkeeper","roachkeeperChefTiny","roachkeeperChef","wraith","swampDrifter","swampGoomba","swampMosquito","swampMosquitoSkinny","swampMuckman","swampMuckmanTall","swampShaman","swampBarnacle","swampDuctsucker","pondSkater","pilgrimFisher","shellwoodGnat","shellwoodWasp","stickInsect","stickInsectCharger","stickInsectFlyer","splinterQueen","flowerDrifter","bloomShooter","bloomPuncher","seth","flowerQueen","bellGoomba","bellFly","bladeSpider","bladeSpiderHang","shellFossilMimic","sandCentipede","coralJudgeChild","coralJudge","lastJudge","coralSpikeGoomba","coralConchShooter","coralConchShooterHeavy","coralConchStabber","coralConchDriller","coralConchDrillerGiant","coralGoombas","coralGoombaLarge","coralSwimmerFat","pokeSwimmer","spikeSwimmer","coralSwimmerSmall","coralBigJellyfish","coralWarrior","coralFlyer","coralFlyerThrow","coralBrawler","coralHunter","coralBubbleBrute","coralKing","coralWarriorGrey","zapCoreEnemy","citadelBat","citadelBatLarge","miteHeavy","understoreMiteGiant","understoreSmall","pilgrim03Understore","pilgrimStaffUnderstore","understorePoker","understoreThrower","understoreHeavy","songPilgrim01","pilgrim01Song","pilgrim02Song","pilgrim03Song","pilgrim04Song","pilgrimStomperSong","songPilgrim03","songReed","songReedGrand","songHeavySentry","songHandmaiden","arboriumKeeper","songAdministrator","songPilgrimMaestro","songKnight","songThreadedHusk","songThreadedHuskSpin","songPilgrim02","songCreeper","conductorBoss","understoreAutomaton","understoreAutomatonEX","songAutomatonGoomba","songAutomatonFly","songAutomatonFlySpike","songAutomaton01","songAutomaton02","songAutomatonShield","songAutomatonBall","clockworkDancer","songScholarAcolyte","lightbearer","scrollkeeper","scholar","trobbio","tormentedTrobbio","slabPrisonerLeaperNew","slabPrisonerFlyNew","slabFlySmallFresh","slabFlySmall","slabFlyMid","slabFlyLarge","slabFlyBroodmother","peaksDrifter","crystalDrifter","crystalDrifterGiant","weaverServitor","weaverServitorLarge","lifebloodFly","boneWormBlueBlood","boneWormBlueTurret","blueAssistant","lilypadFly","grassGoomba","hornetDragonfly","dragonflyLarge","lilypadTrap","cloverstag","cloverstagWhite","grasshopperChild","grasshopperSlasher","grasshopperFly","cloverDancer","abyssCrawler","abyssCrawlerLarge","gloomfly","gloomBeast","voidTendrils","blackThreadCore","whitePalaceFly","centipedeTrap","spikeLazyFlyer","surfaceScuttler","giantCentipede","giantFlea","garmond","pinstressBoss","spinnerBoss","firstWeaver","phantom","lace","silkBoss","lostLace","SavedFlea_Bone_06","SavedFlea_Dock_16","SavedFlea_Bone_East_05","SavedFlea_Dock_03d","SavedFlea_Ant_03","SavedFlea_Bone_East_17b","SavedFlea_Bone_East_10_Church","SavedFlea_Crawl_06","SavedFlea_Greymoor_15b","SavedFlea_Greymoor_06","CaravanLechReturnedToCaravan","SavedFlea_Belltown_04","SavedFlea_Shellwood_03","SavedFlea_Coral_35","SavedFlea_Dust_12","SavedFlea_Shadow_28","SavedFlea_Dust_09","SavedFlea_Shadow_10","SavedFlea_Under_23","SavedFlea_Under_21","SavedFlea_Song_14","SavedFlea_Song_11","SavedFlea_Library_09","tamedGiantFlea","SavedFlea_Slab_Cell","SavedFlea_Slab_06","SavedFlea_Peak_05c","SavedFlea_Coral_24","MetTroupeHunterWild","SavedFlea_Library_01","MAP","object","mapCode","dictionary","translation","objectArray","searchText","entryName","entryDB","fillText","count","ln","HEALTH_MASK_IMAGE","HEALTH_MASK_STEEL_IMAGE","SILKBAR_LEFT_IMAGE","SILKBAR_MIDDLE_IMAGE","SILKBAR_RIGHT_IMAGE","ROSARIES_IMAGE","ROSARIES_SHADE_IMAGE","SHELL_SHARDS_IMAGE","ARCHITECT_CREST_IMAGE","BEAST_CREST_IMAGE","HUNTER_CREST_IMAGE","REAPER_CREST_IMAGE","SHAMAN_CREST_IMAGE","WANDERER_CREST_IMAGE","WITCH_CREST_IMAGE","SYMBOL_PARTIAL","SYMBOL_FILE","SYMBOL_BINDING_NAIL","SYMBOL_BINDING_SHELL","SYMBOL_BINDING_CHARMS","SYMBOL_BINDING_SOUL","SYMBOL_BINDING_ALL","SYMBOL_ATTUNED","SYMBOL_ASCENDED","SYMBOL_RADIANT","ROOT","documentElement","SCROLL_BUTTON","querySelector","bench","ScrollToElement","scrollTo","top","behavior","ShowElement","classList","add","remove","HideElement","TogglePageScrollElement","ratio","scrollTotal","scrollHeight","clientHeight","scrollTop","obj","iconClass","div","finalHTMLFill","Img","maskNormal","maskSteel","silkBarLeft","silkBarMiddle","silkBarRight","rosariesNormalImage","rosariesShadeImage","shellShardsImage","divFlex","hunterCrestImage","architectCrestImage","beastCrestImage","reaperCrestImage","shamanCrestImage","wandererCrestImage","witchCrestImage","SectionStart","CompletionFill","CompletionFillNoSave","SingleEntryFill","SectionDescription","innerHTML","querySelectorAll","forEach","button","PageSwitchTab","h2id","percentBox","symbol","fullString","cl","clGreen","clRed","cp","midP","mp","trueCompletionCurrent","trueCompletionTotal","trueCompletionPercent","perc","divId","content","ToggleSaveModeSwitch","chooseFileButtonLabel","analyzeTextButton","saveTextArea","param","checkboxId","setItem","allClassElements","allClassElementsRed","lengthRed","clickedButton","sectionList","buttonList","contains","type","storage","window","x","removeItem","DOMException","code","FillInnerHTML","elementId","SelectCopyInputText","tooltipId","tooltipFill","getSelection","removeAllRanges","focus","select","setSelectionRange","execCommand","FileNameFormat","file","nameLength","beginLength","endLength","fileName","begin","FileDateFormat","fileDate","Date","lastModified","year","getFullYear","month","getMonth","day","getDate","hour","getHours","getMinutes","tooltip","style","marginLeft","offsetWidth","stopPropagation","preventDefault","dataTransfer","dropEffect","dt","label","nextElementSibling","labelInitialText"],"sourceRoot":""}
\ No newline at end of file
diff --git a/build/index.html b/build/index.html
index a355368..629e367 100644
--- a/build/index.html
+++ b/build/index.html
@@ -299,7 +299,7 @@
- v0.1.0. Work-In-Progress.