def player_join(update: Update, context: CallbackContext): query = update.callback_query chat_data = context.chat_data first_name = name_generator(update.effective_user.first_name) user_id = update.effective_user.id chat_id = update.effective_chat.id # somehow, this callback button is there, but we aren't in join mode, so we handle this now :D if "message" not in chat_data: group_helpers.no_game(update, context, "join_no_game_running") return starter = mention_html(chat_data["starter"]["user_id"], chat_data["starter"]["first_name"]) remove = False for player in chat_data["players"]: player_id = player["user_id"] # player leaves if user_id == player_id: # we do this so player can change their name between joining and leaving chat_data["players"].remove({ "user_id": user_id, "first_name": player["first_name"] }) # we need them in here so we can mention them later. Looks stupid, I know chat_data["left_players"][user_id] = first_name query.answer(get_string(chat_data["lang"], "player_leaves_query")) remove = True break if not remove: # if they left and rejoined before the timer run through, they are still in this dict. If not, nothing happens chat_data["left_players"].pop(user_id, None) chat_data["players"].append({ "user_id": user_id, "first_name": first_name }) query.answer(get_string(chat_data["lang"], "player_joins_query")) players = group_helpers.players_mentions(chat_data["players"]) job = context.job_queue.get_jobs_by_name(chat_id)[0] job.context["players"] = chat_data["players"] job.context["left_players"] = chat_data["left_players"] text = get_string(chat_data["lang"], "start_game").format(starter, players, *chat_data["settings"]) if len(chat_data["players"]) == MAX_PLAYERS: query.edit_message_text(text, parse_mode=ParseMode.HTML) payload = job.context job.schedule_removal() new_context = context setattr(new_context, "job", Job(timer, interval=42, name=chat_id, context=payload)) timer(context) return button = [[ InlineKeyboardButton(get_string(chat_data["lang"], "start_button"), callback_data="join") ]] query.edit_message_text(text, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(button))
def flood_error(context): data = context.job.context # this means the join phase ended and a different call edited the function already if "message" not in data: return starter = mention_html(data["starter"]["user_id"], data["starter"]["first_name"]) players = group_helpers.players_mentions(data["players"]) text = get_string(data["lang"], "start_game").format(starter, players, *data["settings"]) button = InlineKeyboardMarkup([[ InlineKeyboardButton(get_string(data["lang"], "start_button"), callback_data="join_" + data["game_id"]) ]]) context.bot.edit_message_text(text, data["chat_id"], data["message"], parse_mode=ParseMode.HTML, reply_markup=button) del data["flood"]
def timer(context): data = context.job.context chat_id = context.job.name lang = data["lang"] dp = data["dp"] # repeated join/leave timer if not len(data["players"]) == MAX_PLAYERS: known_players = [] joined_player = [] for player in data["players"]: user_id = player["user_id"] known_players.append(user_id) if user_id in data["known_players"]: data["known_players"].remove(user_id) # player joined else: joined_player.append(player) # if players are left in known_players data, they left left_player = [] if data["known_players"]: for user_id in data["known_players"]: left_player.append({ "user_id": user_id, "first_name": data["left_players"][user_id] }) data["left_players"].pop(user_id) # if both lists are empty, nothing happened, so the timer runs out if not joined_player and not left_player: pass # yes, this replace is stupid. stupider then copying the function though. F**k you. else: if joined_player: text = get_string(lang, "player_joins_text")\ .format(group_helpers.players_mentions(joined_player).replace("\n", ", ")) if left_player: text += "\n\n" + get_string(lang, "player_leaves_text")\ .format(group_helpers.players_mentions(left_player).replace("\n", ", ")) # we can do that, cause otherwise we wouldn't be here else: text = get_string(lang, "player_leaves_text")\ .format(group_helpers.players_mentions(left_player).replace("\n", ", ")) if context.job.interval == START_TIME: long = True else: long = False if len(data["players"]) >= 3: text += get_string(lang, "player_action_text").format( get_string(lang, "start")) if long: context.job.interval = TIME else: text += get_string(lang, "player_action_text").format( get_string(lang, "fail")).replace("30", "60") if not long: context.job.interval = START_TIME context.bot.send_message(chat_id, text, parse_mode=ParseMode.HTML) data["known_players"] = known_players return # game either ends/starts dp.chat_data[chat_id].clear() context.job.schedule_removal() if not len(data["players"]) == MAX_PLAYERS: context.bot.edit_message_reply_markup(chat_id, data["message"], reply_markup=None) if len(data["players"]) >= 3: player_ids = [all_player["user_id"] for all_player in data["players"]] if database.get_new_player(player_ids): text = get_string(lang, "rules_prepend") + get_string( lang, "rules") context.bot.send_message(chat_id, text, parse_mode=ParseMode.HTML) dp.chat_data[chat_id]["players"] = True context.job_queue.run_once(delay, 31, [context, data, chat_id, dp]) else: group_helpers.yes_game(context, data, chat_id, dp) database.remove_group_nextgame(chat_id, player_ids) else: text = get_string(lang, "game_failed") context.bot.send_message(chat_id, text, reply_to_message_id=data["message"])
def player_join(update: Update, context: CallbackContext): query = update.callback_query chat_data = context.chat_data first_name = name_generator(update.effective_user.first_name) user_id = update.effective_user.id chat_id = update.effective_chat.id # check if the chat data is from a different state if "message" not in chat_data: # this means there is no game starting/running if "game_id" not in chat_data: group_helpers.no_game(update, context, "join_no_game_running") return # this means there is a game starting, but the button wasn't removed yet if chat_data["game_id"] == query.data.split("_")[1]: query.answer(get_string(chat_data["lang"], "join_while_starting")) return # if we are here, there is a newer game running and someone hit the button of an old one group_helpers.no_game(update, context, "join_old_button") return starter = mention_html(chat_data["starter"]["user_id"], chat_data["starter"]["first_name"]) remove = False for player in chat_data["players"]: player_id = player["user_id"] # player leaves if user_id == player_id: # we do this so player can change their name between joining and leaving chat_data["players"].remove({ "user_id": user_id, "first_name": player["first_name"] }) # we need them in here so we can mention them later. Looks stupid, I know chat_data["left_players"][user_id] = first_name if "flood" in chat_data: query.answer(get_string(chat_data["lang"], "player_leaves_query_flood"), show_alert=True) else: query.answer( get_string(chat_data["lang"], "player_leaves_query")) remove = True break if not remove: # if they left and rejoined before the timer run through, they are still in this dict. If not, nothing happens chat_data["left_players"].pop(user_id, None) chat_data["players"].append({ "user_id": user_id, "first_name": first_name }) if "flood" in chat_data: query.answer(get_string(chat_data["lang"], "player_joins_query_flood"), show_alert=True) else: query.answer(get_string(chat_data["lang"], "player_joins_query")) players = group_helpers.players_mentions(chat_data["players"]) try: job = context.job_queue.get_jobs_by_name(chat_id)[0] except IndexError: # this means the game already started, we are going to return, but quickly notify teh player they didnt made it mention = mention_html(user_id, first_name) context.bot.send_message( chat_id, get_string(chat_data["lang"], "player_joins_query").format(mention), parse_mode="HTML") return job.context["players"] = chat_data["players"] job.context["left_players"] = chat_data["left_players"] text = get_string(chat_data["lang"], "start_game").format(starter, players, *chat_data["settings"]) if len(chat_data["players"]) == MAX_PLAYERS: query.edit_message_text(text, parse_mode=ParseMode.HTML) payload = job.context job.schedule_removal() new_context = context setattr(new_context, "job", Job(timer, interval=42, name=chat_id, context=payload)) timer(context) return if "flood" in chat_data: return button = [[ InlineKeyboardButton(get_string(chat_data["lang"], "start_button"), callback_data="join_" + chat_data["game_id"]) ]] try: query.edit_message_text(text, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(button)) except RetryAfter as e: context.job_queue.run_once(flood_error, e.retry_after + 2, context=chat_data, name="flood for " + str(chat_id)) chat_data["flood"] = True