コード例 #1
0
def create_game(update, context):
    """Create a new game instance for the chat of the user"""
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    # Create either a singleplayer or multiplayer game
    if chat.type == "private":
        game_type = BlackJackGame.Type.SINGLEPLAYER
    elif chat.type == "group" or chat.type == "supergroup":
        game_type = BlackJackGame.Type.MULTIPLAYER_GROUP
    else:
        logger.error("Chat type '{}' not supported!".format(chat.type))
        return

    game = BlackJackGame(gametype=game_type)
    game.add_player(user_id=user.id, first_name=user.first_name)
    GameStore().add_game(chat.id, game)

    # TODO currently the game starts instantly - this should change with multiplayer rooms
    if game.type == BlackJackGame.Type.SINGLEPLAYER:
        update.effective_message.reply_text(translator("game_starts_now").format("", get_cards_string(game.dealer, lang_id)))
        players_turn(update, context)
    else:
        text = translator("mp_request_join").format(game.get_player_list())
        update.effective_message.reply_text(text=text, reply_markup=get_join_keyboard(game.id, lang_id))
コード例 #2
0
def join_callback(update, context):
    """
    CallbackQueryHandler callback for the 'join' inline button. Adds the executing player to the game of the specific chat
    """
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    game = GameStore().get_game(chat.id)

    if not is_button_affiliated(update, context, game, lang_id):
        return

    try:
        game.add_player(user.id, user.first_name)
        update.effective_message.edit_text(text=translator("mp_request_join").format(game.get_player_list()),
                                           reply_markup=get_join_keyboard(game.id, lang_id))
        update.callback_query.answer(translator("mp_join_callback").format(user.first_name))

        # If players are full, replace join keyboard with start keyboard
        if len(game.players) >= game.MAX_PLAYERS:
            update.effective_message.edit_reply_markup(reply_markup=get_start_keyboard(lang_id))
    except errors.GameAlreadyRunningException:
        remove_inline_keyboard(update, context)
        update.callback_query.answer(translator("mp_game_already_begun_callback"))
    except errors.MaxPlayersReachedException:
        update.effective_message.edit_reply_markup(reply_markup=get_start_keyboard(lang_id))
        update.callback_query.answer(translator("mp_max_players_callback"))
    except errors.PlayerAlreadyExistingException:
        update.callback_query.answer(translator("mp_already_joined_callback"))
コード例 #3
0
def next_player(update, context):
    chat = update.effective_chat
    user = update.effective_user
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    game = GameStore().get_game(chat.id)

    try:
        if user.id != game.get_current_player().user_id:
            update.callback_query.answer(translator("mp_not_your_turn_callback").format(user.first_name))
            return

        remove_inline_keyboard(update, context)
        game.next_player()
    except NoPlayersLeftException:
        # TODO merge messages
        update.effective_message.reply_text(translator("dealers_cards_are").format(game.dealer.cardvalue,
                                                                                   get_cards_string(game.dealer, lang_id)),
                                            parse_mode=ParseMode.HTML)
        evaluation_string = generate_evaluation_string(game, lang_id)

        newgame_button = InlineKeyboardButton(text=translator("inline_keyboard_newgame"), callback_data="newgame")
        keyboard = InlineKeyboardMarkup(inline_keyboard=[[newgame_button]])
        update.effective_message.reply_text(evaluation_string, reply_markup=keyboard)
        game.stop(-1)
        return

    players_turn(update, context)
