diff --git a/bot.py b/bot.py index 8680883..eedcf00 100644 --- a/bot.py +++ b/bot.py @@ -1,9 +1,10 @@ import logging from datetime import datetime from random import randint +from uuid import uuid4 from telegram import InlineQueryResultArticle, ParseMode, Message, Chat, \ - Emoji, InputTextMessageContent + Emoji, InputTextMessageContent, InlineQueryResultCachedSticker as Sticker from telegram.ext import Updater, InlineQueryHandler, \ ChosenInlineResultHandler, CommandHandler, MessageHandler, filters from telegram.utils.botan import Botan @@ -33,10 +34,11 @@ help_text = "Follow these steps:\n\n" \ "3. After at least two players have joined, start the game with" \ " /start\n" \ "4. Type @mau_mau_bot into your chat box and hit " \ - "space, or click the via @mau_mau_bot text above " \ - "messages. You will see the cards that you can play, any extra " \ - "options like drawing, your other cards (those you can not play " \ - "at the moment) and an option to see the current game state. " \ + "space, or click the via @mau_mau_bot text next to " \ + "messages. You will see your cards (some greyed out), any extra " \ + "options like drawing, and a ? to see the current game " \ + "state. The greyed out cards are those you can not play at the " \ + "moment." \ "Tap an option to execute the selected action. \n\n" \ "Players can join the game at any time, though you currently " \ "can not play more than one game at a time. To leave a game, " \ @@ -169,8 +171,8 @@ def start_game(bot, update): chat_id = update.message.chat_id game = gm.chatid_game[chat_id] - if False and game.current_player is None or \ - False and game.current_player is game.current_player.next: + if game.current_player is None or \ + game.current_player is game.current_player.next: bot.sendMessage(chat_id, text="At least two players must /join " "the game before you can start it") elif game.started: @@ -178,9 +180,8 @@ def start_game(bot, update): else: game.play_card(game.last_card) game.started = True - bot.sendPhoto(chat_id, - photo=game.last_card.get_image_link(), - caption="First Card") + bot.sendSticker(chat_id, + sticker=c.STICKERS[str(game.last_card)]) bot.sendMessage(chat_id, text="First player: " + display_name(game.current_player.user)) @@ -221,14 +222,8 @@ def reply_to_query(bot, update): if game.choosing_color: add_choose_color(results) else: - playable = list(sorted(player.playable_cards())) - - for card in playable: - add_play_card(card, results) - if not player.drew: - add_draw(player, results, - could_play_card=bool(len(playable))) + add_draw(player, results) else: add_pass(results) @@ -236,7 +231,19 @@ def reply_to_query(bot, update): if game.last_card.special == c.DRAW_FOUR and game.draw_counter: add_call_bluff(results) - add_other_cards(playable, player, results, game) + playable = player.playable_cards() + + for card in sorted(player.cards): + add_play_card(game, card, results, + can_play=(card in playable)) + + if False or game.choosing_color: + add_other_cards(playable, player, results, game) + elif user_id != game.current_player.user.id or not game.started: + for card in sorted(player.cards): + add_play_card(game, card, results, can_play=False) + else: + add_gameinfo(game, results) for result in results: result.id += ':%d' % player.anti_cheat @@ -261,19 +268,12 @@ def add_other_cards(playable, player, results, game): if not playable: playable = list() - players = list() - current_player = game.current_player - itplayer = current_player.next - add_player(current_player, players) - - while itplayer is not current_player: - add_player(itplayer, players) - itplayer = itplayer.next + players = player_list(game) results.append( InlineQueryResultArticle( "hand", - title="Not playable (tap for game state):", + title="Cards (tap for game state):", description=', '.join([repr(card) for card in list_subtract(player.cards, playable)]), input_message_content=InputTextMessageContent( @@ -285,6 +285,17 @@ def add_other_cards(playable, player, results, game): ) +def player_list(game): + players = list() + current_player = game.current_player + itplayer = current_player.next + add_player(current_player, players) + while itplayer is not current_player: + add_player(itplayer, players) + itplayer = itplayer.next + return players + + def add_no_game(results): results.append( InlineQueryResultArticle( @@ -309,13 +320,10 @@ def add_not_started(results): ) -def add_draw(player, results, could_play_card): +def add_draw(player, results): results.append( - InlineQueryResultArticle( - "draw", - title=("No suitable cards..." if not could_play_card else - "I don't want to play a card..."), - description="Draw!", + Sticker( + "draw", sticker_file_id=c.STICKERS['option_draw'], input_message_content= InputTextMessageContent('Drawing %d card(s)' % (player.game.draw_counter or 1)) @@ -323,12 +331,26 @@ def add_draw(player, results, could_play_card): ) +def add_gameinfo(game, results): + players = player_list(game) + + results.append( + Sticker( + "gameinfo", + sticker_file_id=c.STICKERS['option_info'], + input_message_content=InputTextMessageContent( + "Current player: " + display_name(game.current_player.user) + + "\n" + + "Last card: " + repr(game.last_card) + "\n" + + "Players: " + " -> ".join(players)) + ) + ) + + def add_pass(results): results.append( - InlineQueryResultArticle( - "pass", - title="Pass", - description="Don't play a card", + Sticker( + "pass", sticker_file_id=c.STICKERS['option_pass'], input_message_content=InputTextMessageContent('Pass') ) ) @@ -336,29 +358,32 @@ def add_pass(results): def add_call_bluff(results): results.append( - InlineQueryResultArticle( + Sticker( "call_bluff", - title="Call their bluff!", - description="Risk it!", + sticker_file_id=c.STICKERS['option_bluff'], input_message_content= InputTextMessageContent("I'm calling your bluff!") ) ) -def add_play_card(card, results): - results.append( - InlineQueryResultArticle(str(card), - title="Play card", - thumb_url=card.get_thumb_link(), - description=repr(card), - input_message_content= - InputTextMessageContent( - ('\xad' - 'Played card ' + repr(card)) - % card.get_image_link(), - parse_mode=ParseMode.HTML)) - ) +def add_play_card(game, card, results, can_play): + players = player_list(game) + + if can_play: + results.append( + Sticker(str(card), sticker_file_id=c.STICKERS[str(card)]) + ) + else: + results.append( + Sticker(str(uuid4()), sticker_file_id=c.STICKERS_GREY[str(card)], + input_message_content=InputTextMessageContent( + "Current player: " + display_name( + game.current_player.user) + + "\n" + + "Last card: " + repr(game.last_card) + "\n" + + "Players: " + " -> ".join(players))) + ) def add_player(itplayer, players): @@ -385,6 +410,8 @@ def process_result(bot, update): if result_id in ('hand', 'gameinfo', 'nogame'): return + elif len(result_id) == 36: # UUID result + return elif int(anti_cheat) != last_anti_cheat: bot.sendMessage(chat_id, text="Cheat attempt by %s" % display_name(player.user)) diff --git a/card.py b/card.py index cf127c5..0252689 100644 --- a/card.py +++ b/card.py @@ -39,10 +39,123 @@ DRAW_FOUR = 'draw_four' SPECIALS = (CHOOSE, DRAW_FOUR) -IMAGE_PATTERN = 'https://raw.githubusercontent.com/jh0ker/mau_mau_bot/' \ - 'master/images/jpg/%s.jpg' -THUMB_PATTERN = 'https://raw.githubusercontent.com/jh0ker/mau_mau_bot/' \ - 'master/images/thumb/%s.jpg' +STICKERS = { + 'b_0': 'BQADBAAD2QEAAl9XmQAB--inQsYcLTsC', + 'b_1': 'BQADBAAD2wEAAl9XmQABBzh4U-rFicEC', + 'b_2': 'BQADBAAD3QEAAl9XmQABo3l6TT0MzKwC', + 'b_3': 'BQADBAAD3wEAAl9XmQAB2y-3TSapRtIC', + 'b_4': 'BQADBAAD4QEAAl9XmQABT6nhOuolqKYC', + 'b_5': 'BQADBAAD4wEAAl9XmQABwRfmekGnpn0C', + 'b_6': 'BQADBAAD5QEAAl9XmQABQITgUsEsqxsC', + 'b_7': 'BQADBAAD5wEAAl9XmQABVhPF6EcfWjEC', + 'b_8': 'BQADBAAD6QEAAl9XmQABP6baig0pIvYC', + 'b_9': 'BQADBAAD6wEAAl9XmQAB0CQdsQs_pXIC', + 'b_draw': 'BQADBAAD7QEAAl9XmQAB00Wii7R3gDUC', + 'b_skip': 'BQADBAAD8QEAAl9XmQAB_RJHYKqlc-wC', + 'b_reverse': 'BQADBAAD7wEAAl9XmQABo7D0B9NUPmYC', + 'g_0': 'BQADBAAD9wEAAl9XmQABb8CaxxsQ-Y8C', + 'g_1': 'BQADBAAD-QEAAl9XmQAB9B6ti_j6UB0C', + 'g_2': 'BQADBAAD-wEAAl9XmQABYpLjOzbRz8EC', + 'g_3': 'BQADBAAD_QEAAl9XmQABKvc2ZCiY-D8C', + 'g_4': 'BQADBAAD_wEAAl9XmQABJB52wzPdHssC', + 'g_5': 'BQADBAADAQIAAl9XmQABp_Ep1I4GA2cC', + 'g_6': 'BQADBAADAwIAAl9XmQABaaMxxa4MihwC', + 'g_7': 'BQADBAADBQIAAl9XmQABv5Q264Crz8gC', + 'g_8': 'BQADBAADBwIAAl9XmQABjMH-X9UHh8sC', + 'g_9': 'BQADBAADCQIAAl9XmQAB26fZ2fW7vM0C', + 'g_draw': 'BQADBAADCwIAAl9XmQAB64jIZrgXrQUC', + 'g_skip': 'BQADBAADDwIAAl9XmQAB17yhhnh46VQC', + 'g_reverse': 'BQADBAADDQIAAl9XmQAB_xcaab0DkegC', + 'r_0': 'BQADBAADEQIAAl9XmQABiUfr1hz-zT8C', + 'r_1': 'BQADBAADEwIAAl9XmQAB5bWfwJGs6Q0C', + 'r_2': 'BQADBAADFQIAAl9XmQABHR4mg9Ifjw0C', + 'r_3': 'BQADBAADFwIAAl9XmQABYBx5O_PG2QIC', + 'r_4': 'BQADBAADGQIAAl9XmQABTQpGrlvet3cC', + 'r_5': 'BQADBAADGwIAAl9XmQABbdLt4gdntBQC', + 'r_6': 'BQADBAADHQIAAl9XmQABqEI274p3lSoC', + 'r_7': 'BQADBAADHwIAAl9XmQABCw8u67Q4EK4C', + 'r_8': 'BQADBAADIQIAAl9XmQAB8iDJmLxp8ogC', + 'r_9': 'BQADBAADIwIAAl9XmQAB_HCAww1kNGYC', + 'r_draw': 'BQADBAADJQIAAl9XmQABuz0OZ4l3k6MC', + 'r_skip': 'BQADBAADKQIAAl9XmQAC2AL5Ok_ULwI', + 'r_reverse': 'BQADBAADJwIAAl9XmQABu2tIeQTpDvUC', + 'y_0': 'BQADBAADKwIAAl9XmQAB_nWoNKe8DOQC', + 'y_1': 'BQADBAADLQIAAl9XmQABVprAGUDKgOQC', + 'y_2': 'BQADBAADLwIAAl9XmQABqyT4_YTm54EC', + 'y_3': 'BQADBAADMQIAAl9XmQABGC-Xxg_N6fIC', + 'y_4': 'BQADBAADMwIAAl9XmQABbc-ZGL8kApAC', + 'y_5': 'BQADBAADNQIAAl9XmQAB67QJZIF6XAcC', + 'y_6': 'BQADBAADNwIAAl9XmQABJg_7XXoITsoC', + 'y_7': 'BQADBAADOQIAAl9XmQABVrd7OcS2k34C', + 'y_8': 'BQADBAADOwIAAl9XmQABRpJSahBWk3EC', + 'y_9': 'BQADBAADPQIAAl9XmQAB9MwJWKLJogYC', + 'y_draw': 'BQADBAADPwIAAl9XmQABaPYK8oYg84cC', + 'y_skip': 'BQADBAADQwIAAl9XmQABO_AZKtxY6IMC', + 'y_reverse': 'BQADBAADQQIAAl9XmQABZdQFahGG6UQC', + 'draw_four': 'BQADBAAD9QEAAl9XmQABVlkSNfhn76cC', + 'colorchooser': 'BQADBAAD8wEAAl9XmQABl9rUOPqx4E4C', + 'option_draw': 'BQADBAADyAIAAl9XmQABpYfYFs0pgCkC', + 'option_pass': 'BQADBAADxgIAAl9XmQABz8c6BNl49S4C', + 'option_bluff': 'BQADBAADygIAAl9XmQABJoLfB9ntI2UC', + 'option_info': 'BQADBAADxAIAAl9XmQABC5v3Z77VLfEC' +} + +STICKERS_GREY = { + 'b_0': 'BQADBAADRQIAAl9XmQAB1IfkQ5xAiK4C', + 'b_1': 'BQADBAADRwIAAl9XmQABbWvhTeKBii4C', + 'b_2': 'BQADBAADSQIAAl9XmQABS1djHgyQokMC', + 'b_3': 'BQADBAADSwIAAl9XmQABwQ6VTbgY-MIC', + 'b_4': 'BQADBAADTQIAAl9XmQABAlKUYha8YccC', + 'b_5': 'BQADBAADTwIAAl9XmQABMvx8xVDnhUEC', + 'b_6': 'BQADBAADUQIAAl9XmQABDEbhP1Zd31kC', + 'b_7': 'BQADBAADUwIAAl9XmQABXb5XQBBaAnIC', + 'b_8': 'BQADBAADVQIAAl9XmQABgL5HRDLvrjgC', + 'b_9': 'BQADBAADVwIAAl9XmQABtO3XDQWZLtYC', + 'b_draw': 'BQADBAADWQIAAl9XmQAB2kk__6_2IhMC', + 'b_skip': 'BQADBAADXQIAAl9XmQABEGJI6CaH3vcC', + 'b_reverse': 'BQADBAADWwIAAl9XmQAB_kZA6UdHXU8C', + 'g_0': 'BQADBAADYwIAAl9XmQABGD5a9oG7Yg4C', + 'g_1': 'BQADBAADZQIAAl9XmQABqwABZHAXZIg0Ag', + 'g_2': 'BQADBAADZwIAAl9XmQABTI3mrEhojRkC', + 'g_3': 'BQADBAADaQIAAl9XmQABVi3rUyzWS3YC', + 'g_4': 'BQADBAADawIAAl9XmQABZIf5ThaXnpUC', + 'g_5': 'BQADBAADbQIAAl9XmQABNndVJSQCenIC', + 'g_6': 'BQADBAADbwIAAl9XmQABpoy1c4ZkrvwC', + 'g_7': 'BQADBAADcQIAAl9XmQABDeaT5fzxwREC', + 'g_8': 'BQADBAADcwIAAl9XmQABLIQ06ZM5NnAC', + 'g_9': 'BQADBAADdQIAAl9XmQABel-mC7eXGsMC', + 'g_draw': 'BQADBAADdwIAAl9XmQABOHEpxSztCf8C', + 'g_skip': 'BQADBAADewIAAl9XmQABDaQdMxjjPsoC', + 'g_reverse': 'BQADBAADeQIAAl9XmQABek1lGz7SJNAC', + 'r_0': 'BQADBAADfQIAAl9XmQABWrxoiXcsg0EC', + 'r_1': 'BQADBAADfwIAAl9XmQABlav-bkgSgRcC', + 'r_2': 'BQADBAADgQIAAl9XmQABDjZkqfJ4AdAC', + 'r_3': 'BQADBAADgwIAAl9XmQABT7lH7VVcy3MC', + 'r_4': 'BQADBAADhQIAAl9XmQAB1arPC5x0LrwC', + 'r_5': 'BQADBAADhwIAAl9XmQABWvs7xkCDldkC', + 'r_6': 'BQADBAADiQIAAl9XmQABjwABH5ZonWn8Ag', + 'r_7': 'BQADBAADiwIAAl9XmQABjekJfm4fBDIC', + 'r_8': 'BQADBAADjQIAAl9XmQABqFjchpsJeEkC', + 'r_9': 'BQADBAADjwIAAl9XmQAB-sKdcgABdNKDAg', + 'r_draw': 'BQADBAADkQIAAl9XmQABtw9RPVDHZOQC', + 'r_skip': 'BQADBAADlQIAAl9XmQABtG2GixCxtX4C', + 'r_reverse': 'BQADBAADkwIAAl9XmQABz2qyEbabnVsC', + 'y_0': 'BQADBAADlwIAAl9XmQABAb3ZwTGS1lMC', + 'y_1': 'BQADBAADmQIAAl9XmQAB9v5qJk9R0x8C', + 'y_2': 'BQADBAADmwIAAl9XmQABCsgpRHC2g-cC', + 'y_3': 'BQADBAADnQIAAl9XmQAB3kLLXCv-qY0C', + 'y_4': 'BQADBAADnwIAAl9XmQAB7R_y-NexNLIC', + 'y_5': 'BQADBAADoQIAAl9XmQABl-7mwsjD-cMC', + 'y_6': 'BQADBAADowIAAl9XmQABwbVsyv2MfPkC', + 'y_7': 'BQADBAADpQIAAl9XmQABoBqC0JsemVwC', + 'y_8': 'BQADBAADpwIAAl9XmQABpkwAAeh9ldlHAg', + 'y_9': 'BQADBAADqQIAAl9XmQABpSBEUfd4IM8C', + 'y_draw': 'BQADBAADqwIAAl9XmQABMt-2zW0VYb4C', + 'y_skip': 'BQADBAADrwIAAl9XmQABIDf-_TuuxtEC', + 'y_reverse': 'BQADBAADrQIAAl9XmQABm9M0Zh-_UwkC', + 'draw_four': 'BQADBAADYQIAAl9XmQAB_HWlvZIscDEC', + 'colorchooser': 'BQADBAADXwIAAl9XmQABY_ksDdMex-wC' +} class Card(object): @@ -77,14 +190,6 @@ class Card(object): """ Needed for sorting the cards """ return str(self) < str(other) - def get_image_link(self): - """ Returns a link to the image of this card """ - return IMAGE_PATTERN % str(self) - - def get_thumb_link(self): - """ Returns a link to the thumbnail-image of this card """ - return THUMB_PATTERN % str(self) - def from_str(string): """ Decode a Card object from a string """