From 98408feaf3d17825c22f3486e946b52f0503f0b5 Mon Sep 17 00:00:00 2001 From: raeleus Date: Sun, 6 Apr 2025 00:01:59 -0700 Subject: [PATCH] Added #memory --- Input.js | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++- Output.js | 80 +++++++++++++++++++++++++++++++ README.md | 1 + 3 files changed, 221 insertions(+), 1 deletion(-) diff --git a/Input.js b/Input.js index f147f9b..c1864f1 100644 --- a/Input.js +++ b/Input.js @@ -90,6 +90,7 @@ const spellShopSynonyms = ["spellshop", "spellstore"] const itemShopSynonyms = ["itemshop", "itemstore"] const stragedySynonyms = ["stragedy", "playgame", "game", "startgame", "begingame", "playcards", "playstragedy", "startstragedy", "beginstragedy"] const lockpickSynonyms = ["lockpick", "lockpicking", "codebreaker", "pick", "hack", "hacking", "mastermind"] +const memorySynonyms = ["memory", "matchmaking", "matching", "matchmaker", "match2"] const addCardSynonyms = ["addcard"] const equipSynonyms = ["equip", "arm", "wear"] const rewardSynonyms = ["reward"] @@ -141,6 +142,12 @@ const modifier = (text) => { else text = rawText } + if (state.memoryTurn != null) { + text = handleMemoryTurn(text) + if (state.memoryTurn != null) return { text } + else text = rawText + } + if (state.initialized == null || !text.includes("#")) { state.initialized = true; return { text } @@ -170,7 +177,7 @@ const modifier = (text) => { return { text } } - if (!found) found = processCommandSynonyms(command, commandName, helpSynonyms.concat(rollSynonyms, noteSynonyms, eraseNoteSynonyms, showNotesSynonyms, clearNotesSynonyms, showCharactersSynonyms, removeCharacterSynonyms, generateNameSynonyms, setDefaultDifficultySynonyms, showDefaultDifficultySynonyms, renameCharacterSynonyms, cloneCharacterSynonyms, createLocationSynonyms, showLocationsSynonyms, goToLocationSynonyms, removeLocationSynonyms, getLocationSynonyms, clearLocationsSynonyms, goNorthSynonyms, goSouthSynonyms, goEastSynonyms, goWestSynonyms, encounterSynonyms, showEnemiesSynonyms, addEnemySynonyms, removeEnemySynonyms, clearEnemiesSynonyms, initiativeSynonyms, turnSynonyms, fleeSynonyms, versionSynonyms, setupEnemySynonyms, healSynonyms, damageSynonyms, restSynonyms, addExperienceSynonyms, healPartySynonyms, blockSynonyms, repeatTurnSynonyms, lockpickSynonyms, resetSynonyms), function () {return true}) + if (!found) found = processCommandSynonyms(command, commandName, helpSynonyms.concat(rollSynonyms, noteSynonyms, eraseNoteSynonyms, showNotesSynonyms, clearNotesSynonyms, showCharactersSynonyms, removeCharacterSynonyms, generateNameSynonyms, setDefaultDifficultySynonyms, showDefaultDifficultySynonyms, renameCharacterSynonyms, cloneCharacterSynonyms, createLocationSynonyms, showLocationsSynonyms, goToLocationSynonyms, removeLocationSynonyms, getLocationSynonyms, clearLocationsSynonyms, goNorthSynonyms, goSouthSynonyms, goEastSynonyms, goWestSynonyms, encounterSynonyms, showEnemiesSynonyms, addEnemySynonyms, removeEnemySynonyms, clearEnemiesSynonyms, initiativeSynonyms, turnSynonyms, fleeSynonyms, versionSynonyms, setupEnemySynonyms, healSynonyms, damageSynonyms, restSynonyms, addExperienceSynonyms, healPartySynonyms, blockSynonyms, repeatTurnSynonyms, lockpickSynonyms, memorySynonyms, resetSynonyms), function () {return true}) if (found == null) { if (state.characterName == null) { @@ -273,6 +280,7 @@ const modifier = (text) => { if (text == null) text = processCommandSynonyms(command, commandName, itemShopSynonyms, doItemShop) if (text == null) text = processCommandSynonyms(command, commandName, stragedySynonyms, doStragedy) if (text == null) text = processCommandSynonyms(command, commandName, lockpickSynonyms, doLockpick) + if (text == null) text = processCommandSynonyms(command, commandName, memorySynonyms, doMemory) if (text == null) text = processCommandSynonyms(command, commandName, addCardSynonyms, doAddCard) if (text == null) text = processCommandSynonyms(command, commandName, equipSynonyms, doEquip) if (text == null) text = processCommandSynonyms(command, commandName, rewardSynonyms, doReward) @@ -1309,6 +1317,137 @@ function doSetupEnemy(command) { return " " } +function doMemory(command) { + var arg0 = getArgument(command, 0) + if (arg0 == null) { + arg0 = "easy" + } + + switch(arg0) { + case "impossible": + state.memoryWidth = 6 + state.memoryHeight = 6 + state.memoryMaxTurns = 46 + break + case "hard": + state.memoryWidth = 5 + state.memoryHeight = 6 + state.memoryMaxTurns = 40 + break + case "medium": + state.memoryWidth = 4 + state.memoryHeight = 5 + state.memoryMaxTurns = 30 + break + case "effortless": + state.memoryWidth = 3 + state.memoryHeight = 2 + state.memoryMaxTurns = 25 + break + case "automatic": + state.memoryWidth = 2 + state.memoryHeight = 2 + state.memoryMaxTurns = 25 + break + case "easy": + default: + state.memoryWidth = 4 + state.memoryHeight = 3 + state.memoryMaxTurns = 25 + break + } + + state.memoryTurns = 1 + + let possibleSymbols = ["❤️", "💙", "🐉", "🐸", "⚔️", "🛡️", "🐻", "👻", "🦁", "😺", "😈", "🧙", "💀", "🐵", "🐓", "🦉", "🕷️", "🏹", "🎁", "🎲", "❄️", "🔥", "⚡", "🌳", "💦", "🍎", "🥒", "🍖"] + shuffle(possibleSymbols) + possibleSymbols = possibleSymbols.splice(0, state.memoryWidth * state.memoryHeight / 2) + + state.memoryCards = possibleSymbols.concat(possibleSymbols) + shuffle(state.memoryCards) + state.memorySolved = new Array(state.memoryCards.length) + state.memoryRevealed = null + + state.memoryTurn = "game" + state.show = "memory" + return " " +} + +function handleMemoryTurn(text) { + state.show = "memory" + + if (/^\s*>.*says? ".*/.test(text)) { + text = text.replace(/^\s*>.*says? "/, "") + text = text.replace(/"\s*$/, "") + } else if (/^\s*>\s.*/.test(text)) { + text = text.replace(/\s*> /, "") + for (var i = 0; i < info.characters.length; i++) { + var matchString = info.characters[i] == "" ? "You " : `${info.characters[i]} ` + if (text.startsWith(matchString)) { + text = text.replace(matchString, "") + break + } + } + text = text.replace(/\.?\s*$/, "") + } else { + text = text.replace(/^\s+/, "") + } + + text = text.toLowerCase() + if (text == "q") { + state.memoryTurn = "forfeit" + return text + } + + switch (state.memoryTurn) { + case "game": + if (isNaN(text)) return text + let guess = parseInt(text) + state.memoryTurns++ + + if (guess < 1 || guess > state.memoryCards.length) return text + + if (state.memoryRevealed == null) { + state.message = `Card ${guess} is revealed to be:\n${state.memoryCards[guess -1]}` + state.memoryRevealed = guess + } else { + if (state.memoryRevealed == guess) { + state.message = `Card ${guess} is the same card you already picked, silly:\n${state.memoryCards[guess - 1]}` + state.memoryTurns-- + } else if (state.memoryCards[state.memoryRevealed - 1] == state.memoryCards[guess - 1]) { + state.message = `Cards ${state.memoryRevealed} and ${guess} are a match!\n${state.memoryCards[state.memoryRevealed - 1]} ${state.memoryCards[guess - 1]}` + state.memorySolved[state.memoryRevealed - 1] = true + state.memorySolved[guess - 1] = true + state.memoryRevealed = null + } else { + state.message = `Card ${guess} is revealed to be: ${state.memoryCards[guess - 1]}\nCards ${state.memoryRevealed} and ${guess} are NOT a match:${state.memoryCards[state.memoryRevealed - 1]} ${state.memoryCards[guess - 1]}` + state.memoryRevealed = null + } + } + + let win = true + for (let i = 0; i < state.memorySolved.length; i++) { + if (state.memorySolved[i] != true) { + win = false + break + } + } + if (win) state.memoryTurn = "win" + if (state.memoryTurns > state.memoryMaxTurns) state.memoryTurn = "lose" + + log(state.memorySolved) + return text + case "win": + case "lose": + case "forfeit": + state.show = null + state.memoryTurn = null + return text + } + + return `\nUnexpected Mastermind state. Input text: ${text}` +} + function doLockpick(command) { var arg0 = getArgument(command, 0) if (arg0 == null) { diff --git a/Output.js b/Output.js index bc82ac9..7c0ec25 100644 --- a/Output.js +++ b/Output.js @@ -102,6 +102,9 @@ const modifier = (text) => { case "lockpicking": text += handleLockpicking() break + case "memory": + text += handleMemory() + break case "bio": text += `*** ${possessiveName.toUpperCase()} BIO ***\n` text += `Class: ${character.className}\n` @@ -548,6 +551,10 @@ const modifier = (text) => { text += "\n#lockpick (automatic|effortless|easy|medium|hard|impossible)" text += "\n Initiates a lockpicking minigame similar to Mastermind where you have to guess the correct combination with a limited number of tries in order to defeat a lock. Specifying a difficulty (default is easy) sets the number of combinations and tries accordingly. Please see the game manual on github for rules, tactics, and a complete tutorial: github.com/raeleus/Hashtag-DnD/" + text += "\n\n--Memory Minigame--" + text += "\n#memory (automatic|effortless|easy|medium|hard|impossible)" + text += "\n Initiates a memory minigame where you have to flip cards one at a time until you make a matching pair. You only have a set number of turns to finish the game. Specifying a difficulty (default is easy) sets the number of cards and maximum turns accordingly. Please see the game manual on github for rules, tactics, and a complete tutorial: github.com/raeleus/Hashtag-DnD/" + text += "\n\n--Danger Zone--" text += "\n#reset" text += "\n Removes all characters, locations, and notes. Changes all settings to their defaults. Use with caution!" @@ -588,6 +595,79 @@ function mapReplace(map, x, y, character) { return map } +function handleMemory() { + let text = " " + switch (state.memoryTurn) { + case "game": + text = `**Memory** +Select a card from below by typing its number or type q to quit: + +` + + let counter = 0 + for (let y = 0; y < state.memoryHeight; y++) { + for (let x = 0; x < state.memoryWidth; x++) { + counter++ + const solved = state.memorySolved[counter - 1] != null + + let cardText = "" + if (solved) { + cardText = state.memoryCards[counter - 1] + } else { + cardText = counter + } + + text += `${cardText.toString().length == 1 ? " " : ""}${cardText} ` + } + text += "\n" + } + + text += ` + +It is turn ${state.memoryTurns} of ${state.memoryMaxTurns}` + + break + case "win": + text = `You won the game in ${state.memoryTurns} out of ${state.memoryMaxTurns} turns!\n` + + let counter1 = 0 + for (let y = 0; y < state.memoryHeight; y++) { + for (let x = 0; x < state.memoryWidth; x++) { + counter1++ + text += `${state.memoryCards[counter1 - 1]} ` + } + text += "\n" + } + break + case "lose": + text = `After ${state.memoryMaxTurns} turns, you were unable to complete the game.\n` + + let counter2 = 0 + for (let y = 0; y < state.memoryHeight; y++) { + for (let x = 0; x < state.memoryWidth; x++) { + counter2++ + text += `${state.memoryCards[counter2 - 1]} ` + } + text += "\n" + } + break + case "forfeit": + text = "You decided to give up on finishing the game.\n" + + let counter3 = 0 + for (let y = 0; y < state.memoryHeight; y++) { + for (let x = 0; x < state.memoryWidth; x++) { + counter3++ + text += `${state.memoryCards[counter3 - 1]} ` + } + text += "\n" + } + break + } + + return text +} + function handleLockpicking() { var text = " " switch (state.lockpickingTurn) { diff --git a/README.md b/README.md index b57e755..485aa7c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ See the [user guide here](https://github.com/raeleus/Hashtag-DnD/wiki). Watch the [tutorial video](https://youtu.be/E5TYU7rDaBQ). v. 0.6.0 +* Added Memory/Matchmaking Game * Added Item Shop - Make sure to import the latest story cards: https://github.com/raeleus/Hashtag-DnD/blob/master/story-cards.json * Added commands #takeweapon, #takearmor, and #equip to allow automatic stat changes when using gear * Added command #reward for random loot dropping