コード例 #4
0
def players_turn(update, context):
    """Execute a player's turn"""
    chat = update.effective_chat
    game = GameStore().get_game(chat.id)
    player = game.get_current_player()
    user_mention = html_mention(user_id=player.user_id, first_name=player.first_name)

    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    logger.info("Player's turn: {}".format(player))
    player_cards = get_cards_string(player, lang_id)

    # Check if player already has 21 or a BlackJack before their move. If so, automatically jump to the next player.
    # We need reply_text here, because we must send a new message (this is the first message for the player)!
    if player.has_blackjack():
        text = (translator("your_cards_are") + "\n\n" + translator("got_blackjack")).format(user_mention, player.cardvalue, player_cards)
        update.effective_message.reply_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
        next_player(update, context)
    elif player.cardvalue == 21:
        text = (translator("your_cards_are") + "\n\n" + translator("got_21")).format(user_mention, player.cardvalue, player_cards)
        update.effective_message.reply_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
        next_player(update, context)
    else:
        text = translator("your_cards_are").format(user_mention, player.cardvalue, player_cards)
        update.effective_message.reply_text(text=text, parse_mode=ParseMode.HTML, reply_markup=get_game_keyboard(game.id, lang_id))
コード例 #5
0
def answer_comment_cmd(update, context):
    # Answer to admins only in English, because we don't save admin languages yet
    text = update.effective_message.text
    reply_to_message = update.message.reply_to_message
    text = text.replace("/answer ", "")

    # Error handling
    if reply_to_message is None or update.message.reply_to_message.from_user.id != context.bot.id:
        update.message.reply_text("⚠ You need to reply to the user's comment!")
        return
    if update.message.reply_to_message.text is None:
        update.message.reply_text("⚠ You replied to a non text message!")
        return

    try:
        # Parse user data from the message
        user_info = reply_to_message.text.split("\n")[-1]
    except Exception as e:
        update.message.reply_text("⚠ An unexpected error occurred!")
        logger.error(
            "While parsing user data, the following exception occurred: {}".
            format(e))
        return

    user = user_info.split(" | ")

    if type(user) != list or len(user) != 6:
        update.message.reply_text(
            "⚠ Can't parse user data from the message you replied to! Please reply to a comment!"
        )
        logger.warning("Can't parse user data from message: {}".format(
            reply_to_message.text))
        return

    chat_id = user[0]

    if not re.match(r"^\d+$", chat_id):
        update.message.reply_text("⚠ Malformed chat_id!")
        logger.error("Malformed chat_id: {}".format(chat_id))
        return

    translator = Translator(chat_id)
    user_reply = translator("reply_from_maintainer").format(text)

    # The following errors can easily happen here:
    # Have no rights to send a message -> Missing permissions
    # Forbidden: bot was blocked by the user -> User blocked the bot
    context.bot.send_message(chat_id=chat_id, text=user_reply)
    update.message.reply_text(text="I sent your comment to the user!")

    notify_admins(
        "An admin replied to the comment by\n\n{}\n\nwith:\n\n{}".format(
            user_info, text), context)
コード例 #6
0
ファイル: decorators.py プロジェクト: patulinomods/21-bot
    def admin_check(update, context):
        user = update.effective_user
        chat = update.effective_chat
        lang_id = Database().get_lang_id(chat.id)
        translator = Translator(lang_id=lang_id)

        if user.id in Database().get_admins():
            return func(update, context)
        else:
            update.message.reply_text(translator("no_permission"))
            logging.warning(
                "User {} ({}, @{}) tried to use admin function '{}'!".format(
                    user.id, user.first_name, user.username, func.__name__))
コード例 #7
0
def get_join_keyboard(game_id, lang_id):
    """
    Generates a join keyboard translated into the given language
    :param game_id: A unique identifier for each game
    :param lang_id: The language identifier for a specific chat
    :return:
    """
    translator = Translator(lang_id)
    join_button = InlineKeyboardButton(text=translator("inline_keyboard_join"),
                                       callback_data="join_{}".format(game_id))
    start_button = InlineKeyboardButton(
        text=translator("inline_keyboard_start"),
        callback_data="start_{}".format(game_id))
    return InlineKeyboardMarkup(inline_keyboard=[[join_button, start_button]])
