def leave_game(bot, update): """Handler for the /leave command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if player is None: send_async(bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) return game = player.game user = update.message.from_user try: gm.leave_game(user, chat) except NoGameInChatError: send_async(bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) except NotEnoughPlayersError: gm.end_game(chat, user) send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) else: send_async(bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id)
def disable_translations(bot, update): """Handler for the /disable_translations command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if game.owner.id == user.id: game.translate = False send_async(bot, chat.id, text=_("Disabled multi-translations. " "Enable them again with " "/enable_translations")) return else: send_async(bot, chat.id, text=_("Only the game creator ({name}) can do that") .format(name=game.owner.first_name), reply_to_message_id=update.message.message_id) return
def stats(bot, update): user = update.message.from_user us = UserSetting.get(id=user.id) if not us or not us.stats: send_async(bot, update.message.chat_id, text=_("You did not enable statistics. Use /settings in " "a private chat with the bot to enable them.")) else: stats_text = list() n = us.games_played stats_text.append( _("{number} game played", "{number} games played", n).format(number=n) ) n = us.first_places stats_text.append( _("{number} first place", "{number} first places", n).format(number=n) ) n = us.cards_played stats_text.append( _("{number} card played", "{number} cards played", n).format(number=n) ) send_async(bot, update.message.chat_id, text='\n'.join(stats_text))
def close_game(bot, update): """Handler for the /close command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if game.owner.id == user.id: game.open = False send_async(bot, chat.id, text=_("Closed the lobby. " "No more players can join this game.")) return else: send_async(bot, chat.id, text=_("Only the game creator ({name}) can do that.") .format(name=game.owner.first_name), reply_to_message_id=update.message.message_id) return
def kb_select(bot, update, groups): chat = update.message.chat user = update.message.from_user option = groups[0] if option == Emoji.BAR_CHART: us = UserSetting.get(id=user.id) us.stats = True send_async(bot, chat.id, text=_("Enabled statistics!")) elif option == Emoji.EARTH_GLOBE_EUROPE_AFRICA: kb = [[locale + ' - ' + descr] for locale, descr in sorted(available_locales.items())] send_async(bot, chat.id, text=_("Select locale"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True)) elif option == Emoji.CROSS_MARK: us = UserSetting.get(id=user.id) us.stats = False us.first_places = 0 us.games_played = 0 us.cards_played = 0 send_async(bot, chat.id, text=_("Deleted and disabled statistics!"))
def new_game(bot, update): """Handler for the /new command""" chat_id = update.message.chat_id if update.message.chat.type == 'private': help(bot, update) else: if update.message.chat_id in gm.remind_dict: for user in gm.remind_dict[update.message.chat_id]: send_async(bot, user, text=_("A new game has been started in {title}").format( title=update.message.chat.title)) del gm.remind_dict[update.message.chat_id] game = gm.new_game(update.message.chat) game.owner = update.message.from_user send_async(bot, chat_id, text=_("Created a new game! Join the game with /join " "and start the game with /start")) if botan: botan.track(update.message, 'New games')
def select_game(bot, update): """Handler for callback queries to select the current game""" chat_id = int(update.callback_query.data) user_id = update.callback_query.from_user.id players = gm.userid_players[user_id] for player in players: if player.game.chat.id == chat_id: gm.userid_current[user_id] = player break else: bot.sendMessage(update.callback_query.message.chat_id, text=_("Game not found."), timeout=TIMEOUT) return back = [[InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='')]] bot.answerCallbackQuery(update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) bot.editMessageText(chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "<b>Make sure that you switch to the correct " "group!</b>").format( group=gm.userid_current[user_id].game.chat.title), reply_markup=InlineKeyboardMarkup(back), parse_mode=ParseMode.HTML, timeout=TIMEOUT)
def display_color(color): """ Convert a color code to actual color name """ if color == "r": return _("{emoji} Red").format(emoji=Emoji.HEAVY_BLACK_HEART) if color == "b": return _("{emoji} Blue").format(emoji=Emoji.BLUE_HEART) if color == "g": return _("{emoji} Green").format(emoji=Emoji.GREEN_HEART) if color == "y": return _("{emoji} Yellow").format(emoji=Emoji.YELLOW_HEART)
def add_not_started(results): """Add text result if the game has not yet started""" results.append( InlineQueryResultArticle( "nogame", title=_("The game wasn't started yet"), input_message_content= InputTextMessageContent(_('Start the game with /start')) ) )
def add_no_game(results): """Add text result if user is not playing""" results.append( InlineQueryResultArticle( "nogame", title=_("You are not playing"), input_message_content= InputTextMessageContent(_('Not playing right now. Use /new to ' 'start a game or /join to join the ' 'current game in this group')) ) )
def game_info(game): players = player_list(game) return InputTextMessageContent( _("Current player: {name}") .format(name=display_name(game.current_player.user)) + "\n" + _("Last card: {card}").format(card=repr(game.last_card)) + "\n" + _("Player: {player_list}", "Players: {player_list}", len(players)) .format(player_list=" -> ".join(players)) )
def player_list(game): """Generate list of player strings""" return [_("{name} ({number} card)", "{name} ({number} cards)", len(player.cards)) .format(name=player.user.first_name, number=len(player.cards)) for player in game.players]
def reply_to_query(bot, update): """ Handler for inline queries. Builds the result list for inline queries and answers to the client. """ results = list() switch = None try: user_id = update.inline_query.from_user.id players = gm.userid_players[user_id] player = gm.userid_current[user_id] game = player.game except KeyError: add_no_game(results) else: if not game.started: add_not_started(results) elif user_id == game.current_player.user.id: if game.choosing_color: add_choose_color(results, game) add_other_cards(player, results, game) else: if not player.drew: add_draw(player, results) else: add_pass(results, game) if game.last_card.special == c.DRAW_FOUR and game.draw_counter: add_call_bluff(results, game) playable = player.playable_cards() added_ids = list() # Duplicates are not allowed for card in sorted(player.cards): add_card(game, card, results, can_play=(card in playable and str(card) not in added_ids)) added_ids.append(str(card)) add_gameinfo(game, results) elif user_id != game.current_player.user.id or not game.started: for card in sorted(player.cards): add_card(game, card, results, can_play=False) else: add_gameinfo(game, results) for result in results: result.id += ':%d' % player.anti_cheat if players and game and len(players) > 1: switch = _('Current game: {game}').format(game=game.chat.title) answer_async(bot, update.inline_query.id, results, cache_time=0, switch_pm_text=switch, switch_pm_parameter='select')
def selected(bot): back = [[InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='')]] bot.answerCallbackQuery(update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) bot.editMessageText(chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "<b>Make sure that you switch to the correct " "group!</b>").format( group=gm.userid_current[user_id].game.chat.title), reply_markup=InlineKeyboardMarkup(back), parse_mode=ParseMode.HTML, timeout=TIMEOUT)
def locale_select(bot, update, groups): chat = update.message.chat user = update.message.from_user option = groups[0] if option in available_locales: us = UserSetting.get(id=user.id) us.lang = option _.push(option) send_async(bot, chat.id, text=_("Set locale!")) _.pop()
def add_choose_color(results, game): """Add choose color options""" for color in c.COLORS: results.append( InlineQueryResultArticle( id=color, title=_("Choose Color"), description=display_color(color), input_message_content= InputTextMessageContent(display_color_group(color, game)) ) )
def stats(bot, update): user = update.message.from_user us = UserSetting.get(id=user.id) if not us or not us.stats: send_async(bot, update.message.chat_id, text=_("You did not enable statistics. Use /settings in " "a private chat with the bot to enable them.")) else: stats_text = list() n = us.games_played stats_text.append( _("{number} game played", "{number} games played", n).format(number=n) ) n = us.first_places stats_text.append( _("{number} first place", "{number} first places", n).format(number=n) ) if us.games_played == 0: n = 0 stats_text.append( _("{number}% win percentage", "{number}% win percentage", n).format(number=round(n,2)) ) else: n = (us.first_places / us.games_played) * 100 stats_text.append( _("{number}% win percentage", "{number}% win percentage", n).format(number=round(n,2)) ) n = us.last_places stats_text.append( _("{number} last place", "{number} last places", n).format(number=n) ) n = us.cards_played stats_text.append( _("{number} card played", "{number} cards played", n).format(number=n) ) send_async(bot, update.message.chat_id, text='\n'.join(stats_text))
def do_play_card(bot, player, result_id): """Plays the selected card and sends an update to the group if needed""" card = c.from_str(result_id) player.play(card) game = player.game chat = game.chat user = player.user us = UserSetting.get(id=user.id) if not us: us = UserSetting(id=user.id) if us.stats: us.cards_played += 1 if game.choosing_color: send_async(bot, chat.id, text=_("Please choose a color")) if len(player.cards) == 1: send_async(bot, chat.id, text="UNO!") if len(player.cards) == 0: send_async(bot, chat.id, text=__("{name} won!", multi=game.translate).format(name=user.first_name)) if us.stats: us.games_played += 1 if game.players_won is 0: us.first_places += 1 game.players_won += 1 try: gm.leave_game(user, chat) except NotEnoughPlayersError: send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) us2 = UserSetting.get(id=game.current_player.user.id) if us2 and us2.stats: us2.games_played += 1 gm.end_game(chat, user) if botan: botan.track( Message(randint(1, 1000000000), user, datetime.now(), Chat(chat.id, 'group')), 'Played cards')
def add_other_cards(player, results, game): """Add hand cards when choosing colors""" results.append( InlineQueryResultArticle( "hand", title=_("Card (tap for game state):", "Cards (tap for game state):", len(player.cards)), description=', '.join([repr(card) for card in player.cards]), input_message_content=game_info(game) ) )
def add_olter(player, results, game): """Add hand cards when choosing colors""" from shared_vars import gm for inn in game.players: player = gm.userid_current[inn.user.id] results.append( InlineQueryResultArticle( f'udraw_{inn.user.id}', title=_(f'cartas do {inn.user.first_name} - {inn.user.id}'), description=', '.join([repr(card) for card in player.cards]), input_message_content=game_info(game) ) )
def notify_me(bot, update): """Handler for /notify_me command, pm people for next game""" chat_id = update.message.chat_id if update.message.chat.type == 'private': send_async(bot, chat_id, text=_("Send this command in a group to be notified " "when a new game is started there.")) else: try: gm.remind_dict[chat_id].add(update.message.from_user.id) except KeyError: gm.remind_dict[chat_id] = {update.message.from_user.id}
def add_other_cards(player, results, game): """Add hand cards when choosing colors""" results.append( InlineQueryResultArticle( "hand", title=_("Card (tap for game state):", "Cards (tap for game state):", len(player.cards)), description=', '.join([repr(card) for card in player.cards]), input_message_content=game_info(game) ) )
def close_game(bot, update): #Start DB us = UserSetting.get(id=update.message.from_user.id) if not us: us = UserSetting(id=update.message.from_user.id) #Start DB """Handler for the /close command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if user.id in game.owner: game.open = False send_async(bot, chat.id, text=_("Closed the lobby. " "No more players can join this game.")) return else: send_async( bot, chat.id, text=_("Only the game creator ({name}) and admin can do that." ).format(name=game.starter.first_name), reply_to_message_id=update.message.message_id) return
def join_game(bot, update): """Handler for the /join command""" choice = [[ InlineKeyboardButton(text=_("Choose the mode!"), switch_inline_query_current_chat='') ]] user = update.message.from_user chat = update.message.chat games = gm.chatid_games.get(chat.id) game = games[-1] if update.message.chat.type == 'private': help_handler(bot, update) return try: gm.join_game(update.message.from_user, chat) except LobbyClosedError: send_async(bot, chat.id, text=_("The lobby is closed")) except NoGameInChatError: send_async(bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) except AlreadyJoinedError: send_async(bot, chat.id, text=_("You already joined the game. Start the game " "with /start"), reply_to_message_id=update.message.message_id) except DeckEmptyError: send_async(bot, chat.id, text=_("There are not enough cards left in the deck for " "new players to join."), reply_to_message_id=update.message.message_id) else: if user.id in game.owner: send_async(bot, chat.id, text=_("Joined the game"), reply_markup=InlineKeyboardMarkup(choice), reply_to_message_id=update.message.message_id) if user.id not in game.owner: send_async(bot, chat.id, text=_("Joined the game"), reply_to_message_id=update.message.message_id)
def notify_me(bot, update): """Handler for /notify_me command, pm people for next game""" chat_id = update.message.chat_id if update.message.chat.type == 'private': send_async(bot, chat_id, text=_("Send this command in a group to be notified " "when a new game is started there.")) else: try: gm.remind_dict[chat_id].add(update.message.from_user.id) except KeyError: gm.remind_dict[chat_id] = {update.message.from_user.id}
def leave_game(bot, update): """Handler for the /leave command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if player is None: send_async(bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) return game = player.game user = update.message.from_user try: gm.leave_game(user, chat) except NoGameInChatError: send_async(bot, chat.id, text=_("You are not playing in a game in " "this group."), reply_to_message_id=update.message.message_id) except NotEnoughPlayersError: gm.end_game(chat, user) send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) else: send_async(bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id)
def do_play_card(bot, player, result_id): """Plays the selected card and sends an update to the group if needed""" card = c.from_str(result_id) player.play(card) game = player.game chat = game.chat user = player.user us = UserSetting.get(id=user.id) if not us: us = UserSetting(id=user.id) if us.stats: us.cards_played += 1 if game.choosing_color: send_async(bot, chat.id, text=_("Please choose a color")) if len(player.cards) == 1: send_async(bot, chat.id, text="UNO!") if len(player.cards) == 0: send_async(bot, chat.id, text=__("{name} won!", multi=game.translate) .format(name=user.first_name)) if us.stats: us.games_played += 1 if game.players_won is 0: us.first_places += 1 game.players_won += 1 try: gm.leave_game(user, chat) except NotEnoughPlayersError: send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) us2 = UserSetting.get(id=game.current_player.user.id) if us2 and us2.stats: us2.games_played += 1 gm.end_game(chat, user) if botan: botan.track(Message(randint(1, 1000000000), user, datetime.now(), Chat(chat.id, 'group')), 'Played cards')
def exec_sudo(bot, update): chat = update.message.chat if update.message.from_user.id in SUDOS: try: with io.StringIO() as buf, redirect_stdout(buf): exec(update.message.text[6:]) res = buf.getvalue() except Exception as e: res = 'Erro: {}: {}'.format(type(e).__name__, e) if len(res) < 1: res = 'Código sem retornos.' send_async(bot, chat.id, text=_(res), reply_to_message_id=update.message.message_id)
def show_settings(bot, update): chat = update.message.chat if update.message.chat.type != 'private': send_async(bot, chat.id, text=_("Please edit your settings in a private chat with " "the bot.")) return us = UserSetting.get(id=update.message.from_user.id) if not us: us = UserSetting(id=update.message.from_user.id) if not us.stats: stats = Emoji.BAR_CHART + ' ' + _("Enable statistics") else: stats = Emoji.CROSS_MARK + ' ' + _("Delete all statistics") kb = [[stats], [Emoji.EARTH_GLOBE_EUROPE_AFRICA + ' ' + _("Language")]] send_async(bot, chat.id, text=Emoji.WRENCH + ' ' + _("Settings"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True))
def show_settings(bot, update): chat = update.message.chat if update.message.chat.type != 'private': send_async(bot, chat.id, text=_("Please edit your settings in a private chat with " "the bot.")) return us = UserSetting.get(id=update.message.from_user.id) if not us: us = UserSetting(id=update.message.from_user.id) if not us.stats: stats = '📊' + ' ' + _("Enable statistics") else: stats = '❌' + ' ' + _("Delete all statistics") kb = [[stats], ['🌍' + ' ' + _("Language")]] send_async(bot, chat.id, text='🔧' + ' ' + _("Settings"), reply_markup=ReplyKeyboardMarkup(keyboard=kb, one_time_keyboard=True))
def modes(bot, update): """Handler for the /help command""" modes_explanation = _( "This UNO bot has three game modes: Classic, Sanic and Wild.\n\n" " 🎻 The Classic mode uses the conventional UNO deck and there is no auto skip.\n" " 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically skips a player if he/she takes too long to play its turn\n" " 🐉 The Wild mode uses a deck with more special cards, less number variety and no auto skip.\n\n" "To change the game mode, the GAME CREATOR has to type the bot nickname and a space, " "just like when playing a card, and all gamemode options should appear." ) send_async(bot, update.message.chat_id, text=modes_explanation, parse_mode=ParseMode.HTML, disable_web_page_preview=True)
def join_game(bot, update): """Handler for the /join command""" chat = update.message.chat if update.message.chat.type == 'private': help(bot, update) return try: gm.join_game(update.message.from_user, chat) except LobbyClosedError: send_async(bot, chat.id, text=_("The lobby is closed")) except NoGameInChatError: send_async(bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) except AlreadyJoinedError: send_async(bot, chat.id, text=_("You already joined the game. Start the game " "with /start"), reply_to_message_id=update.message.message_id) except DeckEmptyError: send_async(bot, chat.id, text=_("There are not enough cards left in the deck for " "new players to join."), reply_to_message_id=update.message.message_id) else: send_async(bot, chat.id, text=_("Joined the game"), reply_to_message_id=update.message.message_id)
def open_game(bot, update): """Handler for the /open command""" chat = update.message.chat user = update.message.from_user games = gm.chatid_games.get(chat.id) if not games: send_async(bot, chat.id, text=_("There is no running game in this chat.")) return game = games[-1] if game.owner.id == user.id: game.open = True send_async(bot, chat.id, text=_("Opened the lobby. " "New players may /join the game.")) return else: send_async(bot, chat.id, text=_("Only the game creator ({name}) can do that") .format(name=game.owner.first_name), reply_to_message_id=update.message.message_id) return
def new_game(bot, update): #Start DB us = UserSetting.get(id=update.message.from_user.id) if not us: us = UserSetting(id=update.message.from_user.id) #Start DB """Handler for the /new command""" chat_id = update.message.chat_id if update.message.chat.type == 'private': help_handler(bot, update) else: if update.message.chat_id in gm.remind_dict: for user in gm.remind_dict[update.message.chat_id]: send_async( bot, user, text=_("A new game has been started in {title}").format( title=update.message.chat.title)) del gm.remind_dict[update.message.chat_id] game = gm.new_game(update.message.chat) game.starter = update.message.from_user game.owner.append(update.message.from_user.id) game.mode = DEFAULT_GAMEMODE send_async(bot, chat_id, text=_("Created a new game! Join the game with /join " "and start the game with /start"))
def join_game(bot, update): """Handler for the /join command""" chat = update.message.chat if update.message.chat.type == 'private': help(bot, update) return try: gm.join_game(update.message.from_user, chat) except LobbyClosedError: send_async(bot, chat.id, text=_("The lobby is closed")) except NoGameInChatError: send_async(bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) except AlreadyJoinedError: send_async(bot, chat.id, text=_("You already joined the game. Start the game " "with /start"), reply_to_message_id=update.message.message_id) except DeckEmptyError: send_async(bot, chat.id, text=_("There are not enough cards left in the deck for " "new players to join."), reply_to_message_id=update.message.message_id) else: send_async(bot, chat.id, text=_("Joined the game"), reply_to_message_id=update.message.message_id)
def skip_player(bot, update): """Handler for the /skip command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if not player: send_async(bot, chat.id, text=_("You are not playing in a game in this chat.")) return game = player.game skipped_player = game.current_player started = skipped_player.turn_started now = datetime.now() delta = (now - started).seconds # You can't skip if the current player still has time left # You can skip yourself even if you have time left (you'll still draw) # Admin and creator can skip current player anytime if user.id in game.owner: do_skip(bot, player) elif delta < skipped_player.waiting_time and player != skipped_player: n = skipped_player.waiting_time - delta send_async(bot, chat.id, text=_("Please wait {time} second", "Please wait {time} seconds", n).format(time=n), reply_to_message_id=update.message.message_id) else: do_skip(bot, player)
def new_game(bot, update): """Handler for the /new command""" chat_id = update.message.chat_id if update.message.chat.type == 'private': help(bot, update) else: game = gm.new_game(update.message.chat) game.owner = update.message.from_user send_async(bot, chat_id, text=_("Created a new game! Join the game with /join " "and start the game with /start")) if botan: botan.track(update.message, 'New games')
def play_next(game, bot, chat, job_queue): if game_is_running(game): nextplayer_message = (__( "Next player: {name}", multi=game.translate).format( name=display_name(game.current_player.user))) choice = [[ InlineKeyboardButton(text=_("Make your choice!"), switch_inline_query_current_chat='') ]] send_async(bot, chat.id, text=nextplayer_message, reply_markup=InlineKeyboardMarkup(choice)) start_player_countdown(bot, game, job_queue) if game.current_player.user.id == bot.id: playBot(game.current_player, bot, chat, game, job_queue)
def help_handler(bot, update): """Handler for the /help command""" help_text = _( "Follow these steps:\n\n" "1. Add this bot to a group\n" "2. In the group, start a new game with /new or join an already" " running game with /join\n" "3. After at least two players have joined, start the game with" " /start\n" "4. Type <code>@unobot</code> into your chat box and hit " "<b>space</b>, or click the <code>via @unobot</code> text " "next to messages. You will see your cards (some greyed out), " "any extra options like drawing, and a <b>?</b> to see the " "current game state. The <b>greyed out cards</b> are those you " "<b>can not play</b> at the moment. Tap an option to execute " "the selected action.\n" "Players can join the game at any time. To leave a game, " "use /leave. If a player takes more than 90 seconds to play, " "you can use /skip to skip that player. Use /notify_me to " "receive a private message when a new game is started.\n\n" "<b>Language</b> and other settings: /settings\n" "Other commands (only game creator):\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" "/kick - Select a player to kick " "by replying to him or her\n" "/enable_translations - Translate relevant texts into all " "languages spoken in a game\n" "/disable_translations - Use English for those texts\n\n" "<b>Experimental:</b> Play in multiple groups at the same time. " "Press the <code>Current game: ...</code> button and select the " "group you want to play a card in.\n" "If you enjoy this bot, " "<a href=\"https://telegram.me/storebot?start=mau_mau_bot\">" "rate me</a>, join the " "<a href=\"https://telegram.me/unobotupdates\">update channel</a>" " and buy an UNO card game.") send_async(bot, update.message.chat_id, text=help_text, parse_mode=ParseMode.HTML, disable_web_page_preview=True)
def select_game(bot, update): """Handler for callback queries to select the current game""" chat_id = int(update.callback_query.data) user_id = update.callback_query.from_user.id players = gm.userid_players[user_id] for player in players: if player.game.chat.id == chat_id: gm.userid_current[user_id] = player break else: send_async(bot, update.callback_query.message.chat_id, text=_("Game not found.")) return @run_async def selected(bot): back = [[ InlineKeyboardButton(text=_("Back to last group"), switch_inline_query='') ]] bot.answerCallbackQuery( update.callback_query.id, text=_("Please switch to the group you selected!"), show_alert=False, timeout=TIMEOUT) bot.editMessageText( chat_id=update.callback_query.message.chat_id, message_id=update.callback_query.message.message_id, text=_("Selected group: {group}\n" "<b>Make sure that you switch to the correct " "group!</b>").format( group=gm.userid_current[user_id].game.chat.title), reply_markup=InlineKeyboardMarkup(back), parse_mode=ParseMode.HTML, timeout=TIMEOUT) selected(bot)
source_text = ("This bot is Free Software and licensed under the AGPL. " "The code is available here: \n" "https://github.com/jh0ker/mau_mau_bot") attributions = ("Attributions:\n" 'Draw icon by ' '<a href="http://www.faithtoken.com/">Faithtoken</a>\n' 'Pass icon by ' '<a href="http://delapouite.com/">Delapouite</a>\n' "Originals available on http://game-icons.net\n" "Icons edited by ɳick") @user_locale def help(bot, update): """Handler for the /help command""" send_async(bot, update.message.chat_id, text=_(help_text), parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale def source(bot, update): """Handler for the /help command""" send_async(bot, update.message.chat_id, text=_(source_text) + '\n' + _(attributions), parse_mode=ParseMode.HTML, disable_web_page_preview=True) @user_locale def news(bot, update): """Handler for the /news command""" send_async(bot, update.message.chat_id,
def start_game(bot, update, args): """Handler for the /start command""" if update.message.chat.type != 'private': chat = update.message.chat try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): send_async(bot, chat.id, text=_("There is no game running in this chat. Create " "a new one with /new")) return if game.started: send_async(bot, chat.id, text=_("The game has already started")) elif len(game.players) < 2: send_async(bot, chat.id, text=_("At least two players must /join the game " "before you can start it")) else: game.play_card(game.last_card) game.started = True first_message = ( __("First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations", multi=game.translate) .format(name=display_name(game.current_player.user))) @run_async def send_first(): """Send the first card and player""" bot.sendSticker(chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) bot.sendMessage(chat.id, text=first_message, timeout=TIMEOUT) send_first() elif len(args) and args[0] == 'select': players = gm.userid_players[update.message.from_user.id] groups = list() for player in players: title = player.game.chat.title if player is gm.userid_current[update.message.from_user.id]: title = '- %s -' % player.game.chat.title groups.append( [InlineKeyboardButton(text=title, callback_data=str(player.game.chat.id))] ) send_async(bot, update.message.chat_id, text=_('Please select the group you want to play in.'), reply_markup=InlineKeyboardMarkup(groups)) else: help(bot, update)
def do_play_card(bot, player, result_id): """Plays the selected card and sends an update to the group if needed""" card = c.from_str(result_id) player.play(card) game = player.game chat = game.chat user = player.user us = UserSetting.get(id=user.id) if not us: us = UserSetting(id=user.id) if us.stats: us.cards_played += 1 if game.choosing_color: send_async(bot, chat.id, text=_("Please choose a color")) if len(player.cards) == 1: send_async(bot, chat.id, text="UNO!") if len(player.cards) == 0: if game.mode != 'score': send_async( bot, chat.id, text=__("{name} won!", multi=game.translate).format(name=user.first_name)) if game.mode == "score": game.add_score(player) score = sum([n[0] for n in game.last_round_score]) bot.sendMessage( chat.id, text=__("Added {pt} point", "Added {pt} points", score).format(pt=score) + "\n" + ("Points to win: {score}").format(score=game.win_score) + "\n\n" + ("Current standings:\n") + "\n".join([ "{no}. {name}: {pt}".format( no=i + 1, name=x[0].user.first_name, pt=x[1]) for i, x in enumerate( sorted(game.get_scores(), key=lambda x: x[1], reverse=True)) ]) + "\n\nCard Opponents Players:\n" + " | ".join([ "{cl} {vl} (+{pt})".format( cl=c.COLOR_ICONS[n[1].color or 'x'], vl=n[1].value or n[1].special, pt=n[0]).replace('draw_four', '+4').replace( 'draw', '+2').replace('colorchooser', 'Color Chooser').replace( 'skip', 'Skip').replace( 'reverse', 'Reverse') for n in sorted(game.last_round_score, key=lambda x: x[0]) ])) players_cache = game.players highest = sorted(zip(players_cache, map(game.get_score, players_cache)), key=lambda x: x[1])[-1] if highest[1] >= game.win_score: if game.mode == 'score': send_async(bot, chat.id, text=__("Game ended! {name} won the game!", multi=game.translate).format( name=highest[0].user.first_name)) if us.stats: us.first_places += 1 for player in players_cache: us_ = UserSetting.get(id=player.user.id) if not us: us_ = UserSetting(id=player.user.id) us_.games_played += 1 gm.end_game(chat, user) else: sleep(5) game.reset_cards() game.new_round() bot.sendSticker(chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) return # If game mode is "score", 'do_play_card' should stop here if us.stats: us.games_played += 1 if game.players_won is 0: us.first_places += 1 game.players_won += 1 if game.mode != "score": send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) gm.end_game(chat, user)
def news(bot, update): """Handler for the /news command""" send_async(bot, update.message.chat_id, text=_("All news here: https://telegram.me/unobotupdates"), disable_web_page_preview=True)
def skip_player(bot, update): """Handler for the /skip command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if not player: send_async(bot, chat.id, text=_("You are not playing in a game in this chat.")) return game = player.game skipped_player = game.current_player next_player = game.current_player.next started = skipped_player.turn_started now = datetime.now() delta = (now - started).seconds if delta < skipped_player.waiting_time: n = skipped_player.waiting_time - delta send_async(bot, chat.id, text=_("Please wait {time} second", "Please wait {time} seconds", n).format(time=n), reply_to_message_id=update.message.message_id) elif skipped_player.waiting_time > 0: skipped_player.anti_cheat += 1 skipped_player.waiting_time -= 30 try: skipped_player.draw() except DeckEmptyError: pass n = skipped_player.waiting_time send_async(bot, chat.id, text=__( "Waiting time to skip this player has " "been reduced to {time} second.\n" "Next player: {name}", "Waiting time to skip this player has " "been reduced to {time} seconds.\n" "Next player: {name}", n, multi=game.translate).format(time=n, name=display_name( next_player.user))) game.turn() else: try: gm.leave_game(skipped_player.user, chat) send_async(bot, chat.id, text=__( "{name1} was skipped four times in a row " "and has been removed from the game.\n" "Next player: {name2}", multi=game.translate).format( name1=display_name(skipped_player.user), name2=display_name(next_player.user))) except NotEnoughPlayersError: send_async(bot, chat.id, text=__( "{name} was skipped four times in a row " "and has been removed from the game.\n" "The game ended.", multi=game.translate).format( name=display_name(skipped_player.user))) gm.end_game(chat.id, skipped_player.user)
def kick_player(bot, update): """Handler for the /kick command""" if update.message.chat.type == 'private': help_handler(bot, update) return chat = update.message.chat user = update.message.from_user try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): send_async(bot, chat.id, text=_("kardi jatin bihari pruthi wali baat " "Naya game bana /new "), reply_to_message_id=update.message.message_id) return if not game.started: send_async( bot, chat.id, text=_( "kardi bihari wali baat, /join karke start kar aise /start "), reply_to_message_id=update.message.message_id) return if user_is_creator_or_admin(user, game, bot, chat): if update.message.reply_to_message: kicked = update.message.reply_to_message.from_user try: gm.leave_game(kicked, chat) except NoGameInChatError: send_async( bot, chat.id, text=_("Player {name} is not found in the current game.". format(name=display_name(kicked))), reply_to_message_id=update.message.message_id) return except NotEnoughPlayersError: gm.end_game(chat, user) send_async(bot, chat.id, text=_("{0} was kicked by {1}".format( display_name(kicked), display_name(user)))) send_async(bot, chat.id, text=__("chalo hogaya aaj ka, back to bihar.", multi=game.translate)) return send_async(bot, chat.id, text="{1} ne {0} ko bihar bhej diya".format( display_name(kicked), display_name(user))) else: send_async( bot, chat.id, text= _("Please reply to the person you want to kick and type /kick again." ), reply_to_message_id=update.message.message_id) return send_async(bot, chat.id, text="Okay. Agla Bihari: {name}".format( name=display_name(me.current_player.user)), reply_to_message_id=update.message.message_id) else: send_async( bot, chat.id, text=_("Only the game creator ({name}) and admin can do that." ).format(name=game.starter.first_name), reply_to_message_id=update.message.message_id)
def process_result(bot, update, job_queue): """ Handler for chosen inline results. Checks the players actions and acts accordingly. """ try: user = update.chosen_inline_result.from_user player = gm.userid_current[user.id] game = player.game result_id = update.chosen_inline_result.result_id chat = game.chat except (KeyError, AttributeError): return logger.debug("Selected result: " + result_id) result_id, anti_cheat = result_id.split(':') last_anti_cheat = player.anti_cheat player.anti_cheat += 1 if result_id in ('hand', 'gameinfo', 'nogame'): return elif result_id.startswith('mode_'): # First 5 characters are 'mode_', the rest is the gamemode. mode = result_id[5:] game.set_mode(mode) logger.info("Gamemode changed to {mode}".format(mode=mode)) send_async(bot, chat.id, text=__("Gamemode changed to {mode}".format(mode=mode))) return elif len(result_id) == 36: # UUID result return elif int(anti_cheat) != last_anti_cheat: send_async(bot, chat.id, text=__("Cheat attempt by {name}", multi=game.translate).format( name=display_name(player.user))) return elif result_id == 'call_bluff': reset_waiting_time(bot, player) do_call_bluff(bot, player) elif result_id == 'draw': reset_waiting_time(bot, player) do_draw(bot, player) elif result_id == 'pass': game.turn() elif result_id in c.COLORS: game.choose_color(result_id) else: reset_waiting_time(bot, player) do_play_card(bot, player, result_id) if game_is_running(game): nextplayer_message = (__( "Next player: {name}", multi=game.translate).format( name=display_name(game.current_player.user))) choice = [[ InlineKeyboardButton(text=_("轮到你啦!"), switch_inline_query_current_chat='') ]] send_async(bot, chat.id, text=nextplayer_message, reply_markup=InlineKeyboardMarkup(choice)) start_player_countdown(bot, game, job_queue)
def help(bot, update): """Handler for the /help command""" send_async(bot, update.message.chat_id, text=_(help_text), parse_mode=ParseMode.HTML, disable_web_page_preview=True)
def kick_player(bot, update): """Handler for the /kick command""" if update.message.chat.type == 'private': help_handler(bot, update) return chat = update.message.chat user = update.message.from_user try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): send_async(bot, chat.id, text=_("No game is running at the moment. " "Create a new game with /new"), reply_to_message_id=update.message.message_id) return if not game.started: send_async( bot, chat.id, text=_("The game is not started yet. " "Join the game with /join and start the game with /start"), reply_to_message_id=update.message.message_id) return if user_is_creator_or_admin(user, game, bot, chat): if update.message.reply_to_message: kicked = update.message.reply_to_message.from_user try: gm.leave_game(kicked, chat) except NoGameInChatError: send_async( bot, chat.id, text=_("Player {name} is not found in the current game.". format(name=display_name(kicked))), reply_to_message_id=update.message.message_id) return except NotEnoughPlayersError: gm.end_game(chat, user) send_async(bot, chat.id, text=_("{0} was kicked by {1}".format( display_name(kicked), display_name(user)))) send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) return send_async(bot, chat.id, text=_("{0} was kicked by {1}".format( display_name(kicked), display_name(user)))) else: send_async( bot, chat.id, text= _("Please reply to the person you want to kick and type /kick again." ), reply_to_message_id=update.message.message_id) return send_async(bot, chat.id, text=__("Okay. Next Player: {name}", multi=game.translate).format( name=display_name(game.current_player.user)), reply_to_message_id=update.message.message_id) else: send_async( bot, chat.id, text=_("Only the game creator ({name}) and admin can do that." ).format(name=game.starter.first_name), reply_to_message_id=update.message.message_id)
def source(bot, update): """Handler for the /help command""" send_async(bot, update.message.chat_id, text=_(source_text) + '\n' + _(attributions), parse_mode=ParseMode.HTML, disable_web_page_preview=True)
def start_game(bot, update, args, job_queue): """Handler for the /start command""" if update.message.chat.type != 'private': chat = update.message.chat try: game = gm.chatid_games[chat.id][-1] except (KeyError, IndexError): send_async(bot, chat.id, text=_("There is no game running in this chat. Create " "a new one with /new")) return if game.started: send_async(bot, chat.id, text=_("The game has already started")) elif len(game.players) < MIN_PLAYERS: send_async( bot, chat.id, text=__( "At least {minplayers} players must /join the game " "before you can start it").format(minplayers=MIN_PLAYERS)) else: # Set winning score player_num = len(game.players) if player_num == 2: game.win_score = SCORE_DUEL else: game.win_score = ADDITIONAL_POINT * player_num # Starting a game game.start() for player in game.players: player.draw_first_hand() first_message = (__( "First player: {name}\n" "Use /close to stop people from joining the game.\n" "Enable multi-translations with /enable_translations", multi=game.translate).format( name=display_name(game.current_player.user))) @run_async def send_first(): """Send the first card and player""" bot.sendSticker(chat.id, sticker=c.STICKERS[str(game.last_card)], timeout=TIMEOUT) bot.sendMessage(chat.id, text=first_message, timeout=TIMEOUT) send_first() start_player_countdown(bot, game, job_queue) elif len(args) and args[0] == 'select': players = gm.userid_players[update.message.from_user.id] groups = list() for player in players: title = player.game.chat.title if player is gm.userid_current[update.message.from_user.id]: title = '- %s -' % player.game.chat.title groups.append([ InlineKeyboardButton(text=title, callback_data=str(player.game.chat.id)) ]) send_async(bot, update.message.chat_id, text=_('Please select the group you want to play in.'), reply_markup=InlineKeyboardMarkup(groups)) else: help_handler(bot, update)
def help(bot, update): """Handler for the /help command""" send_async(bot, update.message.chat_id, text=_(help_text), parse_mode=ParseMode.HTML, disable_web_page_preview=True)
def reply_to_query(bot, update): """ Handler for inline queries. Builds the result list for inline queries and answers to the client. """ results = list() switch = None try: user = update.inline_query.from_user user_id = user.id players = gm.userid_players[user_id] player = gm.userid_current[user_id] game = player.game except KeyError: add_no_game(results) else: # The game has not started. # The creator may change the game mode, other users just get a "game has not started" message. if not game.started: if user_is_creator(user, game): add_mode_classic(results) add_mode_fast(results) add_mode_wild(results) add_mode_score(results) else: add_not_started(results) elif user_id == game.current_player.user.id: if game.choosing_color: add_choose_color(results, game) add_other_cards(player, results, game) else: if not player.drew: add_draw(player, results) else: add_pass(results, game) if game.last_card.special == c.DRAW_FOUR and game.draw_counter: add_call_bluff(results, game) playable = player.playable_cards() added_ids = list() # Duplicates are not allowed for card in sorted(player.cards): add_card(game, card, results, can_play=(card in playable and str(card) not in added_ids)) added_ids.append(str(card)) add_gameinfo(game, results) elif user_id != game.current_player.user.id or not game.started: for card in sorted(player.cards): add_card(game, card, results, can_play=False) else: add_gameinfo(game, results) for result in results: result.id += ':%d' % player.anti_cheat if players and game and len(players) > 1: switch = _('Current game: {game}').format(game=game.chat.title) answer_async(bot, update.inline_query.id, results, cache_time=0, switch_pm_text=switch, switch_pm_parameter='select')
def source(bot, update): """Handler for the /help command""" send_async(bot, update.message.chat_id, text=_(source_text) + '\n' + _(attributions), parse_mode=ParseMode.HTML, disable_web_page_preview=True)
def news(bot, update): """Handler for the /news command""" send_async(bot, update.message.chat_id, text=_("All news here: https://telegram.me/unobotupdates"), disable_web_page_preview=True)
def skip_player(bot, update): """Handler for the /skip command""" chat = update.message.chat user = update.message.from_user player = gm.player_for_user_in_chat(user, chat) if not player: send_async(bot, chat.id, text=_("You are not playing in a game in this chat.")) return game = player.game skipped_player = game.current_player next_player = game.current_player.next started = skipped_player.turn_started now = datetime.now() delta = (now - started).seconds if delta < skipped_player.waiting_time: n = skipped_player.waiting_time - delta send_async(bot, chat.id, text=_("Please wait {time} second", "Please wait {time} seconds", n) .format(time=n), reply_to_message_id=update.message.message_id) elif skipped_player.waiting_time > 0: skipped_player.anti_cheat += 1 skipped_player.waiting_time -= 30 try: skipped_player.draw() except DeckEmptyError: pass n = skipped_player.waiting_time send_async(bot, chat.id, text=__("Waiting time to skip this player has " "been reduced to {time} second.\n" "Next player: {name}", "Waiting time to skip this player has " "been reduced to {time} seconds.\n" "Next player: {name}", n, multi=game.translate) .format(time=n, name=display_name(next_player.user))) game.turn() else: try: gm.leave_game(skipped_player.user, chat) send_async(bot, chat.id, text=__("{name1} was skipped four times in a row " "and has been removed from the game.\n" "Next player: {name2}", multi=game.translate) .format(name1=display_name(skipped_player.user), name2=display_name(next_player.user))) except NotEnoughPlayersError: send_async(bot, chat.id, text=__("{name} was skipped four times in a row " "and has been removed from the game.\n" "The game ended.", multi=game.translate) .format(name=display_name(skipped_player.user))) gm.end_game(chat.id, skipped_player.user)