From d14f1a7cc35c9f628d140df82d9e178f3d5e4a34 Mon Sep 17 00:00:00 2001 From: ReznoRMichael Date: Tue, 20 Jul 2021 23:22:20 +0200 Subject: [PATCH] format files --- src/css/style.css | 836 ++++++------ src/js/HKCheckCompletion.js | 2458 +++++++++++++++++------------------ src/js/LoadJson.js | 130 +- src/js/LoadSaveFile.js | 236 ++-- src/js/hk-dictionary.js | 786 +++++------ src/js/hk-functions.js | 22 +- src/js/page-functions.js | 1732 ++++++++++++------------ 7 files changed, 3100 insertions(+), 3100 deletions(-) diff --git a/src/css/style.css b/src/css/style.css index 5436816..5013007 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -19,692 +19,692 @@ */ :root { - --rt-main: #1e4d6c; - cursor: default; + --rt-main: #1e4d6c; + cursor: default; } html { - font-size: 17px; - font-weight: 300; + font-size: 17px; + font-weight: 300; } body { - font-family: 'Heebo', sans-serif; - color: #fff; - background-color: #050d19; - margin: 0; - overflow: auto; + font-family: 'Heebo', sans-serif; + color: #fff; + background-color: #050d19; + margin: 0; + overflow: auto; } ::-webkit-scrollbar { - width: 8px; - height: 8px; + width: 8px; + height: 8px; } ::-webkit-scrollbar-thumb { - background-color: #1e4d6c; + background-color: #1e4d6c; } ::-webkit-scrollbar-thumb:hover { - background-color: #2e5d7c; + background-color: #2e5d7c; } ::-webkit-scrollbar-track, ::-webkit-scrollbar-track-piece { - background: url("../img/scrollbar-track.png") repeat-y !important; + background: url("../img/scrollbar-track.png") repeat-y !important; } ::-webkit-resizer { - background-color: #050d19; - color: #1e4d6c; + background-color: #050d19; + color: #1e4d6c; } #background { - position: fixed; - padding: 0; - margin: 0; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-image: url("../img/hk-background.jpg"); - background-size: auto 100%; - background-position: center top; - background-repeat: no-repeat; - background-attachment: fixed; - z-index: 1; + position: fixed; + padding: 0; + margin: 0; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url("../img/hk-background.jpg"); + background-size: auto 100%; + background-position: center top; + background-repeat: no-repeat; + background-attachment: fixed; + z-index: 1; } #content { - max-width: 600px; - margin: 0 auto; - padding: 0 .6rem; - position: relative; - z-index: 1000; + max-width: 600px; + margin: 0 auto; + padding: 0 .6rem; + position: relative; + z-index: 1000; } b { - font-weight: 500; - color: #aac7d4; + font-weight: 500; + color: #aac7d4; } p { - margin-top: 0.6rem; - margin-bottom: 0.6rem; + margin-top: 0.6rem; + margin-bottom: 0.6rem; } del { - text-decoration: none; - opacity: 0.5; + text-decoration: none; + opacity: 0.5; } strong { - font-weight: 700; + font-weight: 700; } h1 { - font-size: 1.7rem; - color: #d9f3ff; - margin: 0.6rem 0; + font-size: 1.7rem; + color: #d9f3ff; + margin: 0.6rem 0; } #h1-title { - text-align: center; + text-align: center; } h2 { - text-align: center; - margin: 0.6rem 0; - color: rgba(231, 251, 255, 0.6); - font-weight: 700; + text-align: center; + margin: 0.6rem 0; + color: rgba(231, 251, 255, 0.6); + font-weight: 700; } h6 { - text-align: center; - font-size: 1.2rem; - font-weight: 500; - margin: 0.6rem 0; - color: rgba(231, 251, 255, 0.6); + text-align: center; + font-size: 1.2rem; + font-weight: 500; + margin: 0.6rem 0; + color: rgba(231, 251, 255, 0.6); } .hall-of-fame { - color: rgba(0, 255, 220, 0.6); + color: rgba(0, 255, 220, 0.6); } #hk-hints { - border: 0.2rem solid rgba(231, 251, 255, 0.33); - border-radius: 1rem; - border-style: double; - padding: 1.3rem; - margin: 1.3rem; + border: 0.2rem solid rgba(231, 251, 255, 0.33); + border-radius: 1rem; + border-style: double; + padding: 1.3rem; + margin: 1.3rem; } #h2-hk-hints { - margin-top: 0; - color: rgba(255, 255, 255, 1.0); - font-weight: 400; - text-align: left; + margin-top: 0; + color: rgba(255, 255, 255, 1.0); + font-weight: 400; + text-align: left; } .section-description { - text-align: center; - font-size: 0.8rem; - margin: 0 1.3rem 1.3rem 1.3rem; - color: rgba(129, 221, 224, 0.85); + text-align: center; + font-size: 0.8rem; + margin: 0 1.3rem 1.3rem 1.3rem; + color: rgba(129, 221, 224, 0.85); } #save-location-input { - display: block; - font-family: 'Consolas', monospace; - font-size: 0.75rem; - text-align: center; - width: 100%; - max-width: 32em; - color: #fff; - background-color: rgba(128, 128, 128, 0.5); - margin: 0.4rem auto 0.6rem auto; - padding: 0.16rem 0.5rem 0.25rem 0.5rem; - border: 1px solid rgba(231, 251, 255, 0.6); - border-radius: 3px; + display: block; + font-family: 'Consolas', monospace; + font-size: 0.75rem; + text-align: center; + width: 100%; + max-width: 32em; + color: #fff; + background-color: rgba(128, 128, 128, 0.5); + margin: 0.4rem auto 0.6rem auto; + padding: 0.16rem 0.5rem 0.25rem 0.5rem; + border: 1px solid rgba(231, 251, 255, 0.6); + border-radius: 3px; } #save-location-input:focus { - outline: 0; - border: 1px solid rgba(231, 251, 255, 0.8); + outline: 0; + border: 1px solid rgba(231, 251, 255, 0.8); } input { - font-family: 'Heebo', sans-serif; - font-size: 1rem; - text-align: left; + font-family: 'Heebo', sans-serif; + font-size: 1rem; + text-align: left; } textarea { - font-family: 'Consolas', monospace; - font-size: 0.8rem; - text-align: left; - background-color: rgba(0, 0, 0, 0); - color: #fff; - caret-color: #fff; - border: 1px solid #e3ebf7; - padding: 2px; - margin: 0.5rem 2px 0.5rem 2px; - overflow-x: hidden; - overflow-y: scroll; + font-family: 'Consolas', monospace; + font-size: 0.8rem; + text-align: left; + background-color: rgba(0, 0, 0, 0); + color: #fff; + caret-color: #fff; + border: 1px solid #e3ebf7; + padding: 2px; + margin: 0.5rem 2px 0.5rem 2px; + overflow-x: hidden; + overflow-y: scroll; - /* These are technically the same, but use both */ - overflow-wrap: break-word; - word-wrap: break-word; + /* These are technically the same, but use both */ + overflow-wrap: break-word; + word-wrap: break-word; - -ms-word-break: break-all; - /* This is the dangerous one in WebKit, as it breaks things wherever */ - word-break: break-all; - /* Instead use this non-standard one: */ - word-break: break-word; + -ms-word-break: break-all; + /* This is the dangerous one in WebKit, as it breaks things wherever */ + word-break: break-all; + /* Instead use this non-standard one: */ + word-break: break-word; - /* Adds a hyphen where the word breaks, if supported (No Blink) */ - -ms-hyphens: none; - -moz-hyphens: none; - -webkit-hyphens: none; - hyphens: none; + /* Adds a hyphen where the word breaks, if supported (No Blink) */ + -ms-hyphens: none; + -moz-hyphens: none; + -webkit-hyphens: none; + hyphens: none; } textarea:focus { - border-color: rgba(0, 0, 0, 0); - box-shadow: 0 0 4px 2px #fff; - outline: 0; - /* outline: #fff 2px solid; + border-color: rgba(0, 0, 0, 0); + box-shadow: 0 0 4px 2px #fff; + outline: 0; + /* outline: #fff 2px solid; outline-offset: 1px; */ } textarea::placeholder { - color: rgba(255, 255, 255, 0.5); - font-size: 1rem; - text-align: center; - caret-color: #fff; + color: rgba(255, 255, 255, 0.5); + font-size: 1rem; + text-align: center; + caret-color: #fff; } input[type="file"] { - /* max-width: 500px; */ - /* margin: 0.5rem 0.5rem 0.5rem 0.25rem; */ + /* max-width: 500px; */ + /* margin: 0.5rem 0.5rem 0.5rem 0.25rem; */ } .input-file { - width: 0.1px; - height: 0.1px; - opacity: 0; - overflow: hidden; - position: absolute; - z-index: -1; + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; } #file-input-label { - max-width: 325px; + max-width: 325px; } #save-area { - display: block; - width: 100%; - max-width: 592px; - height: 5.65rem; + display: block; + width: 100%; + max-width: 592px; + height: 5.65rem; } #drop-area { - position: fixed; - width: 100%; - height: 100%; - left: 0; - top: 0; - z-index: 9999; - visibility: hidden; + position: fixed; + width: 100%; + height: 100%; + left: 0; + top: 0; + z-index: 9999; + visibility: hidden; } #drop-area-inside { - background-color: rgba(38, 189, 38, 0.5); - border: 0.3rem dashed rgba(38, 189, 38, 0.85); - border-radius: 1rem; - width: 100%; - height: 100%; - left: 0; - top: 0; - z-index: 9000; + background-color: rgba(38, 189, 38, 0.5); + border: 0.3rem dashed rgba(38, 189, 38, 0.85); + border-radius: 1rem; + width: 100%; + height: 100%; + left: 0; + top: 0; + z-index: 9000; } #drop-area #drop-area-inside.highlight { - border-color: rgb(61, 228, 61); + border-color: rgb(61, 228, 61); } .hint { - display: block; - font-style: italic; + display: block; + font-style: italic; } .blurred { - filter: blur(5px); - -webkit-filter: blur(5px); - transition: all 0.3s ease; + filter: blur(5px); + -webkit-filter: blur(5px); + transition: all 0.3s ease; } .blurred:hover { - filter: none; - -webkit-filter: none; + filter: none; + -webkit-filter: none; } .spoiler-span.blurred:hover { - cursor: default; + cursor: default; } .hint::first-letter { - position: absolute; - float: left; - margin-right: 0.6rem; - margin-top: 0.5rem; - font-size: 2.8rem; - line-height: 0.8; - font-weight: 500; + position: absolute; + float: left; + margin-right: 0.6rem; + margin-top: 0.5rem; + font-size: 2.8rem; + line-height: 0.8; + font-weight: 500; } .buttons { - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; } .input-buttons { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } .checkboxes { - margin-top: 0rem; + margin-top: 0rem; } .button { - display: flex; - flex-direction: row; - align-items: center; - width: max-content; - font-size: 1rem; - font-weight: 500; - font-family: 'Heebo', sans-serif; - text-align: center; - background-color: #1e4d6c; - color: #aac7d4; - border: 2px solid #183c55; - border-radius: 2px; - padding: 0.3rem 1rem; - margin: 0.25rem 0.5rem 0.25rem 0.25rem; - transition: all 0.3s ease; + display: flex; + flex-direction: row; + align-items: center; + width: max-content; + font-size: 1rem; + font-weight: 500; + font-family: 'Heebo', sans-serif; + text-align: center; + background-color: #1e4d6c; + color: #aac7d4; + border: 2px solid #183c55; + border-radius: 2px; + padding: 0.3rem 1rem; + margin: 0.25rem 0.5rem 0.25rem 0.25rem; + transition: all 0.3s ease; } .button:first-child { - margin-left: 0.25rem; + margin-left: 0.25rem; } .button:hover { - color: #d9f3ff; - background-color: #2e5d7c; - border-color: #2e5d7c; - cursor: pointer; + color: #d9f3ff; + background-color: #2e5d7c; + border-color: #2e5d7c; + cursor: pointer; } .button:focus, -.input-file:focus + label { - /* outline: 2px solid #5e8dac; */ - outline: 0; - border-color: #5e8dac; - /* outline-offset: -2px; */ +.input-file:focus+label { + /* outline: 2px solid #5e8dac; */ + outline: 0; + border-color: #5e8dac; + /* outline-offset: -2px; */ } .centered { - flex-direction: row; - align-items: center; + flex-direction: row; + align-items: center; } @media screen and (max-width: 570px) { - .centered { - flex-direction: column; - align-items: flex-start; - } + .centered { + flex-direction: column; + align-items: flex-start; + } } @media screen and (max-width: 400px) { - .buttons { - flex-direction: column; - align-items: center; - } + .buttons { + flex-direction: column; + align-items: center; + } - .input-buttons { - align-items: center; - justify-content: center; - } + .input-buttons { + align-items: center; + justify-content: center; + } - .centered { - flex-direction: column; - align-items: flex-start; - } + .centered { + flex-direction: column; + align-items: flex-start; + } - .checkboxes { - margin-top: 0.8rem; - } + .checkboxes { + margin-top: 0.8rem; + } } .horizontal-line { - margin: 1rem 0; - height: 1.5rem; - width: 100%; - background-image: url("../img/fleur-divide.png"); - background-size: auto 100%; - background-position: center top; - background-repeat: no-repeat; + margin: 1rem 0; + height: 1.5rem; + width: 100%; + background-image: url("../img/fleur-divide.png"); + background-size: auto 100%; + background-position: center top; + background-repeat: no-repeat; } @media screen and (max-width: 460px) { - .horizontal-line { - height: 1.15rem; - } + .horizontal-line { + height: 1.15rem; + } } @media screen and (max-width: 360px) { - .horizontal-line { - height: 0.9rem; - } + .horizontal-line { + height: 0.9rem; + } } .smalltext { - font-size: 0.8rem; - text-align: center; + font-size: 0.8rem; + text-align: center; } a, a:active, a:visited { - display: inline-block; - color: #aac7d4; - font-weight: 700; - text-decoration: none; - transition: all 0.3s ease; + display: inline-block; + color: #aac7d4; + font-weight: 700; + text-decoration: none; + transition: all 0.3s ease; } a:hover { - color: #d9f3ff; - text-decoration: none; - text-shadow: 0 0 0.6em #1bff73; + color: #d9f3ff; + text-decoration: none; + text-shadow: 0 0 0.6em #1bff73; } a.button:active, a.button:visited { - font-weight: 500; + font-weight: 500; } a.button:hover { - text-shadow: none; + text-shadow: none; } a.wiki { - font-weight: 500; + font-weight: 500; } .link-social { - margin: 0.25rem; + margin: 0.25rem; } .icon-cancel { - color: #f03a17; + color: #f03a17; } .icon-ok-squared { - color: #16c60c; + color: #16c60c; } .icon-info-circled { - color: #479ae7; + color: #479ae7; } .icon-download-cloud, .icon-doc-text-inv { - color: #d9f3ff; + color: #d9f3ff; } .flex-container { - display: flex; - flex-wrap: wrap; - flex-direction: row; - align-items: normal; - justify-content: left; + display: flex; + flex-wrap: wrap; + flex-direction: row; + align-items: normal; + justify-content: left; } .flex-row { - flex-direction: row; + flex-direction: row; } .align-center { - align-items: center; + align-items: center; } .soul-orb:first-child { - margin-left: 0.3rem; + margin-left: 0.3rem; } .health-mask, .soul-orb, .geo-symbol, .notch { - width: auto; - height: 1.48rem; - margin: 0 0 0 0.3rem; + width: auto; + height: 1.48rem; + margin: 0 0 0 0.3rem; } .notch { - padding-left: 0.3rem; - margin-left: -0.6rem; + padding-left: 0.3rem; + margin-left: -0.6rem; } .soul-orb { - height: 1.3rem; - padding-left: 0.3rem; - margin-left: -0.15rem; + height: 1.3rem; + padding-left: 0.3rem; + margin-left: -0.15rem; } .geo-symbol { - margin-right: 0.15rem; + margin-right: 0.15rem; } .padding-left { - padding-left: 1.4rem; - height: 1.47rem; + padding-left: 1.4rem; + height: 1.47rem; } .p-left-small { - display: inline; - padding-left: 0.3rem; - height: 1.47rem; + display: inline; + padding-left: 0.3rem; + height: 1.47rem; } .scroll-up-button { - width: 50px; - height: 50px; - text-decoration: none; - background-color: #1e4d6c; - border: 0; - border-radius: 2px; - outline: 0; - position: fixed; - right: 1px; - bottom: 0; - z-index: 1100; - opacity: 0; - transition: all 0.3s ease; + width: 50px; + height: 50px; + text-decoration: none; + background-color: #1e4d6c; + border: 0; + border-radius: 2px; + outline: 0; + position: fixed; + right: 1px; + bottom: 0; + z-index: 1100; + opacity: 0; + transition: all 0.3s ease; } .scroll-up-button:hover { - background-color: #2e5d7c; - cursor: pointer; + background-color: #2e5d7c; + cursor: pointer; } .scroll-up-button-arrow { - position: relative; - left: 12px; - top: 3px; - width: 12px; - height: 12px; - border: solid #aac7d4; - border-width: 2px 0px 0px 2px; - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - transform: rotate(45deg); + position: relative; + left: 12px; + top: 3px; + width: 12px; + height: 12px; + border: solid #aac7d4; + border-width: 2px 0px 0px 2px; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); } .hidden { - display: none; + display: none; } .visible-block { - display: block; + display: block; } .opacity-none { - opacity: 0; + opacity: 0; } .opacity-full { - opacity: 1; + opacity: 1; } .spoiler-text { - display: inline; - /* These are technically the same, but use both */ - overflow-wrap: break-word; - word-wrap: break-word; + display: inline; + /* These are technically the same, but use both */ + overflow-wrap: break-word; + word-wrap: break-word; - -ms-word-break: break-all; - /* This is the dangerous one in WebKit, as it breaks things wherever */ - word-break: break-all; - /* Instead use this non-standard one: */ - word-break: break-word; + -ms-word-break: break-all; + /* This is the dangerous one in WebKit, as it breaks things wherever */ + word-break: break-all; + /* Instead use this non-standard one: */ + word-break: break-word; - /* Adds a hyphen where the word breaks, if supported (No Blink) */ - -ms-hyphens: auto; - -moz-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; + /* Adds a hyphen where the word breaks, if supported (No Blink) */ + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; } .radio, .checkbox { - position: relative; - display: block; - left: -40px; - padding: 4px; - margin-left: 10px; + position: relative; + display: block; + left: -40px; + padding: 4px; + margin-left: 10px; } input[type="checkbox"], input[type="radio"] { - margin-right: 10px; + margin-right: 10px; } .radio-label, .checkbox-label { - display: inline-block; - position: relative; - padding: 0 0 0 1.8rem; - margin: 0.25rem 1rem 0.25rem 0.5rem; - cursor: pointer; - font-size: 1rem; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - width: max-content; + display: inline-block; + position: relative; + padding: 0 0 0 1.8rem; + margin: 0.25rem 1rem 0.25rem 0.5rem; + cursor: pointer; + font-size: 1rem; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + width: max-content; } .checkbox-label:last-child { - margin-right: 0; + margin-right: 0; } .radiomark, .checkmark { - position: absolute; - top: 0; - left: 0; - height: 22px; - width: 22px; - background-color: #aac7d4; - border: 1px solid #1e4d6c; - border: 1px solid var(--rt-main); + position: absolute; + top: 0; + left: 0; + height: 22px; + width: 22px; + background-color: #aac7d4; + border: 1px solid #1e4d6c; + border: 1px solid var(--rt-main); } .radiomark { - border-radius: 50%; + border-radius: 50%; } /* Hide the browser's default checkbox */ .radio-label input, .checkbox-label input { - position: absolute; - opacity: 0; - cursor: pointer; - height: 0; - width: 0; + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; } /* On mouse-over change background color */ .radio-label:hover input~.radiomark, .checkbox-label:hover input~.checkmark { - background-color: #d9f3ff; + background-color: #d9f3ff; } /* When the checkbox is checked change background color */ .radio-label input:checked~.radiomark, .checkbox-label input:checked~.checkmark { - background-color: #1e4d6c; - background-color: var(--rt-main); + background-color: #1e4d6c; + background-color: var(--rt-main); } /* When the checkbox is checked change background color on hover */ .radio-label:hover input:checked~.radiomark, .checkbox-label:hover input:checked~.checkmark { - background-color: #2e5d7c; - border-color: #2e5d7c; + background-color: #2e5d7c; + border-color: #2e5d7c; } /* Create the checkmark/indicator (hidden when not checked) */ .radiomark:after, .checkmark:after { - content: ""; - position: absolute; - display: none; + content: ""; + position: absolute; + display: none; } /* Show the checkmark when checked */ .radio-label input:checked~.radiomark:after, .checkbox-label input:checked~.checkmark:after { - display: block; + display: block; } /* Style the checkmark/indicator */ .checkbox-label .checkmark:after { - left: 7px; - top: 2px; - width: 6px; - height: 12px; - border: solid #aac7d4; - border-width: 0 2px 2px 0; - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - transform: rotate(45deg); + left: 7px; + top: 2px; + width: 6px; + height: 12px; + border: solid #aac7d4; + border-width: 0 2px 2px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); } /* Style the checkmark/indicator */ .radio-label .radiomark:after { - top: 7px; - left: 7px; - width: 10px; - height: 10px; - border-radius: 50%; - background: #000; + top: 7px; + left: 7px; + width: 10px; + height: 10px; + border-radius: 50%; + background: #000; } /* input[type="checkbox"]:focus + label, @@ -713,86 +713,86 @@ input[type="radio"]:focus + label { } */ .tooltip { - position: relative; - display: block; - margin: 0 auto; - width: 100%; - max-width: 550px; + position: relative; + display: block; + margin: 0 auto; + width: 100%; + max-width: 550px; } .tooltip .tooltip-text { - visibility: hidden; - width: max-content; - background-color: #1e4d6c; - color: #d9f3ff; - font-size: 0.85rem; - text-align: center; - border-radius: 3px; - padding: 0.16rem 0.7rem; - position: absolute; - z-index: 1; - bottom: 130%; - left: 50%; - margin-left: -109px; - opacity: 0; - transition: opacity 0.3s; + visibility: hidden; + width: max-content; + background-color: #1e4d6c; + color: #d9f3ff; + font-size: 0.85rem; + text-align: center; + border-radius: 3px; + padding: 0.16rem 0.7rem; + position: absolute; + z-index: 1; + bottom: 130%; + left: 50%; + margin-left: -109px; + opacity: 0; + transition: opacity 0.3s; } .tooltip .tooltip-text::after { - content: ""; - position: absolute; - top: 100%; - left: 50%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - border-color: #1e4d6c transparent transparent transparent; + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #1e4d6c transparent transparent transparent; } .tooltip:hover .tooltip-text { - visibility: visible; - opacity: 1; + visibility: visible; + opacity: 1; } @media screen and (max-width: 570px) { - .tooltip { - display: none; - } + .tooltip { + display: none; + } } .percent-box { - display: inline-block; - text-align: center; - font-size: 1.1rem; - vertical-align: middle; - color: #d9f3ff; - margin: 0 0.5rem 0rem 0.5rem; - padding: 0.2rem 1.2rem 0.2rem 1.2rem; - background: #1e4d6c; - border: 2px solid #3e6d8c; - border-radius: 4px; + display: inline-block; + text-align: center; + font-size: 1.1rem; + vertical-align: middle; + color: #d9f3ff; + margin: 0 0.5rem 0rem 0.5rem; + padding: 0.2rem 1.2rem 0.2rem 1.2rem; + background: #1e4d6c; + border: 2px solid #3e6d8c; + border-radius: 4px; } .box-red { - color: #ffe2dd; - background: #c22e14; - border: 2px solid #e24e34; + color: #ffe2dd; + background: #c22e14; + border: 2px solid #e24e34; } .box-green { - color: #ddffd9; - background: #1e6c1e; - border: 2px solid #2d8a49; + color: #ddffd9; + background: #1e6c1e; + border: 2px solid #2d8a49; } .pp-gold { - color: #ffbc00; + color: #ffbc00; } .pp-silver { - color: #ebf9ff; + color: #ebf9ff; } .test { - color: #59d1da; + color: #59d1da; } \ No newline at end of file diff --git a/src/js/HKCheckCompletion.js b/src/js/HKCheckCompletion.js index ff5fd6f..d7c3a21 100644 --- a/src/js/HKCheckCompletion.js +++ b/src/js/HKCheckCompletion.js @@ -7,16 +7,16 @@ import HK from "./hk-database.js"; /* ----------------- Helper functions --------------------------------------- */ import { - GenerateInnerHTML, - AppendHTML, - CheckboxHintsToggle, - CheckboxSpoilersToggle, - StorageAvailable + GenerateInnerHTML, + AppendHTML, + CheckboxHintsToggle, + CheckboxSpoilersToggle, + StorageAvailable } from "./page-functions.js"; import { - ObjectLength, - TranslateMapName + ObjectLength, + TranslateMapName } from "./hk-functions.js"; // ---------------- Load image files (necessary for Webpack) ----------------- // @@ -47,15 +47,15 @@ const WIKI_LINK = "https://hollowknight.fandom.com/wiki/"; let completionSymbol = SYMBOL_FALSE; let divStart = [ - "
" + "
" ].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 = `health mask image`; - let maskSteel = `steel health mask image`; - let maskImg = ""; + /* let icon = SYMBOL_EMPTY; + let textFill = "Health:"; + let maskImages = ""; + let maskNormal = `health mask image`; + let maskSteel = `steel health mask image`; + 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 = `soul orb image`; - let soulImg = soulNormal; + /* let icon = SYMBOL_EMPTY; + let textFill = "Soul:"; + let soulImages = ""; + let soulNormal = `soul orb image`; + 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:geo symbol image${geoValue}`; + /* let icon = SYMBOL_EMPTY; + let textFill = `Geo:geo symbol image${geoValue}`; - // Show Shade Geo value and image only if Shade has at least 1 Geo on it - if (geoPoolValue > 0) textFill += ` - ${pSpan}+shade geo symbol image${geoPoolValue}`; + // Show Shade Geo value and image only if Shade has at least 1 Geo on it + if (geoPoolValue > 0) textFill += ` + ${pSpan}+shade geo symbol image${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 = `notch image`; - let notchFilledImage = `notch image`; - let notchOvercharmedImage = `notch image`; + let notchImages = ""; + let notchNormalImage = `notch image`; + let notchFilledImage = `notch image`; + let notchOvercharmedImage = `notch image`; - // 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 = `health mask image`; - let maskSteel = `steel health mask image`; - let soulNormal = `soul orb image`; - let notchNormalImage = `notch image`; - let notchFilledImage = `notch image`; - let notchOvercharmedImage = `notch image`; - let geoNormalImage = `geo symbol image`; - let geoShadeImage = `shade geo symbol image`; - 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 = `health mask image`; + let maskSteel = `steel health mask image`; + let soulNormal = `soul orb image`; + let notchNormalImage = `notch image`; + let notchFilledImage = `notch image`; + let notchOvercharmedImage = `notch image`; + let geoNormalImage = `geo symbol image`; + let geoShadeImage = `shade geo symbol image`; + 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 = `health mask image`; - let maskSteel = `steel health mask image`; - let soulNormal = `soul orb image`; - let notchNormalImage = `notch image`; - let notchFilledImage = `notch image`; - let notchOvercharmedImage = `notch image`; - let geoNormalImage = `geo symbol image`; - let geoShadeImage = `shade geo symbol image`; - let wiki = ""; + let textPrefix = ""; + let textSuffix = ""; + let textFill = ""; + let Img = ""; + let maskNormal = `health mask image`; + let maskSteel = `steel health mask image`; + let soulNormal = `soul orb image`; + let notchNormalImage = `notch image`; + let notchFilledImage = `notch image`; + let notchOvercharmedImage = `notch image`; + let geoNormalImage = `geo symbol image`; + let geoShadeImage = `shade geo symbol image`; + 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