Skip to content

Commit

Permalink
fixup! [ADD] support players without username
Browse files Browse the repository at this point in the history
  • Loading branch information
maschlr committed Sep 7, 2024
1 parent 85960c6 commit b0e9b94
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 30 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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 @<otherPlayer> {<winningRounds>}` to start a new game. (If no winning rounds are specified, the default is 1)
3. In the group, type `/newgame @<otherPlayer> {<winningRounds>}` 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.
8 changes: 4 additions & 4 deletions src/handlers/acceptGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 },
);
}
4 changes: 3 additions & 1 deletion src/handlers/listGames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
Expand Down
19 changes: 15 additions & 4 deletions src/handlers/newGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 },
);
}
15 changes: 9 additions & 6 deletions src/handlers/revengeGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
]);
}
34 changes: 25 additions & 9 deletions src/handlers/rollDice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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: {
Expand All @@ -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 },
);
}
Expand Down
7 changes: 5 additions & 2 deletions src/handlers/scoreBoard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/models/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit b0e9b94

Please sign in to comment.