Hangman

  • community
  • minigames
  • by limon
  • Takaro v0.0.21
  • all
Version
View export JSON

A classic Hangman game where players guess letters to reveal a hidden word. This interactive module adds a fun, competitive element to your server with full economy integration.

Key Functionality

  • Game Hosting: Players can create new Hangman games by specifying a secret word or phrase for others to guess.
  • Player Participation: Multiple players can join ongoing games, creating a social, competitive experience.
  • Letter Guessing: Players take turns guessing letters or attempting the full word, with visual feedback after each guess.
  • Progressive Difficulty: Wrong guesses accumulate toward a maximum limit, creating tension as the game progresses.
  • Economic Integration: Full support for your server's economy with:
    • Hosting fees for creating games
    • Entry fees for joining games
    • Optional costs per guess
    • Currency rewards for winners
  • Game Management: Commands for checking game status, revealing answers, or canceling games as needed.

How to Use

  1. Configuration:

    • maxWrongGuesses: Set the number of incorrect guesses allowed before the game ends.
    • minWordLength and maxWordLength: Define valid word length parameters.
    • entryFee: Cost for players to join a game.
    • hostingFee: Cost to start a new game.
    • guessPrice: Optional cost per letter guess.
    • winReward: Currency awarded to successful players.
    • hostReward: Currency awarded to hosts when no player solves the puzzle.
    • gameTimeout: Maximum duration a game can run.
  2. Commands:

    • /hangmanstart [word]: Create a new game or start a waiting game.
    • /hangmanjoin: Join an existing game that hasn't started.
    • /hangmanguess [letter/word]: Make a guess during an active game.
    • /hangmanstatus: Check the current state of the game.
    • /hangmanreveal: Reveal the answer and end the game (host/admin only).
    • /hangmancancel: Cancel the current game (host/admin only).
  3. Permissions:

    • HANGMAN_HOST: Allows players to create and host games.
    • HANGMAN_PLAY: Allows players to join games and make guesses.
    • HANGMAN_ADMIN: Grants administrative control over all games.

Game Flow

  1. A player with hosting permissions creates a new game with a secret word.
  2. Other players join the waiting game.
  3. The host starts the game when enough players have joined.
  4. Players take turns guessing letters or the complete word.
  5. With each guess, the game displays the current word state and remaining guesses.
  6. The game ends when:
    • A player correctly guesses the word (player wins the pot)
    • Players reach the maximum wrong guesses (host wins the pot)
    • An admin or host cancels or reveals the game

Important Considerations

  • Configuring appropriate fees and rewards helps balance your server economy.
  • The word validation ensures fair gameplay (letters and spaces only).
  • Players cannot join games that have already started.
  • The host cannot participate in guessing since they know the word.
  • Currency features require the economy system to be enabled.

Configuration 9

Settings you fill in when installing the module on a server.

