From d795d500ca25418f9c54d4fb12346ff38ea77909 Mon Sep 17 00:00:00 2001 From: raeleus Date: Sat, 4 Jan 2025 23:55:32 -0800 Subject: [PATCH] Added Mastermind minigame. --- Input.js | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++- Output.js | 46 ++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/Input.js b/Input.js index f736dbd..30b56e9 100644 --- a/Input.js +++ b/Input.js @@ -85,6 +85,7 @@ const repeatTurnSynonyms = ["repeatturn", "repeat"] const basicDeckSynonyms = ["basicdeck", "stragedybasicdeck"] const cardShopSynonyms = ["cardshop", "stragedyshop", "cardstore", "stragedystore"] const stragedySynonyms = ["stragedy", "playgame", "game", "startgame", "begingame", "playcards", "playstragedy", "startstragedy", "beginstragedy"] +const lockpickSynonyms = ["lockpick", "lockpicking", "codebreaker", "pick", "hack", "mastermind"] const addCardSynonyms = ["addcard"] const helpSynonyms = ["help"] @@ -116,6 +117,12 @@ const modifier = (text) => { else text = rawText } + if (state.lockpickingTurn != null) { + text = handleLockpickingTurn(text) + if (state.lockpickingTurn != null) return { text } + else text = rawText + } + if (state.initialized == null || !text.includes("#")) { state.initialized = true; return { text } @@ -244,7 +251,8 @@ const modifier = (text) => { if (text == null) text = processCommandSynonyms(command, commandName, repeatTurnSynonyms, doRepeatTurn) if (text == null) text = processCommandSynonyms(command, commandName, basicDeckSynonyms, doBasicDeck) if (text == null) text = processCommandSynonyms(command, commandName, cardShopSynonyms, doCardShop) - if (text == null) text = processCommandSynonyms(command, commandName, stragedySynonyms, doStragedy) + 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, addCardSynonyms, doAddCard) if (text == null) text = processCommandSynonyms(command, commandName, helpSynonyms, doHelp) if (text == null) { @@ -1277,6 +1285,111 @@ function doSetupEnemy(command) { return " " } +function doLockpick(command) { + var arg0 = getArgument(command, 0) + if (arg0 == null) { + arg0 = "easy" + } + + state.lockpickingTurn = "intro" + state.lockpickingGuesses = 0 + state.show = "lockpicking" + + switch(arg0) { + case "impossible": + state.lockpickingSlots = 7 + state.lockpickingGuessMax = 15 + break + case "hard": + state.lockpickingSlots = 6 + state.lockpickingGuessMax = 15 + break + case "medium": + state.lockpickingSlots = 5 + state.lockpickingGuessMax = 15 + break + case "effortless": + state.lockpickingSlots = 4 + state.lockpickingGuessMax = 15 + break + case "automatic": + state.lockpickingSlots = 3 + state.lockpickingGuessMax = 20 + break + case "easy": + default: + state.lockpickingSlots = 4 + state.lockpickingGuessMax = 12 + break + } + + state.lockpickingCombination = "" + for (let i = 0; i < state.lockpickingSlots; i++) { + state.lockpickingCombination += getRandomFromList("r", "y", "w", "g", "o", "b") + } + log(state.lockpickingCombination) + + return " " +} + +function handleLockpickingTurn(text) { + state.show = "lockpicking" + + 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.lockpickingTurn = "forfeit" + return text + } + + switch (state.lockpickingTurn) { + case "intro": + state.lockpickingTurn = "game" + case "game": + state.lockpickingInput = text + + state.lockpickingCorrect = 0 + let combo = state.lockpickingCombination + for (var i = 0; i < state.lockpickingSlots; i++) { + let letter = text.substring(i, i + 1) + if (letter == state.lockpickingCombination.substring(i, i + 1)) state.lockpickingCorrect++ + combo = combo.replace(letter, "") + } + state.lockpickingWrongPlace = state.lockpickingSlots - combo.length - state.lockpickingCorrect + + if (state.lockpickingInput.length == state.lockpickingSlots) state.lockpickingGuesses++ + + if (state.lockpickingCorrect == state.lockpickingSlots) state.lockpickingTurn = "win" + else if (state.lockpickingGuesses >= state.lockpickingGuessMax) state.lockpickingTurn = "lose" + + return text + case "win": + case "lose": + case "forfeit": + state.show = null + state.lockpickingTurn = null + return text + } + + return `\nUnexpected Mastermind state. Input text: ${text}` +} + function doBasicDeck(command) { var character = getCharacter() var takeWord = character.name == "You" ? "take" : "takes" diff --git a/Output.js b/Output.js index 4f5c7e7..848715b 100644 --- a/Output.js +++ b/Output.js @@ -93,6 +93,9 @@ const modifier = (text) => { case "stragedyShop": text += handleStragedyShop() break + case "lockpicking": + text += handleLockpicking() + break case "bio": text += `*** ${possessiveName.toUpperCase()} BIO ***\n` text += `Class: ${character.className}\n` @@ -523,6 +526,10 @@ const modifier = (text) => { text += "\n#stragedy (automatic|effortless|easy|medium|hard|impossible)" text += "\n Initiates a game of Stragedy, a card game played against an AI opponent. Specifying a difficulty (default is easy) grants the opponent a corresponding deck. Please see the game manual on github for rules, tactics, and a complete tutorial: github.com/raeleus/Hashtag-DnD/" + text += "\n\n--Lockpicking Minigame--" + 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--Danger Zone--" text += "\n#reset" text += "\n Removes all characters, locations, and notes. Changes all settings to their defaults. Use with caution!" @@ -563,6 +570,45 @@ function mapReplace(map, x, y, character) { return map } +function handleLockpicking() { + var character = getCharacter() + var haveWord = character.name == "You" ? "have" : "has" + var possessiveName = getPossessiveName(character.name) + + var text = " " + switch (state.lockpickingTurn) { + case "intro": + text = `**Mastermind** +Welcome to Mastermind! A minigame to stand in for lockpicking, hacking, and other tasks of skill. +Please see the game manual on github for rules, tactics, and a complete tutorial: +github.com/raeleus/Hashtag-DnD/ +You must solve the ${state.lockpickingSlots} color combination within ${state.lockpickingGuessMax} guesses! +Colors: r (red), y (yellow), w (white), g (green), o (orange), b (blue) +Enter your first guess below by typing the letter for each color. Type "q" to quit: +` + break + case "game": + if (state.lockpickingInput.length != state.lockpickingSlots) text = `\nAn incorrect number of colors was input. Only type ${state.lockpickingSlots} letters!\n` + else text = ` +Correct: ${state.lockpickingCorrect}. Wrong position: ${state.lockpickingWrongPlace}. ${state.lockpickingGuessMax - state.lockpickingGuesses} ${state.lockpickingGuessMax - state.lockpickingGuesses == 1 ? "try" : "tries"} left. +Colors: r (red), y (yellow), w (white), g (green), o (orange), b (blue) +Enter your guess below by typing the letter for each color. Type "q" to quit: +` + break + case "win": + text = `You solved the combination with ${state.lockpickingGuesses} ${state.lockpickingGuesses == 1 ? "guess" : "guesses"}!` + break + case "lose": + text = `After ${state.lockpickingGuesses} ${state.lockpickingGuesses == 1 ? "guess" : "guesses"}, you were unable to solve the combination...` + break + case "forfeit": + text = "You decided to give up on solving the combination." + break + } + + return text +} + function handleStragedy() { var character = getCharacter() var haveWord = character.name == "You" ? "have" : "has"