diff --git a/config/default.js b/config/default.js index 1a59e1c..06f2964 100644 --- a/config/default.js +++ b/config/default.js @@ -22,7 +22,7 @@ module.exports = { greeting: 'Hi, I am aisha, your game host!', usernamePrefix: '@', channels: ['GamesNight'], - games: ['mash', 'trivia', 'letters', 'duck', 'ping', 'say', 'kill'], + games: ['mash', 'trivia', 'letters', 'duck', 'ping', 'say', 'kill', 'help'], schatColors: { red: 'var(--message-3)', green: 'var(--message-23)', diff --git a/src/games/duck.js b/src/games/duck.js index 0fc1571..61a88c3 100644 --- a/src/games/duck.js +++ b/src/games/duck.js @@ -32,7 +32,7 @@ function launchDuck(context) { function onCommand(args, context) { const duck = ducks.get(context.room.id); - if (!duck && context.command === 'bang') { + if (!duck && ['bang', 'shoot'].includes(context.command)) { const message = pickRandom([ `There is no duck, what are you shooting at, ${context.user.prefixedUsername}?!`, `You're wasting bullets, ${context.user.prefixedUsername}, there is no duck!`, @@ -58,7 +58,7 @@ function onCommand(args, context) { const hit = Math.random() > config.duck.missRatio; const time = ((new Date().getTime() - duck.getTime()) / 1000).toFixed(3); - if (context.command === 'bang') { + if (['bang', 'shoot'].includes(context.command)) { if (hit) { context.sendMessage(`You shot a duck in ${style.bold(`${time} seconds`)}, ${context.user.prefixedUsername}`, context.room.id); launchDuck(context); @@ -83,7 +83,7 @@ function onCommand(args, context) { if (['bef', 'befriend'].includes(context.command)) { if (hit) { - context.sendMessage(`You befriended a duck in ${style.bold(`${time} seconds`)}, ${context.user.prefixedUsername}`, context.room.id); + context.sendMessage(`You befriended a duck in ${style.bold(style.green(`${time} seconds`))}, ${context.user.prefixedUsername}`, context.room.id); launchDuck(context); context.setPoints(context.user, 1, { key: 'befriend' }); @@ -104,7 +104,8 @@ function onCommand(args, context) { module.exports = { name: 'Duck', - commands: ['bang', 'bef', 'befriend'], + commands: ['bang', 'shoot', 'bef', 'befriend'], + help: `There are ducks on the loose! When you see one, you can be nice and ${config.prefix}befriend them, or... ${config.prefix}bang`, onStart: launchDuck, onCommand, }; diff --git a/src/games/help.js b/src/games/help.js new file mode 100644 index 0000000..dd3e43b --- /dev/null +++ b/src/games/help.js @@ -0,0 +1,16 @@ +'use strict'; + +const config = require('config'); +const { version } = require('../../package.json'); + +function onCommand(args, context) { + const commandsByGame = Object.entries(context.games).reduce((acc, [command, game]) => ({ ...acc, [game.name]: [...(acc[game.name] || []), command] }), {}); + const commands = Object.entries(commandsByGame).map(([gameName, gameCommands]) => `${gameCommands.length > 1 ? `${gameName}: ` : ''}${gameCommands.map((command) => `${config.prefix}${command}`).join(', ')}`).join(' | '); + + context.sendMessage(`${config.user.username} v${version} | ${commands} | try ${config.prefix}game:help for more info, ${config.prefix}game:score [username] and ${config.prefix}game:lead for scores.`, context.room.id, { styleCommands: true }); +} + +module.exports = { + onCommand, + commands: ['commands'], +}; diff --git a/src/games/kill.js b/src/games/kill.js index fdf4c83..6682937 100644 --- a/src/games/kill.js +++ b/src/games/kill.js @@ -20,6 +20,8 @@ function onCommand(args, context) { } module.exports = { + name: 'Kill', commands: ['kill', 'restart', 'shutdown'], + help: `Am I getting a little confused? Try to ${config.prefix}restart me.`, onCommand, }; diff --git a/src/games/letters.js b/src/games/letters.js index 31e8e31..8f00790 100644 --- a/src/games/letters.js +++ b/src/games/letters.js @@ -145,11 +145,6 @@ function onCommand(args, context) { return; } - if (['help', 'commands'].includes(context.subcommand)) { - context.sendMessage('Make the longest word using the available letters. To pick the letters, say con(sonant), vow(el) or supply multiple: CCCCCVVVV. Available subcommands: :stop', context.room.id); - return; - } - if (!context.subcommand) { start(context); } @@ -188,6 +183,7 @@ function onMessage(message, context) { module.exports = { name: 'Letters', + help: `Make the longest word from the ${config.letters.length} letters on the board. Start with ${config.prefix}letters, and fill the board by selecting a vow(el), a con(sonant), or multiple at once like CCVVCCVVC.`, onCommand, onMessage, }; diff --git a/src/games/mash.js b/src/games/mash.js index 5cd3b85..4bd2f44 100644 --- a/src/games/mash.js +++ b/src/games/mash.js @@ -194,7 +194,7 @@ function onCommand(args, context) { } if (!word || !mash) { - context.sendMessage(`Start a mash with ${config.prefix}mash {length}`, context.room.id); + context.sendMessage(`Start a mash with ${config.prefix}mash [length]`, context.room.id); return; } @@ -214,4 +214,5 @@ module.exports = { commands: ['mash', ...defineCommands, ...resolveCommands], onCommand, onMessage, + help: `Resolve the anagram. Get a new mash with ${config.prefix}mash [length], look up definitions with ${config.prefix}define [word], resolve an anagram (that's not currently in play) with ${config.prefix}solve [anagram].`, }; diff --git a/src/games/say.js b/src/games/say.js index 049968e..d90a409 100644 --- a/src/games/say.js +++ b/src/games/say.js @@ -37,5 +37,6 @@ function onCommand(args, context) { } module.exports = { + name: 'Say', onCommand, }; diff --git a/src/games/trivia.js b/src/games/trivia.js index 05ccebd..274b5a5 100644 --- a/src/games/trivia.js +++ b/src/games/trivia.js @@ -168,10 +168,6 @@ function onCommand(args, context) { context.sendMessage(`There is no game going on at the moment. Start one with ${config.prefix}trivia!`, context.room.id); } - if (['help', 'commands'].includes(context.subcommand)) { - context.sendMessage(`Available subcommands for ${config.prefix}trivia are :stop, :mode, :rounds and :timeout`, context.room.id); - } - const subcommand = context.subcommand?.toLowerCase(); if (subcommand && settings[subcommand]) { @@ -230,4 +226,5 @@ module.exports = { name: 'Trivia', onCommand, onMessage, + help: `Boast your pointless knowledge! Start a game with ${config.prefix}trivia. Available subcommands are :stop, :mode [first|timeout], :rounds [${config.trivia.bounds.rounds[0]}-${config.trivia.bounds.rounds[1]}] and :timeout [${config.trivia.bounds.timeout[0]}-${config.trivia.bounds.timeout[1]}]`, }; diff --git a/src/play.js b/src/play.js index 262e046..4557354 100644 --- a/src/play.js +++ b/src/play.js @@ -84,6 +84,30 @@ function getLeaderboard(game, { user, room, command }) { game.sendMessage(`The top ${Math.min(Object.keys(leaderboard).length, 10)} ${style.italic(game.name)} players are: ${curatedLeaderboard}`, room.id); } +/* eslint-disable no-irregular-whitespace */ +function styleCommands(rawBody) { + const styledCommands = rawBody.replaceAll(new RegExp(`${config.prefix}\\w+`, 'g'), (match) => (match.includes('game') ? `${style.cyan(config.prefix)}${style.italic(style.grey(match.slice(1)))}` : style.cyan(match))); + const styledSubcommands = styledCommands.replaceAll(/:\w+/g, (match) => style.green(match)); + + return styledSubcommands.replaceAll(/(? { + // using a zero-width space so numerical values don't mess up the color code + const value = match.slice(1, -1).replace(/[|-]/, (delimiter) => `​${style.grey(delimiter)}​`); + + return `${style.grey('[')}​${value}​${style.grey(']')}`; + }); +} +/* eslint-enable no-irregular-whitespace */ + +function curateMessageBody(rawBody, game, key, options) { + const body = options?.styleCommands ? styleCommands(rawBody) : rawBody; + + if (options?.label === false || config.labels === false) { + return body; + } + + return `${style.grey(`[${game.name || key}]`)} ${body}`; +} + async function getGames(bot, identifier) { await initPoints(identifier); @@ -91,7 +115,7 @@ async function getGames(bot, identifier) { const game = require(`./games/${key.game || key}`); // eslint-disable-line global-require, import/no-dynamic-require const sendMessage = (body, roomId, options, recipient) => { - const curatedBody = options?.label === false || config.labels === false ? body : `${style.grey(`[${game.name || key}]`)} ${body}`; + const curatedBody = curateMessageBody(body, game, key, options); if (config.platform === 'irc') { bot.client.say(roomId || recipient, curatedBody); @@ -191,6 +215,14 @@ function onMessage(message, bot, games) { return; } + if (game && game.help && subcommand === 'help') { + game.sendMessage(game.help, room.id, { styleCommands: true }); + + if (game.blockHelp !== false) { + return; + } + } + if (game && game.onCommand) { if (user) { user.points = points[game.key]?.[`${user.id}:${user.username}`] || 0; @@ -205,6 +237,7 @@ function onMessage(message, bot, games) { user, room, points: points[game.key] || {}, + games, logger, }); }