コード例 #8
0
ファイル: decorators.py プロジェクト: patulinomods/21-bot
    def wrapper(update, context, *args, **kwargs):
        chat = update.effective_chat
        lang_id = Database().get_lang_id(chat.id)
        translator = Translator(lang_id=lang_id)

        try:
            game = GameStore().get_game(chat.id)
        except NoActiveGameException:
            remove_inline_keyboard(update, context)
            update.effective_message.reply_text(
                translator("mp_no_created_game_callback"))
            return

        return func(update, context)
コード例 #9
0
def stop_cmd(update, context):
    """Stops a game for a specific user"""
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    game = GameStore().get_game(chat.id)

    try:
        game.stop(user.id)
        update.effective_message.reply_text(translator("game_ended"))
    except errors.InsufficientPermissionsException:
        update.effective_message.reply_text(
            translator("mp_only_creator_can_end"))
コード例 #10
0
def start_cmd(update, context):
    """Handles messages contianing the /start command. Starts a game for a specific user"""
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    Database().add_user(user.id, user.language_code, user.first_name, user.last_name, user.username)

    try:
        GameStore().get_game(update.effective_chat.id)
        # TODO notify user that there is a running game already?
    except NoActiveGameException:
        # If there is no game, we create one
        create_game(update, context)
コード例 #11
0
def get_game_keyboard(game_id, lang_id):
    """Generates a game keyboard translated into the given language
    :param game_id: A unique identifier for each game
    :param lang_id: The language identifier for a specific chat
    :return:
    """
    translator = Translator(lang_id)
    one_more_button = InlineKeyboardButton(
        text=translator("inline_keyboard_hit"),
        callback_data="hit_{}".format(game_id))
    no_more_button = InlineKeyboardButton(
        text=translator("inline_keyboard_stand"),
        callback_data="stand_{}".format(game_id))
    stop_button = InlineKeyboardButton(text="Stop",
                                       callback_data="stop_{}".format(game_id))
    return InlineKeyboardMarkup(
        inline_keyboard=[[one_more_button, no_more_button]])
コード例 #12
0
def start_callback(update, context):
    """Starts a game that has been created already"""
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    try:
        game = GameStore().get_game(update.effective_chat.id)

        if not is_button_affiliated(update, context, game, lang_id):
            return
    except NoActiveGameException:
        update.callback_query.answer(translator("mp_no_created_game_callback"))
        remove_inline_keyboard(update, context)
        return

    try:
        game.start(user.id)
        update.callback_query.answer(translator("mp_starting_game_callback"))
    except errors.GameAlreadyRunningException:
        update.callback_query.answer(
            translator("mp_game_already_begun_callback"))
        return
    except errors.NotEnoughPlayersException:
        update.callback_query.answer(
            translator("mp_not_enough_players_callback"))
        return
    except errors.InsufficientPermissionsException:
        update.callback_query.answer(
            translator("mp_only_creator_start_callback").format(
                user.first_name))
        return

    if game.type != BlackJackGame.Type.SINGLEPLAYER:
        players_are = translator("mp_players_are")
        for player in game.players:
            players_are += "👤{}\n".format(player.first_name)
        players_are += "\n"
    else:
        players_are = ""

    update.effective_message.edit_text(
        translator("game_starts_now").format(
            players_are, get_cards_string(game.dealer, lang_id)))
    players_turn(update, context)
コード例 #13
0
def _generate_evaluation_string_mp(game, lang_id):
    list_won, list_tie, list_losses = game.evaluation()
    message = ""
    translator = Translator(lang_id)
    dealer_name = translator("dealer_name")

    if len(list_won) > 0:
        message += translator("eval_heading_wins") + "\n"
        message += _get_player_list_string(list_won, dealer_name)

    # 🔃
    if len(list_tie) > 0:
        message += "\n\n{}\n".format(translator("eval_heading_ties"))
        message += _get_player_list_string(list_tie, dealer_name)

    if len(list_losses) > 0:
        message += "\n\n{}\n".format(translator("eval_heading_losses"))
        message += _get_player_list_string(list_losses, dealer_name)

    return message
