From b0e9b94561786297b745c3ef34f947b18dc23be8 Mon Sep 17 00:00:00 2001 From: "Marten (msc)" Date: Sat, 7 Sep 2024 07:40:30 -0500 Subject: [PATCH] fixup! [ADD] support players without `username` --- README.md | 6 ++++-- src/handlers/acceptGame.ts | 8 ++++---- src/handlers/listGames.ts | 4 +++- src/handlers/newGame.ts | 19 +++++++++++++++---- src/handlers/revengeGame.ts | 15 +++++++++------ src/handlers/rollDice.ts | 34 +++++++++++++++++++++++++--------- src/handlers/scoreBoard.ts | 7 +++++-- src/models/game.ts | 4 ++-- 8 files changed, 67 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 957d0b1..f9f43bd 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # 🎲 Dice Duel Bot 🎲 -A Telegram bot for playing dice duels with friends, powered by [Deno](https://deno.com/). +A Telegram bot for playing dice duels with friends, powered by +[Deno](https://deno.com/). ## How to play 1. Add [@diceduel_bot](https://t.me/diceduel_bot) to your Telegram group. 2. Invite your friends to the group. -3. In the group, type `/newgame @ {}` to start a new game. (If no winning rounds are specified, the default is 1) +3. In the group, type `/newgame @ {}` to start a new + game. (If no winning rounds are specified, the default is 1) 4. The `otherPlayer` accepts the game by clicking the button in the message. 5. Both player roll the dice by sending the 🎲 emoji or by typing `:dice` 6. After the game is finished, use `/scoreboard` to see the current standings. diff --git a/src/handlers/acceptGame.ts b/src/handlers/acceptGame.ts index cd56999..8d04a39 100644 --- a/src/handlers/acceptGame.ts +++ b/src/handlers/acceptGame.ts @@ -29,7 +29,7 @@ export async function acceptGameHandler(ctx: Context, gameId: string) { if ( ctx.from?.username !== game.opponent.username && - ctx.from?.first_name !== game.opponent.first_name + ctx.from?.first_name !== game.opponent.username ) { await ctx.answerCallbackQuery("You are not the challenged player."); return; @@ -84,9 +84,9 @@ export async function revengeHandler(ctx: Context, gameId: string) { .text("Accept Challenge", `accept_game:${createGameResult.game?.id}`); await ctx.reply( - `🎲 @${challenger.username} has challenged @${opponent?.username} to a dice duel with ${ - oldGame?.winningRounds || 1 - } winning rounds! 🎲`, + `🎲 @${challenger.username || challenger.first_name} has challenged @${ + opponent?.username || opponent?.first_name + } to a dice duel with ${oldGame?.winningRounds || 1} winning rounds! 🎲`, { reply_markup: keyboard }, ); } diff --git a/src/handlers/listGames.ts b/src/handlers/listGames.ts index e42dd4f..16c3e85 100644 --- a/src/handlers/listGames.ts +++ b/src/handlers/listGames.ts @@ -36,7 +36,9 @@ export async function listGamesCommand(ctx: Context) { status = "Finished"; break; } - return `@${game.challenger.username} vs @${game.opponent.username} - ${status}`; + return `@${game.challenger.username || game.challenger.first_name} vs @${ + game.opponent.username || game.opponent.first_name + } - ${status}`; }).join("\n"); await ctx.reply(`Active games in this channel:\n\n${gameList}`); diff --git a/src/handlers/newGame.ts b/src/handlers/newGame.ts index b058284..3e78358 100644 --- a/src/handlers/newGame.ts +++ b/src/handlers/newGame.ts @@ -20,17 +20,26 @@ export async function newGameCommand(ctx: Context) { const challenger: Player = await getPlayerFromContext(ctx); const args = ctx.match.toString().split(" "); - const opponentUsername = args[0].replace("@", ""); + const opponentUsernameOrFirstName = args[0].replace("@", ""); // extract the number of winning rounds from the ctx as a possible 2nd argument const winningRounds = args.length > 1 ? parseInt(args[1]) : 1; - if (challenger.username === opponentUsername) { + if (isNaN(winningRounds)) { + await ctx.reply("The number of winning rounds must be a number!"); + return; + } + + if ( + challenger.username === opponentUsernameOrFirstName || + challenger.first_name === opponentUsernameOrFirstName + ) { await ctx.reply("You can't challenge yourself!"); return; } + // this might be a username or first name const opponent: Player = { - username: opponentUsername, + username: opponentUsernameOrFirstName, }; const createGameResult: CreateGameResult = await createGame( challenger, @@ -50,7 +59,9 @@ export async function newGameCommand(ctx: Context) { .text("Accept Challenge", `accept_game:${createGameResult.game?.id}`); await ctx.reply( - `🎲 @${challenger.username} has challenged @${opponent.username} to a dice duel with ${winningRounds} winning rounds! 🎲`, + `🎲 @${ + challenger.username || challenger.first_name + } has challenged @${opponent.username} to a dice duel with ${winningRounds} winning rounds! 🎲`, { reply_markup: keyboard, protect_content: true }, ); } diff --git a/src/handlers/revengeGame.ts b/src/handlers/revengeGame.ts index 95496a5..9a7bd0a 100644 --- a/src/handlers/revengeGame.ts +++ b/src/handlers/revengeGame.ts @@ -38,10 +38,13 @@ export async function revengeHandler(ctx: Context, gameId: string) { const keyboard = new InlineKeyboard() .text("Accept Challenge", `accept_game:${createGameResult.game?.id}`); - await ctx.reply( - `🎲 @${challenger.username} has challenged @${opponent?.username} to a dice duel with ${ - oldGame?.winningRounds || 1 - } winning rounds! 🎲`, - { reply_markup: keyboard }, - ); + await Promise.all([ + ctx.reply( + `🎲 @${challenger.username || challenger.first_name} has challenged @${ + opponent?.username || opponent?.first_name + } to a dice duel with ${oldGame?.winningRounds || 1} winning rounds! 🎲`, + { reply_markup: keyboard }, + ), + ctx.answerCallbackQuery(), + ]); } diff --git a/src/handlers/rollDice.ts b/src/handlers/rollDice.ts index ccd2209..77f892d 100644 --- a/src/handlers/rollDice.ts +++ b/src/handlers/rollDice.ts @@ -34,8 +34,8 @@ export async function rollDiceHandler(ctx: Context) { ); const otherPlayerUsername = playerIsChallenger - ? game.opponent.username - : game.challenger.username; + ? game.opponent.username || game.opponent.first_name + : game.challenger.username || game.challenger.first_name; const { challengerScore, opponentScore } = determineScore(rollResult.game); const playerScore = playerIsChallenger ? challengerScore : opponentScore; const otherPlayerScore = playerIsChallenger ? opponentScore : challengerScore; @@ -45,27 +45,39 @@ export async function rollDiceHandler(ctx: Context) { switch (rollResult.status) { case RollStatus.win: await ctx.reply( - `@${player.username} rolls a ${rollScore}! This round goes to @${player.username}!\n\n${scoreCard}`, + `@${ + player.username || player.first_name + } rolls a ${rollScore}! This round goes to @${ + player.username || player.first_name + }!\n\n${scoreCard}`, ); break; case RollStatus.loose: await ctx.reply( - `@${player.username} rolls a ${rollScore}! This round goes to @${otherPlayerUsername}!\n\n${scoreCard}`, + `@${ + player.username || player.first_name + } rolls a ${rollScore}! This round goes to @${otherPlayerUsername}!\n\n${scoreCard}`, ); break; case RollStatus.invalid: await ctx.reply( - `Sorry, @${player.username} it's not your turn. @${otherPlayerUsername} needs to roll first.`, + `Sorry, @${ + player.username || player.first_name + } it's not your turn. @${otherPlayerUsername} needs to roll first.`, ); break; case RollStatus.tie: await ctx.reply( - `@${player.username} rolls a ${rollScore}! This round is a tie!\n\n${scoreCard}`, + `@${ + player.username || player.first_name + } rolls a ${rollScore}! This round is a tie!\n\n${scoreCard}`, ); break; case RollStatus.open: await ctx.reply( - `@${player.username} rolls a ${rollScore} and opens this round! It's your turn @${otherPlayerUsername}!`, + `@${ + player.username || player.first_name + } rolls a ${rollScore} and opens this round! It's your turn @${otherPlayerUsername}!`, ); break; case RollStatus.closed: { @@ -76,12 +88,16 @@ export async function rollDiceHandler(ctx: Context) { .text("Revenge!", `revenge:${game.id}`); if (playerWins) { await ctx.reply( - `πŸ‘‘ Winner, winner, chicken dinner! @${player.username} rolls a ${rollScore} and wins this game!\n\n${scoreCard}`, + `πŸ‘‘ Winner, winner, chicken dinner! @${ + player.username || player.first_name + } rolls a ${rollScore} and wins this game!\n\n${scoreCard}`, { reply_markup: keyboard }, ); } else { await ctx.reply( - `πŸ‘‘Winner, winner, chicken dinner! @${player.username} rolls a ${rollScore} and looses this round and the match! The winner is: @${otherPlayerUsername}!\n\n${scoreCard}`, + `πŸ‘‘Winner, winner, chicken dinner! @${ + player.username || player.first_name + } rolls a ${rollScore} and looses this round and the match! The winner is: @${otherPlayerUsername}!\n\n${scoreCard}`, { reply_markup: keyboard }, ); } diff --git a/src/handlers/scoreBoard.ts b/src/handlers/scoreBoard.ts index 99649ae..1196e6d 100644 --- a/src/handlers/scoreBoard.ts +++ b/src/handlers/scoreBoard.ts @@ -40,8 +40,11 @@ export async function scoreBoardHandler(ctx: Context) { } const players = await Promise.all(promises); for (const player of players) { - if (player && player.id && player.username) { - playerIdToName.set(player.id, player.username); + if (player && player.id && (player.username || player.first_name)) { + playerIdToName.set( + player.id, + (player.username || player.first_name) as string, + ); } } diff --git a/src/models/game.ts b/src/models/game.ts index 668cb56..546666b 100644 --- a/src/models/game.ts +++ b/src/models/game.ts @@ -33,8 +33,8 @@ export interface Game { export interface Player { id?: string; - username: string; - first_name: string; // use snake case like TG + username?: string; + first_name?: string; // use snake case like TG } export interface CreateGameResult {