SettingTypeDefaultDescription
maxWrongGuesses maxWrongGuesses number 6 Maximum number of wrong guesses allowed before the game ends.
winReward winReward number 100 Amount of currency to reward the player who guesses the word correctly.
hostReward hostReward number 50 Amount of currency to reward the player who hosts the game if nobody guesses the word.
gameTimeout gameTimeout number 60000 Maximum time a game can run before automatically ending.
minWordLength minWordLength number 4 Minimum length of words that can be used in the game.
maxWordLength maxWordLength number 15 Maximum length of words that can be used in the game.
entryFee entryFee number 10 Cost to join a Hangman game
guessPrice guessPrice number 0 Cost per letter guess
hostingFee hostingFee number 20 Cost to create and host a new Hangman game
Raw config schema
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [],
  "additionalProperties": false,
  "properties": {
    "maxWrongGuesses": {
      "title": "maxWrongGuesses",
      "description": "Maximum number of wrong guesses allowed before the game ends.",
      "default": 6,
      "type": "number",
      "minimum": 1,
      "maximum": 100
    },
    "winReward": {
      "title": "winReward",
      "description": "Amount of currency to reward the player who guesses the word correctly.",
      "default": 100,
      "type": "number"
    },
    "hostReward": {
      "title": "hostReward",
      "description": "Amount of currency to reward the player who hosts the game if nobody guesses the word.",
      "default": 50,
      "type": "number"
    },
    "gameTimeout": {
      "title": "gameTimeout",
      "description": "Maximum time a game can run before automatically ending.",
      "default": 60000,
      "x-component": "duration",
      "type": "number"
    },
    "minWordLength": {
      "title": "minWordLength",
      "description": "Minimum length of words that can be used in the game.",
      "default": 4,
      "type": "number",
      "minimum": 3
    },
    "maxWordLength": {
      "title": "maxWordLength",
      "description": "Maximum length of words that can be used in the game.",
      "default": 15,
      "type": "number",
      "minimum": 5
    },
    "entryFee": {
      "title": "entryFee",
      "description": "Cost to join a Hangman game",
      "default": 10,
      "type": "number"
    },
    "guessPrice": {
      "title": "guessPrice",
      "description": "Cost per letter guess",
      "default": 0,
      "type": "number"
    },
    "hostingFee": {
      "title": "hostingFee",
      "description": "Cost to create and host a new Hangman game",
      "default": 20,
      "type": "number"
    }
  }
}
Raw UI schema
{}

Commands 6