コード例 #14
0
def _generate_evaluation_string_sp(game, lang_id):
    list_won, list_tie, list_losses = game.evaluation()
    message = ""
    join_str = "\n{} - {}"
    player = game.players[0]
    translator = Translator(lang_id)

    if len(list_won) == 1:
        if game.dealer.busted:
            # Dealer busted, you won
            message += translator("dealer_busted")
        else:
            # Closer to 21
            message += translator("closer_to_21")

        message += "\n"
        message += join_str.format(player.first_name, player.cardvalue)
        message += join_str.format(translator("dealer_name"),
                                   game.dealer.cardvalue)
    elif len(list_tie) == 1:
        # Same value as dealer
        message += translator("tied_with_dealer")
        message += "\n"
        message += join_str.format(player.first_name, player.cardvalue)
        message += join_str.format(translator("dealer_name"),
                                   game.dealer.cardvalue)
    elif len(list_losses) == 1:
        if player.busted:
            # busted
            message += translator("you_busted")
        elif game.dealer.has_blackjack():
            message += translator("dealer_got_blackjack")
        else:
            message += translator("dealer_got_21")

        message += "\n"
        message += join_str.format(translator("dealer_name"),
                                   game.dealer.cardvalue)
        message += join_str.format(player.first_name, player.cardvalue)

    return message
コード例 #15
0
def hit_callback(update, context):
    """
    CallbackQueryHandler callback for the 'hit' inline button. Draws a card for you.
    """
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    game = GameStore().get_game(chat.id)

    if not is_button_affiliated(update, context, game, lang_id):
        return

    player = game.get_current_player()
    user_mention = html_mention(user_id=player.user_id, first_name=player.first_name)

    try:
        if user.id != player.user_id:
            update.callback_query.answer(translator("mp_not_your_turn_callback").format(user.first_name))
            return

        game.draw_card()
        player_cards = get_cards_string(player, lang_id)
        text = translator("your_cards_are").format(user_mention, player.cardvalue, player_cards)
        update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=get_game_keyboard(game.id, lang_id))
    except errors.PlayerBustedException:
        player_cards = get_cards_string(player, lang_id)
        text = (translator("your_cards_are") + "\n\n" + translator("you_busted")).format(user_mention, player.cardvalue, player_cards)
        update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
        next_player(update, context)
    except errors.PlayerGot21Exception:
        player_cards = get_cards_string(player, lang_id)
        if player.has_blackjack():
            text = (translator("your_cards_are") + "\n\n" + translator("got_blackjack")).format(user_mention, player.cardvalue, player_cards)
            update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
            next_player(update, context)
        elif player.cardvalue == 21:
            text = (translator("your_cards_are") + "\n\n" + translator("got_21")).format(user_mention, player.cardvalue, player_cards)
            update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
            next_player(update, context)
コード例 #16
0
def stop_cmd(update, context):
    """Stops a game for a specific user"""
    user = update.effective_user
    chat = update.effective_chat
    lang_id = Database().get_lang_id(chat.id)
    translator = Translator(lang_id=lang_id)

    game = GameStore().get_game(chat.id)

    user_id = user.id
    try:
        if chat.type == "group" or chat.type == "supergroup":
            # If yes, get the chat admins
            admins = context.bot.get_chat_administrators(chat_id=chat.id)
            # if user.id in chat admin IDs, let them end the game with admin powers
            if user.id in [x.user.id for x in admins]:
                user_id = -1

        game.stop(user_id)
        update.effective_message.reply_text(translator("game_ended"))
    except errors.InsufficientPermissionsException:
        update.effective_message.reply_text(translator("mp_only_creator_can_end"))
コード例 #17
0
def get_start_keyboard(lang_id):
    translator = Translator(lang_id)
    start_button = InlineKeyboardButton(
        text=translator("inline_keyboard_start"), callback_data="start")
    return InlineKeyboardMarkup(inline_keyboard=[[start_button]])