« get me outta code hell

Time trial, weee - guess-the-character - Unnamed repository; edit this file 'description' to name the repository.
summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2019-01-17 22:43:02 -0400
committerFlorrie <towerofnix@gmail.com>2019-01-17 22:43:02 -0400
commitc83e12b6f2de41168de22ff33779be9f2e16ea74 (patch)
tree0ab9c0595f3b662920cb89699debd41da8f9f194
parent865bbee8e39acee57893e5c4000ce7c16c92f9a4 (diff)
Time trial, weee HEAD master
-rw-r--r--index.html5
-rw-r--r--main.js224
-rw-r--r--style.css33
3 files changed, 185 insertions, 77 deletions
diff --git a/index.html b/index.html
index 9ab3afc..d0a2b26 100644
--- a/index.html
+++ b/index.html
@@ -36,12 +36,17 @@
                 </div>
             </div>
             <div id="game">
+                <h2 id="time-trial-heading">TIME TRIAL <span id="time-trial-time">30.00s</span> TIME TRIAL</h2>
                 <div id="choice-container"></div>
                 <div id="results" class="hide">
                     <p id="correct"><span>Correct!</span></p>
                     <p id="incorrect"><span>Incorrect.</span><br>The correct choice was <span id="correct-character">Noelle</span>.</p>
                     <p><a href="#" id="next-link">Next</a></p>
                 </div>
+                <div id="final-results">
+                    <p>Good job! You got <span id="final-correct">0</span> <span>correct</span> and <span id="final-incorrect">0</span> <span>incorrect</span>.</p>
+                    <p><a href="#" id="play-again-link">Play again?</a></p>
+                </div>
                 <div id="scorekeeper"></div>
             </div>
         </div>
