commit 607f09b75a70d3ae8fa2a8973b0581a52bf60ab8 Author: Gnarwhal Date: Sun Jul 14 22:58:08 2024 +0000 Gam diff --git a/index.html b/index.html new file mode 100644 index 0000000..3cbb705 --- /dev/null +++ b/index.html @@ -0,0 +1,22 @@ + + + + + Ludum Dare 47 - Loops + + + + + +
+
+
+
+
>
+ +
 
+
+
+ + + diff --git a/script.js b/script.js new file mode 100644 index 0000000..7b4941c --- /dev/null +++ b/script.js @@ -0,0 +1,205 @@ +var storyline = storyline || {}; +storyline.access = (path) => { + path = path.split('.'); + let obj = storyline; + for (const sub of path) { + obj = obj[sub]; + } + return obj; +} + +let widthDummy = null; +function fitToText(element) { + let elementStyle = window.getComputedStyle(element); + widthDummy.style.fontSize = elementStyle.getPropertyValue('font-size'); + widthDummy.style.fontFamily = elementStyle.getPropertyValue('font-family'); + + widthDummy.textContent = '|'; + let pipeWidth = widthDummy.clientWidth; + widthDummy.textContent = '|' + element.value + '|'; + element.style.width = widthDummy.clientWidth - 2 * pipeWidth + "px"; +} + +/* https://davidwalsh.name/caret-end */ +function moveCursorToEnd(el) { + if (typeof el.selectionStart == "number") { + el.selectionStart = el.selectionEnd = el.value.length; + } else if (typeof el.createTextRange != "undefined") { + el.focus(); + var range = el.createTextRange(); + range.collapse(false); + range.select(); + } +} + +function sleep(millis) { + return new Promise(resolve => setTimeout(resolve, millis)); +} + +let promptDiv = null; +let responses = []; +let currentId = 0; +function reset(id) { + if (id === currentId) { + promptDiv.textContent = ""; + } +} + +function append(id, c) { + if (id === currentId) { + promptDiv.textContent += c; + } +} + +async function promptUser(module) { + const MIN_SLEEP = 25; + const MAX_SLEEP = 50; + const SPACE_SCALAR = 1.1; + + const localId = ++currentId; + module = storyline.access(module); + for (const p of module.prompts) { + responses = p.responses; + reset(localId); + for (let i = 0; i < p.text.length; ++i) { + let c = p.text.charAt(i); + append(localId, c); + if (c === ' ') { + await sleep((Math.random() * (MAX_SLEEP - MIN_SLEEP) + MIN_SLEEP) * SPACE_SCALAR); + } else { + await sleep((Math.random() * (MAX_SLEEP - MIN_SLEEP) + MIN_SLEEP)); + } + } + await sleep(p.wait); + } + if (localId === currentId && module.continuation) { + promptUser(module.continuation); + } +} + +window.addEventListener("load", () => { + widthDummy = document.querySelector("#width_dummy"); + promptDiv = document.querySelector("#prompt"); + + let userConsole = document.querySelector("#console"); + let underCursor = document.querySelector("#under_cursor"); + userConsole.addEventListener("input", (event) => { + fitToText(userConsole); + }); + userConsole.addEventListener("keyup", (event) => { + if (event.keyCode === 37) { + moveCursorToEnd(userConsole); + } else if (event.keyCode === 13) { + const entry = userConsole.value; + let matched = false; + for (const responseOption of responses) { + if (responseOption.matches(entry)) { + matched = true; + promptUser(responseOption.target); + break; + } + } + if (matched) { + userConsole.value = ""; + fitToText(userConsole); + } + } + }); + userConsole.addEventListener("click", (event) => { + moveCursorToEnd(userConsole); + }); + let timerId = 0; + let state = 0; + userConsole.addEventListener("focusin", (event) => { + moveCursorToEnd(userConsole); + timerId = window.setInterval((e) => { + if (state === 0) { + underCursor.style.visibility = "visible"; + state = 1; + } else { + underCursor.style.visibility = "hidden"; + state = 0; + } + }, 500); + }); + userConsole.addEventListener("focusout", (event) => { + state = 0; + window.clearInterval(timerId); + underCursor.style.visibility = "hidden"; + }); + + fitToText(userConsole); + userConsole.focus(); + + let entrySpace = document.querySelector("#entry_space"); + entrySpace.addEventListener("click", (event) => { + userConsole.focus(); + }); + + promptUser('welcome'); +}); + +function Regex(regex) { + return text => regex.test(text); +} + +storyline.common = {}; +storyline.common.yes = Regex(/^(y(y*e+s+)?)|(sure)$/i); +storyline.common.no = Regex(/^n(n*o+)?$/i); +storyline.common.any = text => true; + +storyline.welcome = { + prompts: [ + { text: "Welcome!", wait: 1000, responses: [] }, + ], + continuation: 'begin', +}; + +storyline.begin = { + prompts: [ + { text: "Would you like to begin?", wait: 0, responses: [ + { matches: storyline.common.yes, target: 'repeat', }, + { matches: storyline.common.no, target: 'begin.no', }, + { matches: storyline.common.any, target: 'begin.unclear', }, + ]}, + ], +}; + +storyline.begin.no = { + prompts: [ + { text: "As you wish. Whenever you're ready, hit enter and we will begin.", wait: 3000, responses: [ + { matches: storyline.common.any, target: 'repeat' }, + ]}, + ], +}; + +storyline.begin.unclear = { + prompts: [ + { text: "My apologies, I am unable to parse the textual data you passed forth. I invite you to please try again.", wait: 3000, }, + ], + continuation: 'begin', +}; + +storyline.repeat = { + prompts: [ + { text: "Pete and repeat went out on a boat. Pete fell off. Who was left?", wait: 2000, responses: [ + { matches: Regex(/r[e3]p[3e][a4]t/i), target: 'repeat', }, + { matches: Regex(/.*n[o0]t.*p[e3]t[e3].*/i), target: 'repeat.unsmort', }, + { matches: storyline.common.any, target: 'repeat.wat', }, + ]}, + ], +}; + +storyline.repeat.unsmort = { + prompts: [ + { text: "Ah! A self proclaimed intellectual I see. Listen here, I'm gonna ask you again and I want a NAME this time! Thank you in advance.", wait: 4000, responses: [], }, + ], + continuation: 'repeat', +}; + +storyline.repeat.wat = { + prompts: [ + { text: "I do apologize but that is not the correct answer. I do hope this hasn't discouraged you and you will try again though!", wait: 3500, responses: [], }, + ], + continuation: 'repeat', +}; diff --git a/style.css b/style.css new file mode 100644 index 0000000..491e2ad --- /dev/null +++ b/style.css @@ -0,0 +1,86 @@ +:root { + --background-color: #000000; + --text-color: #00FF33; +} + +::selection { + background-color: var(--text-color); + color: var(--background-color); +} + +html { + height: 100%; +} + +body { + height: 100%; + margin: 0; + padding: 0; + background-color: var(--background-color); +} + + +#primary { + width: 100%; + height: 50%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +#width_dummy { + position: fixed; + visibility: hidden; +} + +#prompt { + width: 80%; + height: max-content; + + margin-bottom: 0.2em; + + font-size: 3em; + font-family: 'Ubuntu Mono', monospace; + text-align: center; + word-wrap: break-word; + + color: var(--text-color); +} + +#entry_space { + width: 100%; + display: flex; + justify-content: center; + +} + +#arrow { + margin-right: 0.25em; + + font-size: 2em; + font-family: 'Ubuntu Mono', monospace; + + color: var(--text-color); +} + +#console { + border: 0px solid var(--background-color); + padding: 0px; + + font-size: 2em; + font-family: 'Ubuntu Mono', monospace; + text-overflow: hidden; + caret-color: transparent; + + background-color: var(--background-color); + color: var(--text-color); +} + +#under_cursor { + font-size: 2em; + font-family: 'Ubuntu Mono', monospace; + + background-color: var(--text-color); +} +