Chat commands players trigger in game.

  • hangmanStart

    No help text available

    ArgumentTypeDefaultHelp
    word string The word or phrase players will try to guess.
    Command source
    // commands/hangmanStart.js
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    
    async function main() {
        const { player, gameServerId, module: mod, arguments: args, pog } = data;
    
        try {
            // Check if player has permission to host games
            if (!checkPermission(pog, 'HANGMAN_HOST')) {
                throw new TakaroUserError('You do not have permission to host Hangman games!');
            }
    
            // Search for existing game
            const gameVars = await takaro.variable.variableControllerSearch({
                filters: {
                    key: ['hangman_game_state'],
                    gameServerId: [gameServerId],
                    moduleId: [mod.moduleId]
                }
            });
    
            // Check if there's an existing game
            if (gameVars.data.data.length === 0) {
                // No existing game
                if (!args.word) {
                    throw new TakaroUserError('You must provide a word or phrase to start a Hangman game!');
                }
    
                // Word provided, create new game
                const word = args.word.toLowerCase().trim();
    
                // Validate word
                if (word.length < mod.userConfig.minWordLength) {
                    throw new TakaroUserError(`Word must be at least ${mod.userConfig.minWordLength} characters long!`);
                }
    
                if (word.length > mod.userConfig.maxWordLength) {
                    throw new TakaroUserError(`Word must be no more than ${mod.userConfig.maxWordLength} characters long!`);
                }
    
                if (!/^[a-z ]+$/.test(word)) {
                    throw new TakaroUserError('Word can only contain letters and spaces!');
                }
    
                // Check if there's a hosting fee and process it
                let hostingFee = mod.userConfig.hostingFee || 0;
                if (hostingFee > 0) {
                    try {
                        // Check if player has enough currency
                        const playerData = await takaro.playerOnGameserver.playerOnGameServerControllerGetOne(gameServerId, player.id);
                        const currentBalance = playerData.data.data.currency;
    
                        if (currentBalance < hostingFee) {
                            throw new TakaroUserError(`You need ${hostingFee} currency to host a Hangman game. You only have ${currentBalance}.`);
                        }
    
                        // Deduct the hosting fee
                        await takaro.playerOnGameserver.playerOnGameServerControllerDeductCurrency(
                            gameServerId,
                            player.id,
                            {
                                currency: hostingFee
                            }
                        );
    
                        await player.pm(`You paid ${hostingFee} currency to host this Hangman game.`);
                    } catch (error) {
                        if (error instanceof TakaroUserError) throw error;
                        console.error('Economy error:', error);
                        throw new TakaroUserError('Failed to process hosting fee. Economy system might be disabled.');
                    }
                }
    
                // Create game state
                const gameState = {
                    word: word,
                    hostId: player.id,
                    hostName: player.name,
                    players: [{ id: player.id, name: player.name }],
                    guessedLetters: [],
                    wrongLetters: [],
                    wrongGuesses: 0,
                    maxWrongGuesses: mod.userConfig.maxWrongGuesses,
                    startTime: Date.now(),
                    gameTimeout: mod.userConfig.gameTimeout,
                    active: false,
                    started: false,
                    pot: hostingFee // Initialize pot with the hosting fee
                };
    
                // Create variable
                await takaro.variable.variableControllerCreate({
                    key: 'hangman_game_state',
                    value: JSON.stringify(gameState),
                    gameServerId,
                    moduleId: mod.moduleId
                });
    
                // Send messages
                await player.pm(`You've started a new Hangman game with the word: ${word}`);
                await player.pm('As the host, you cannot participate in guessing since you know the word.');
                await player.pm('Players can join by typing /hangmanjoin');
                await player.pm('Once players have joined, use /hangmanstart again (with the word) to begin the game!');
    
                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                    message: `${player.name} has created a new Hangman game! Type /hangmanjoin to participate.`
                });
            }
            else {
                // Existing game, try to activate it
                const gameState = JSON.parse(gameVars.data.data[0].value);
    
                // If game already started
                if (gameState.started) {
                    throw new TakaroUserError('A Hangman game is already in progress! Use /hangmanstatus to see the current game.');
                }
    
                // If player is not host
                if (gameState.hostId !== player.id) {
                    throw new TakaroUserError('You are not the host of this game! Only the host can start it.');
                }
    
                // If not enough players
                if (gameState.players.length < 2) {
                    throw new TakaroUserError('At least one other player must join before you can start the game!');
                }
    
                // Activate game
                gameState.active = true;
                gameState.started = true;
    
                // Update variable
                await takaro.variable.variableControllerUpdate(gameVars.data.data[0].id, {
                    value: JSON.stringify(gameState)
                });
    
                // Announce game start
                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                    message: `The Hangman game has begun! Use /hangmanguess [letter] to make guesses. Current pot: ${gameState.pot} currency.`
                });
            }
        } catch (error) {
            if (error instanceof TakaroUserError) {
                throw error;
            }
            console.error('Error in hangmanStart:', error);
            throw new TakaroUserError('An error occurred while processing your command.');
        }
    }
    
    await main();
  • hangmanJoin

    No help text available

    Command source
    // commands/hangmanJoin.js
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    
    async function main() {
        const { player, gameServerId, module: mod, pog } = data;
    
        // Check if player has permission to play
        if (!checkPermission(pog, 'HANGMAN_PLAY')) {
            throw new TakaroUserError('You do not have permission to play Hangman games!');
        }
    
        // Check if there's a game to join
        const gameVars = await takaro.variable.variableControllerSearch({
            filters: {
                key: ['hangman_game_state'],
                gameServerId: [gameServerId],
                moduleId: [mod.moduleId]
            }
        });
    
        if (gameVars.data.data.length === 0) {
            throw new TakaroUserError('There is no Hangman game in progress! Use /hangmanstart to create one.');
        }
    
        const gameState = JSON.parse(gameVars.data.data[0].value);
    
        // Check if player is the host
        if (player.id === gameState.hostId) {
            throw new TakaroUserError('You are the host of this game! As the host, you cannot participate in guessing since you know the word.');
        }
    
        // Check if game has already started
        if (gameState.started) {
            throw new TakaroUserError('The game has already started! Wait for the next game.');
        }
    
        // Check if player is already in the game
        if (gameState.players.some(p => p.id === player.id)) {
            throw new TakaroUserError('You have already joined this game!');
        }
    
        // Process entry fee if configured
        const entryFee = mod.userConfig.entryFee || 0;
        if (entryFee > 0) {
            try {
                // Check if player has enough currency
                const playerData = await takaro.playerOnGameserver.playerOnGameServerControllerGetOne(gameServerId, player.id);
                const currentBalance = playerData.data.data.currency;
    
                if (currentBalance < entryFee) {
                    throw new TakaroUserError(`You need ${entryFee} currency to join this game. You only have ${currentBalance}.`);
                }
    
                // Deduct the entry fee
                await takaro.playerOnGameserver.playerOnGameServerControllerDeductCurrency(
                    gameServerId,
                    player.id,
                    {
                        currency: entryFee
                    }
                );
    
                // Add to the pot
                gameState.pot += entryFee;
    
                await player.pm(`You paid ${entryFee} currency to join the game. Current pot: ${gameState.pot}`);
            } catch (error) {
                if (error instanceof TakaroUserError) throw error;
                console.error('Economy error:', error);
                throw new TakaroUserError('Failed to process entry fee. Economy system might be disabled.');
            }
        }
    
        // Add player to game
        gameState.players.push({ id: player.id, name: player.name });
    
        // Save updated game state
        await takaro.variable.variableControllerUpdate(gameVars.data.data[0].id, {
            value: JSON.stringify(gameState)
        });
    
        // Notify players
        await player.pm('You have joined the Hangman game!');
    
        // Notify the host - using the correct API call
        const hostPlayer = await takaro.player.playerControllerGetOne(gameState.hostId);
        if (hostPlayer && hostPlayer.data && hostPlayer.data.data) {
            const hostPog = await takaro.playerOnGameserver.playerOnGameServerControllerSearch({
                filters: {
                    playerId: [gameState.hostId],
                    gameServerId: [gameServerId],
                    online: [true]
                }
            });
    
            if (hostPog.data.data.length > 0) {
                // Host is online, send a PM
                await takaro.gameserver.gameServerControllerExecuteCommand(gameServerId, {
                    command: `pm ${hostPog.data.data[0].steamId} "${player.name} has joined your Hangman game! ${gameState.players.length} players are now participating."`
                });
            }
        }
    
        // Send announcement
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
            message: `${player.name} has joined the Hangman game! (${gameState.players.length} players)`
        });
    }
    
    await main();
  • hangmanGuess

    No help text available

    ArgumentTypeDefaultHelp
    letter string The letter you want to guess.
    Command source
    // commands/hangmanGuess.js
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    
    async function main() {
      const { player, gameServerId, module: mod, arguments: args, pog } = data;
    
      // Check if player has permission to play
      if (!checkPermission(pog, 'HANGMAN_PLAY')) {
        throw new TakaroUserError('You do not have permission to play Hangman games!');
      }
    
      // Check if there's a game in progress
      const gameVars = await takaro.variable.variableControllerSearch({
        filters: {
          key: ['hangman_game_state'],
          gameServerId: [gameServerId],
          moduleId: [mod.moduleId]
        }
      });
    
      if (gameVars.data.data.length === 0) {
        throw new TakaroUserError('There is no Hangman game in progress!');
      }
    
      const gameState = JSON.parse(gameVars.data.data[0].value);
    
      // Check if the game is active
      if (!gameState.active) {
        throw new TakaroUserError('The game has not started yet!');
      }
    
      // Check if player is participating
      if (!gameState.players.some(p => p.id === player.id)) {
        throw new TakaroUserError('You are not participating in this game! Wait for the next one.');
      }
    
      // Check if player is the host
      if (player.id === gameState.hostId) {
        throw new TakaroUserError('As the game host, you cannot participate in guessing since you know the word!');
      }
    
      // Validate guess
      if (!args.letter) {
        throw new TakaroUserError('You must provide a letter or word to guess!');
      }
    
      // Process guess fee
      const guessPrice = mod.userConfig.guessPrice || 0;
      if (guessPrice > 0) {
        try {
          // Check if player has enough currency
          const playerData = await takaro.playerOnGameserver.playerOnGameServerControllerGetOne(gameServerId, player.id); const currentBalance = playerData.data.data.currency;
    
          if (currentBalance < guessPrice) {
            throw new TakaroUserError(`You need ${guessPrice} currency to make a guess. You only have ${currentBalance}.`);
          }
    
          // Deduct the guess fee
          await takaro.playerOnGameserver.playerOnGameServerControllerDeductCurrency(
            gameServerId,
            player.id,
            {
              currency: guessPrice
            }
          );
    
          // Add to the pot
          gameState.pot += guessPrice;
    
          await player.pm(`You paid ${guessPrice} currency to make a guess. Current pot: ${gameState.pot}`);
        } catch (error) {
          if (error instanceof TakaroUserError) throw error;
          console.error('Economy error:', error);
          throw new TakaroUserError('Failed to process guess fee. Economy system might be disabled.');
        }
      }
    
      const guess = args.letter.toLowerCase().trim();
    
      // Handle full word guess
      if (guess.length > 1) {
        // Check if the guess matches the full word
        if (guess === gameState.word) {
          // Player correctly guessed the whole word!
          await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
            message: `Congratulations! ${player.name} has correctly guessed the word: ${gameState.word}`
          });
    
          // Award pot to winner
          if (gameState.pot > 0) {
            try {
              await takaro.playerOnGameserver.playerOnGameServerControllerAddCurrency(
                gameServerId,
                player.id,
                {
                  currency: gameState.pot
                }
              );
    
              await player.pm(`Congratulations! You won the entire pot of ${gameState.pot} currency!`);
              await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                message: `${player.name} won the Hangman game and collected the pot of ${gameState.pot} currency!`
              });
            } catch (error) {
              console.error('Error granting currency:', error);
            }
          }
    
          // Clear game state
          await takaro.variable.variableControllerDelete(gameVars.data.data[0].id);
          return;
        } else {
          // Wrong word guess - counts as a wrong guess
          gameState.wrongGuesses++;
    
          await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
            message: `${player.name} guessed "${guess}" - That's not the word! (${gameState.wrongGuesses}/${gameState.maxWrongGuesses})`
          });
    
          // Check if game over due to too many wrong guesses
          if (gameState.wrongGuesses >= gameState.maxWrongGuesses) {
            await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
              message: `Game over! The word was: ${gameState.word}`
            });
    
            // Award pot to host
            if (gameState.pot > 0) {
              try {
                await takaro.playerOnGameserver.playerOnGameServerControllerAddCurrency(
                  gameServerId,
                  gameState.hostId,
                  {
                    currency: gameState.pot
                  }
                );
    
                await takaro.player.playerControllerPm(gameState.hostId, {
                  message: `You received the pot of ${gameState.pot} currency because nobody solved your Hangman puzzle!`
                });
                await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                  message: `${gameState.hostName} receives the ${gameState.pot} currency pot as nobody solved the puzzle!`
                });
              } catch (error) {
                console.error('Error granting currency:', error);
              }
            }
    
            // Clear game state
            await takaro.variable.variableControllerDelete(gameVars.data.data[0].id);
            return;
          }
    
          // Update game state
          await takaro.variable.variableControllerUpdate(gameVars.data.data[0].id, {
            value: JSON.stringify(gameState)
          });
    
          // Render current state
          await renderAndSendGameState(gameState, gameServerId);
          return;
        }
      }
    
      // Handle single letter guess
      if (guess.length !== 1 || !/^[a-z]$/.test(guess)) {
        throw new TakaroUserError('You can only guess a single letter or the entire word!');
      }
    
      // Check if letter has already been guessed
      if (gameState.guessedLetters.includes(guess)) {
        throw new TakaroUserError(`The letter "${guess}" has already been guessed!`);
      }
    
      // Record the guess
      gameState.guessedLetters.push(guess);
    
      // Check if guess is correct
      if (gameState.word.includes(guess)) {
        // Correct guess
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
          message: `${player.name} correctly guessed "${guess}"!`
        });
      } else {
        // Wrong guess
        gameState.wrongGuesses++;
        gameState.wrongLetters.push(guess);
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
          message: `${player.name} guessed "${guess}" - not in the word! (${gameState.wrongGuesses}/${gameState.maxWrongGuesses})`
        });
      }
    
      // Render current game state
      await renderAndSendGameState(gameState, gameServerId);
    
      // Check if the game is over
      const wordLetters = new Set(gameState.word.replace(/\s/g, '').split(''));
      const correctlyGuessed = gameState.guessedLetters.filter(letter => gameState.word.includes(letter));
      const allLettersGuessed = [...wordLetters].every(letter => correctlyGuessed.includes(letter));
    
      if (allLettersGuessed) {
        // Player won!
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
          message: `Congratulations! The word has been solved: ${gameState.word}`
        });
    
        // Award pot to winner
        if (gameState.pot > 0) {
          try {
            await takaro.playerOnGameserver.playerOnGameServerControllerAddCurrency(
              gameServerId,
              player.id,
              {
                currency: gameState.pot
              }
            );
    
            await player.pm(`Congratulations! You won the entire pot of ${gameState.pot} currency!`);
            await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
              message: `${player.name} won the Hangman game and collected the pot of ${gameState.pot} currency!`
            });
          } catch (error) {
            console.error('Error granting currency:', error);
          }
        }
    
        // Clear game state
        await takaro.variable.variableControllerDelete(gameVars.data.data[0].id);
    
      } else if (gameState.wrongGuesses >= gameState.maxWrongGuesses) {
        // Game over - too many wrong guesses
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
          message: `Game over! The word was: ${gameState.word}`
        });
    
        // Award pot to host
        if (gameState.pot > 0) {
          try {
            await takaro.playerOnGameserver.playerOnGameServerControllerAddCurrency(
              gameServerId,
              gameState.hostId,
              {
                currency: gameState.pot
              }
            );
    
            await takaro.player.playerControllerPm(gameState.hostId, {
              message: `You received the pot of ${gameState.pot} currency because nobody solved your Hangman puzzle!`
            });
            await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
              message: `${gameState.hostName} receives the ${gameState.pot} currency pot as nobody solved the puzzle!`
            });
          } catch (error) {
            console.error('Error granting currency:', error);
          }
        }
    
        // Clear game state
        await takaro.variable.variableControllerDelete(gameVars.data.data[0].id);
      } else {
        // Game continues - save updated state
        await takaro.variable.variableControllerUpdate(gameVars.data.data[0].id, {
          value: JSON.stringify(gameState)
        });
      }
    }
    
    // Helper function to render and send game state
    async function renderAndSendGameState(gameState, gameServerId) {
      const { word, guessedLetters, wrongGuesses, maxWrongGuesses, wrongLetters } = gameState;
    
      // Create the word display with correctly guessed letters shown
      const wordDisplay = word.split('').map(letter => {
        if (letter === ' ') return ' ';
        return guessedLetters.includes(letter.toLowerCase()) ? letter : '_';
      }).join(' ');
    
      // Create a dynamic status based on current progress
      const percentComplete = Math.floor((wrongGuesses / maxWrongGuesses) * 100);
      let hangmanStatus;
    
      if (wrongGuesses === 0) {
        hangmanStatus = "Hangman: No wrong guesses yet";
      } else {
        hangmanStatus = `Hangman: ${wrongGuesses}/${maxWrongGuesses} wrong guesses (${percentComplete}% to game over)`;
      }
    
      const wrongGuessesText = `Wrong guesses: ${wrongLetters.join(' ') || 'none'}`;
      const guessedLettersText = `Letters guessed: ${guessedLetters.join(' ') || 'none'}`;
      const potInfo = `Current pot: ${gameState.pot} currency`;
    
      const display = `${hangmanStatus}\n${wordDisplay}\n${wrongGuessesText}\n${guessedLettersText}\n${potInfo}`;
    
      await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
        message: display
      });
    }
    
    await main();
  • hangmanStatus

    No help text available

    Command source
    // commands/hangmanStatus.js
    import { takaro, data, TakaroUserError } from '@takaro/helpers';
    import { getGameState, renderHangmanState } from './utils.js';
    
    async function main() {
        const { player, gameServerId, module: mod } = data;
    
        // Check if there's a game in progress
        const gameState = await getGameState(gameServerId, mod.moduleId);
        if (!gameState) {
            throw new TakaroUserError('There is no Hangman game in progress!');
        }
    
        // Show the game status
        if (!gameState.started) {
            const playerList = gameState.players.map(p => p.name).join(', ');
            await player.pm(`Hangman game hosted by ${gameState.hostName} is waiting to start.`);
            await player.pm(`Players (${gameState.players.length}): ${playerList}`);
            await player.pm(`Current pot: ${gameState.pot || 0} currency`);
            await player.pm('Type /hangmanjoin to participate!');
        } else {
            // Show the current state of the game
            const display = renderHangmanState(gameState);
            await player.pm(`Current Hangman Game Status:`);
            await player.pm(display);
            await player.pm(`Players (${gameState.players.length}): ${gameState.players.map(p => p.name).join(', ')}`);
            await player.pm(`Current pot: ${gameState.pot || 0} currency`);
        }
    }
    
    await main();
  • hangmanReveal

    No help text available

    Command source
    // commands/hangmanReveal.js
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    import { getGameState, saveGameState } from './utils.js';
    
    async function main() {
        const { player, gameServerId, module: mod, pog } = data;
    
        // Check if there's a game in progress
        const gameState = await getGameState(gameServerId, mod.moduleId);
        if (!gameState) {
            throw new TakaroUserError('There is no Hangman game in progress!');
        }
    
        // Check if player has permission to reveal
        const isHost = gameState.hostId === player.id;
        const isAdmin = checkPermission(pog, 'HANGMAN_ADMIN');
    
        if (!isHost && !isAdmin) {
            throw new TakaroUserError('Only the game host or an admin can reveal the word!');
        }
    
        // Reveal the word and end the game
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
            message: `${player.name} has revealed the word: ${gameState.word}`
        });
    
        // Clear game state
        await clearGameState(gameServerId, mod.moduleId);
        return { success: true };
    }
    
    await main();
  • hangmanCancel

    No help text available

    Command source
    // commands/hangmanCancel.js
    import { takaro, data, TakaroUserError, checkPermission } from '@takaro/helpers';
    import { getGameState, clearGameState } from './utils.js';
    
    async function main() {
        const { player, gameServerId, module: mod, pog } = data;
    
        // Check if there's a game to cancel
        const gameState = await getGameState(gameServerId, mod.moduleId);
        if (!gameState) {
            throw new TakaroUserError('There is no Hangman game in progress!');
        }
    
        // Check if player has permission to cancel
        const isHost = gameState.hostId === player.id;
        const isAdmin = checkPermission(pog, 'HANGMAN_ADMIN');
    
        if (!isHost && !isAdmin) {
            throw new TakaroUserError('Only the game host or an admin can cancel the game!');
        }
    
        // Cancel the game
        await clearGameState(gameServerId, mod.moduleId);
    
        // Announce cancellation
        await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
            message: `${player.name} has cancelled the current Hangman game.`
        });
    
        if (gameState.started) {
            await takaro.gameserver.gameServerControllerSendMessage(gameServerId, {
                message: `The word was: ${gameState.word}`
            });
        }
    
    
    }
    
    await main()