diff --git a/main.js b/main.js
index 97fc007..2129149 100644
--- a/main.js
+++ b/main.js
@@ -269,6 +269,7 @@ function waitForEvent(el, eventName) {
 
 function setupScorekeeper(numCharacters) {
     const container = document.getElementById('scorekeeper');
+    container.innerHTML = '';
     for (let i = 0; i < numCharacters; i++) {
         const el = document.createElement('div')
         el.classList.add('marker');
@@ -290,6 +291,8 @@ function markScorekeeper(cls, character) {
 async function mainLol() {
     const testChar = 'Noellef';
 
+    // one-time initialization .............................................uuh
+
     document.body.addEventListener('keydown', evt => {
         const choiceContainer = document.getElementById('choice-container');
         if (!choiceContainer.classList.contains('hide')) {
@@ -322,10 +325,6 @@ async function mainLol() {
         }
     });
 
-    // pre-game ------------------------------------------------------------...
-
-    let mode;
-
     const modeLinks = document.querySelectorAll('#mode-picker a[data-mode]');
     const modeParas = document.querySelectorAll('#mode-descriptions p[data-mode]');
 
@@ -344,110 +343,181 @@ async function mainLol() {
         el.addEventListener('click', evt => pickMode(evt.target));
     }
 
+    let mode;
+
     pickMode(modeLinks[0]);
     modeLinks[0].focus();
 
-    // you can pick game options before resources are loaded
     await loadResources();
 
     document.body.classList.add('resources-loaded');
 
-    const gameEl = document.getElementById('game');
+    // pre-game ------------------------------------------------------------...
 
-    const playLink = document.getElementById('play-link');
-    await waitForEvent(playLink, 'click');
+    while (true) {
+        const gameEl = document.getElementById('game');
 
-    document.body.classList.add('game');
+        const playLink = document.getElementById('play-link');
+        await waitForEvent(playLink, 'click');
 
-    const deckGames = ['deltarune'];
-    const hardMode = false;
+        document.body.classList.add('game');
+        document.body.classList.add('mode-' + mode);
 
-    const characterDeck = gameData.characters.filter(chr => chr.games.some(g => deckGames.includes(g)));
+        const deckGames = ['deltarune'];
+        const hardMode = false;
 
-    // game loop -----------------------------------------------------------nym
+        const characterDeck = gameData.characters.filter(chr => chr.games.some(g => deckGames.includes(g)));
 
-    setupScorekeeper(characterDeck.length);
+        // time trial display ----------------------------------------------TT!
 
-    while (characterDeck.length) {
-        gameEl.classList.remove('correct');
-        gameEl.classList.remove('incorrect');
+        const startTime = Date.now();
+        const timeTrialDuration = 30;
+        let timeTrialOver = false;
 
-        const correctCharacter = characterWithName(testChar) || spliceRandom(characterDeck);
+        let resolveTimeTrial;
+        const timeTrialPromise = new Promise(res => {
+            resolveTimeTrial = res;
+        });
 
-        const numChoices = 6;
-        const potentialOptions = characterDeck.slice().filter(chr => chr !== correctCharacter);
-        const correctIndex = Math.min(Math.floor(Math.random() * numChoices), potentialOptions.length);
-        const allCharacters = [];
-        for (let i = 0; i < numChoices; i++) {
-            if (i === correctIndex) {
-                allCharacters.push(correctCharacter);
-            } else if (potentialOptions.length) {
-                let choice;
-                allCharacters.push(spliceRandom(potentialOptions));
-            } else {
-                break
+        const updateTimeTrialDisplay = () => {
+            const remaining = Math.max(0, startTime + 1000 * timeTrialDuration - Date.now());
+            const str = (Math.floor(remaining / 10) / 100).toString();
+            const int = str.split('.')[0];
+            const frac = str.split('.')[1] || '';
+            document.getElementById('time-trial-time').innerHTML = `${int}.${frac.padEnd(2, '0')}s`;
+
+            if (remaining === 0) {
+                resolveTimeTrial();
+                timeTrialOver = true;
             }
-        }
 
-        let msg;
-        if (hardMode) {
-            msg = pickRandom(['Oh?', 'Hello!']);
-        } else {
-            msg = pickRandom(correctCharacter.messages);
-        }
+            requestAnimationFrame(updateTimeTrialDisplay);
+        };
 
         if (mode === 'time-trial') {
-            doSpeech(correctCharacter, msg);
-            await delay(100);
-        } else {
-            await doSpeech(correctCharacter, msg);
-            await delay(500);
+            updateTimeTrialDisplay();
         }
 
-        const choice = await displayChoices(allCharacters, mode === 'time-trial');
+        // game loop -----------------------------------------------------------nym
+
+        let numCorrect = 0;
+        let numIncorrect = 0;
+
+        setupScorekeeper(characterDeck.length);
+
+        while (characterDeck.length) {
+            gameEl.classList.remove('correct');
+            gameEl.classList.remove('incorrect');
+
+            // heck sorry I don't know how to code I know this is bad
+            const status = await Promise.race([timeTrialPromise, (async () => {
+                const correctCharacter = characterWithName(testChar) || spliceRandom(characterDeck);
+
+                const numChoices = 6;
+                const potentialOptions = characterDeck.slice().filter(chr => chr !== correctCharacter);
+                const correctIndex = Math.min(Math.floor(Math.random() * numChoices), potentialOptions.length);
+                const allCharacters = [];
+                for (let i = 0; i < numChoices; i++) {
+                    if (i === correctIndex) {
+                        allCharacters.push(correctCharacter);
+                    } else if (potentialOptions.length) {
+                        let choice;
+                        allCharacters.push(spliceRandom(potentialOptions));
+                    } else {
+                        break
+                    }
+                }
 
-        const container = document.getElementById('choice-container');
-        for (let i = 0; i < allCharacters.length; i++) {
-            const el = container.children[i];
-            if (i === correctIndex) {
-                el.classList.add('correct');
-            } else {
-                el.classList.add('incorrect');
-            }
-            if (i === allCharacters.indexOf(choice)) {
-                el.classList.add('chosen');
-            } else {
-                el.classList.add('not-chosen');
-            }
-        }
+                let msg;
+                if (hardMode) {
+                    msg = pickRandom(['Oh?', 'Hello!']);
+                } else {
+                    msg = pickRandom(correctCharacter.messages);
+                }
 
-        if (choice === correctCharacter) {
-            markScorekeeper('correct', correctCharacter);
-        } else {
-            markScorekeeper('incorrect', correctCharacter);
-        }
+                if (mode === 'time-trial') {
+                    doSpeech(correctCharacter, msg.slice(0, 10));
+                    await delay(100);
+                } else {
+                    await doSpeech(correctCharacter, msg);
+                    await delay(500);
+                }
 
-        await delay(200);
+                const choice = await displayChoices(allCharacters, mode === 'time-trial');
+
+                if (timeTrialOver) return;
+
+                const container = document.getElementById('choice-container');
+                for (let i = 0; i < allCharacters.length; i++) {
+                    const el = container.children[i];
+                    if (i === correctIndex) {
+                        el.classList.add('correct');
+                    } else {
+                        el.classList.add('incorrect');
+                    }
+                    if (i === allCharacters.indexOf(choice)) {
+                        el.classList.add('chosen');
+                    } else {
+                        el.classList.add('not-chosen');
+                    }
+                }
 
-        if (choice === correctCharacter) {
-            gameEl.classList.add('correct');
-        } else {
-            gameEl.classList.add('incorrect');
-            const el = document.getElementById('correct-character');
-            el.innerHTML = '';
-            el.appendChild(document.createTextNode(correctCharacter.name));
+                if (choice === correctCharacter) {
+                    markScorekeeper('correct', correctCharacter);
+                    numCorrect++;
+                } else {
+                    markScorekeeper('incorrect', correctCharacter);
+                    numIncorrect++;
+                }
+
+                await delay(200);
+
+                if (choice === correctCharacter) {
+                    gameEl.classList.add('correct');
+                } else {
+                    gameEl.classList.add('incorrect');
+                    const el = document.getElementById('correct-character');
+                    el.innerHTML = '';
+                    el.appendChild(document.createTextNode(correctCharacter.name));
+                }
+
+                if (timeTrialOver) return;
+
+                document.getElementById('results').classList.remove('hide');
+
+                const nextLink = document.getElementById('next-link');
+                nextLink.focus();
+                await waitForEvent(nextLink, 'click');
+            })()]);
+
+            document.getElementById('choice-container').classList.add('hide');
+            document.getElementById('results').classList.add('hide');
+
+            await delay(400);
+
+            if (timeTrialOver) {
+                break;
+            }
         }
 
-        document.getElementById('results').classList.remove('hide');
+        // results screen ------------------------------------------------------gg-
 
-        const nextLink = document.getElementById('next-link');
-        nextLink.focus();
-        await waitForEvent(nextLink, 'click');
+        document.body.classList.add('game-over');
+        document.getElementById('final-correct').innerHTML = numCorrect;
+        document.getElementById('final-incorrect').innerHTML = numIncorrect;
 
-        document.getElementById('choice-container').classList.add('hide');
-        document.getElementById('results').classList.add('hide');
+        const playAgain = document.getElementById('play-again-link');
+        playAgain.focus();
+        await waitForEvent(playAgain, 'click');
 
-        await delay(400);
+        document.getElementById('choice-container').innerHTML = '';
+        document.getElementById('scorekeeper').innerHTML = '';
+        document.body.classList.remove('game-over');
+        await delay(1000);
+        document.body.classList.remove('game');
+        for (const el of modeLinks) {
+            document.body.classList.remove('mode-' + el.dataset.mode);
+        }
     }
 }
 
diff --git a/style.css b/style.css
index cc09a9a..7d48241 100644
--- a/style.css
+++ b/style.css
@@ -46,6 +46,19 @@ body:not(.resources-loaded) #play-paragraph {
     display: none;
 }
 
+body:not(.game-over) #final-results {
+    opacity: 0;
+}
+
+#final-results {
+    transition: opacity 1s;
+}
+
+/* We have to hide these, or else they messes up layouting of elements below it. */
+body.game-over #results, body.game-over #choice-container {
+    display: none;
+}
+
 #crash-trace {
     text-align: start;
     border: 1pt dotted white;
@@ -205,6 +218,26 @@ body:not(.resources-loaded) #play-paragraph {
     background-color: red;
 }
 
+body:not(.mode-time-trial) #time-trial-heading {
+    display: none;
+}
+
+#time-trial-heading {
+    color: rgba(255, 255, 255, 0.3);
+}
+
+#time-trial-time {
+    color: red;
+}
+
+#final-correct, #final-correct + span {
+    color: green;
+}
+
+#final-incorrect, #final-incorrect + span {
+    color: red;
+}
+
 body, html {
     width: 100%;
     height: 100%;