Functions 1

Shared helpers the module's commands, hooks and cron jobs import.

  • utils

    Function source
    // functions/utils.js
    import { takaro } from '@takaro/helpers';
    
    /**
     * Gets the current hangman game state from variables
     */
    export async function getGameState(gameServerId, moduleId) {
        const gameVars = await takaro.variable.variableControllerSearch({
            filters: {
                key: ['hangman_game_state'],
                gameServerId: [gameServerId],
                moduleId: [moduleId]
            }
        });
    
        if (gameVars.data.data.length === 0) {
            return null;
        }
    
        return JSON.parse(gameVars.data.data[0].value);
    }
    
    /**
     * Saves the current hangman game state to variables
     */
    export async function saveGameState(gameState, gameServerId, moduleId) {
        const gameVars = await takaro.variable.variableControllerSearch({
            filters: {
                key: ['hangman_game_state'],
                gameServerId: [gameServerId],
                moduleId: [moduleId]
            }
        });
    
        if (gameVars.data.data.length === 0) {
            await takaro.variable.variableControllerCreate({
                key: 'hangman_game_state',
                value: JSON.stringify(gameState),
                gameServerId,
                moduleId
            });
        } else {
            await takaro.variable.variableControllerUpdate(gameVars.data.data[0].id, {
                value: JSON.stringify(gameState)
            });
        }
    }
    
    /**
     * Clears the current hangman game state
     */
    export async function clearGameState(gameServerId, moduleId) {
        const gameVars = await takaro.variable.variableControllerSearch({
            filters: {
                key: ['hangman_game_state'],
                gameServerId: [gameServerId],
                moduleId: [moduleId]
            }
        });
    
        if (gameVars.data.data.length > 0) {
            await takaro.variable.variableControllerDelete(gameVars.data.data[0].id);
        }
    }
    
    /**
     * Renders the current hangman state for display
     */
    export function renderHangmanState(gameState) {
        const { word, guessedLetters, wrongGuesses, maxWrongGuesses, wrongLetters } = gameState;
    
        // Create the word display with correctly guessed letters shown
        const wordDisplay = word.split('').map(letter => {
            if (letter === ' ') return ' ';
            return guessedLetters.includes(letter.toLowerCase()) ? letter : '_';
        }).join(' ');
    
        // Create a dynamic status based on current progress
        const percentComplete = Math.floor((wrongGuesses / maxWrongGuesses) * 100);
        let hangmanStatus;
    
        if (wrongGuesses === 0) {
            hangmanStatus = "Hangman: No wrong guesses yet";
        } else {
            hangmanStatus = `Hangman: ${wrongGuesses}/${maxWrongGuesses} wrong guesses (${percentComplete}% to game over)`;
        }
    
        const wrongGuessesText = `Wrong guesses: ${wrongLetters ? wrongLetters.join(' ') : 'none'}`;
        const guessedLettersText = `Letters guessed: ${guessedLetters.length > 0 ? guessedLetters.join(' ') : 'none'}`;
        const potInfo = `Current pot: ${gameState.pot || 0} currency`;
    
        return `${hangmanStatus}\n${wordDisplay}\n${wrongGuessesText}\n${guessedLettersText}\n${potInfo}`;
    }
    
    /**
     * Checks if a player has permission to perform an action
     */
    export function hasPermission(pog, permission) {
        for (const role of pog.roles) {
            const perm = role.permissions.find(p => p.permission === permission);
            if (perm) return true;
        }
        return false;
    }

Permissions 3

Roles you can grant to decide who may use what.

  • Host Hangman Game

    Allows the player to start and host Hangman games.

  • Play Hangman

    Allows the player to join and make guesses in Hangman games.

  • Hangman Admin

    Allows the player to manage and control running Hangman games.