def king_cabinet_construction(bot, update): request = "select location_id from locations where state is false and building_process = -1" cursor.execute(request) row = cursor.fetchone() response = "Здания, которые можно начать строить:\n" while row is not None: location = Location.get_location(row[0]) if location is None: row = cursor.fetchone() continue response += "<b>{}</b>\nСтоимость: 🌲: <code>{}</code>, ⛰: <code>{}</code>\nНачать строительство: " \ "/begin_construction_{}\n".format(location.name, location.need_res_to_construct.get("wood") or 0, location.need_res_to_construct.get("stone") or 0, location.id) row = cursor.fetchone() response += "\n----------------------\nСтройка в процессе:\n" request = "select location_id from locations where state is false and building_process >= 0" cursor.execute(request) row = cursor.fetchone() while row is not None: location = Location.get_location(row[0]) if location is None: row = cursor.fetchone() continue response += "<b>{}</b>\nПрогресс: <code>{}</code> из <code>{}</code>\n" \ "\n".format(location.name, location.building_process, location.need_clicks_to_construct) row = cursor.fetchone() treasury = Location.get_location(6) response += "\n----------------------\nСостояние казны: 🌲Дерево: <b>{}</b>, " \ "⛰Камень: <b>{}</b>".format(treasury.wood, treasury.stone) bot.send_message(chat_id=update.message.chat_id, text=response, parse_mode='HTML')
def begin_construction(bot, update): mes = update.message location_id = re.search("_(\\d+)", mes.text) if location_id is None: bot.send_message(chat_id=mes.chat_id, text="Неверный синтаксис") return location_id = int(location_id.group(1)) location = Location.get_location(location_id) if location is None: bot.send_message(chat_id=mes.chat_id, text="Локация не найдена") return if location.state is True or location.building_process > 0: bot.send_message(chat_id=mes.chat_id, text="Локация уже построена или стройка в процессе") return treasury = Location.get_location(6) need_wood = location.need_res_to_construct.get("wood") or 0 need_stone = location.need_res_to_construct.get("stone") or 0 if treasury.wood < need_wood or treasury.stone < need_stone: bot.send_message(chat_id=mes.chat_id, text="Не хватает ресурсов для начала строительства. " "Вам следует быть жестче с подчинёнными!") return treasury.wood -= need_wood treasury.stone -= need_stone treasury.update_location_to_database() ctrl = Location.get_location(0) old = ctrl.special_info.get("enter_text_format_values") old[1] = treasury.wood old[2] = treasury.stone location.building_process = 0 location.update_location_to_database() bot.send_message(chat_id=mes.chat_id, text="Стройка <b>{}</b> началась!".format(location.name), parse_mode='HTML')
def construct(bot, update, user_data): mes = update.message location_id = None for loc in list(locations.values()): if loc.name == mes.text: location_id = loc.id break if mes.text == '/build_teaparty': location_id = 9 if location_id is None: send_general_buttons(mes.from_user.id, user_data=user_data, bot=bot) return location = Location.get_location(location_id) if location is None: bot.send_message(chat_id=mes.chat_id, text="Локация не найдена.") return if location.state is True or location.building_process < 0: bot.send_message(chat_id=mes.chat_id, text="Локация уже построена или стройка не начиналась.") return context = [update.message.from_user.id, user_data] j = job.run_once(callback=construction_return, when=CONSTRUCTION_DURATION_SECONDS, context=context) old_j = construction_jobs.get(update.message.from_user.id) if old_j is not None: old_j.job.schedule_removal() construction_jobs.update({update.message.from_user.id: MyJob(j, CONSTRUCTION_DURATION_SECONDS)}) user_data.update({"status": "construction", "construction_id": location.id}) buttons = get_general_buttons(user_data) bot.send_message(chat_id=update.message.chat_id, text="Вы отправились на стройку. Это займёт 5 минут.", reply_markup=buttons)
def remove_general(bot, update): """ Функция удаления Генерала """ mes = update.message player_id = re.search("_(\\d+)", mes.text) if player_id is None: bot.send_message(chat_id=update.message.from_user.id, text="Неверный синтаксис.") return player_id = int(player_id.group(1)) if player_id not in high_access_list: bot.send_message(chat_id=update.message.from_user.id, text="Так он, это, вроде и не генерал вовсе. " "Может, помилуем?") return player = Player.get_player(player_id, notify_on_error=False) throne = Location.get_location(2) mid_players = throne.special_info.get("mid_players") mid_players.remove(player_id) throne.update_location_to_database() fill_mid_players() bot.send_message(chat_id=update.message.from_user.id, text="@{} сослан в тортугу и больше не генерал".format( player.username))
def request_roulette_bet(bot, update, user_data): """ Запрос ставки в рулетке """ mes = update.message user_data.update({"status": "awaiting_roulette_bet"}) roulette = Location.get_location(10) placed = roulette.special_info["placed"].get(str(mes.from_user.id)) if placed is None: placed = 0 buttons = get_general_buttons(user_data) player = Player.get_player(mes.from_user.id) if player is None: return bot.send_message( chat_id=update.message.from_user.id, text= "Введите количество 🔘жетонов для ставки:\nМинимальная ставка: 10🔘\n\n" "Ваша ставка: <b>{}</b>🔘.\n" "Доступно: <b>{}</b>🔘.{}\n\n<em>Обратите внимание, отменить ставку невозможно.</em>" "".format( placed, player.reputation, "\nМаксимальная ставка: <b>{}</b>🔘".format(ROULETTE_MAX_BET_LIMIT) if datetime.datetime.now(tz=moscow_tz).replace(tzinfo=None).time() < datetime.time(hour=ROULETTE_HOUR_LIMIT) else ""), reply_markup=buttons, parse_mode='HTML')
def restrict_feedback(bot, update): """ Функция ограничения возможности обращения в МИД """ mes = update.message user_id = re.search("_(\\d+)", mes.text) if user_id is None: bot.send_message(chat_id=mes.chat_id, text="Неверный синтаксис", reply_to_message_id=mes.message_id) return user_id = int(user_id.group(1)) location_id = None if mes.chat_id == MID_CHAT_ID: location_id = 2 elif mes.chat_id == SENTINELS_DUTY_CHAT_ID: location_id = 3 if location_id is None: return loc = Location.get_location(location_id) banned_users = loc.special_info.get("banned_in_feedback") if user_id in banned_users: bot.send_message(chat_id=mes.chat_id, text="Этот человек уже забанен", reply_to_message_id=mes.message_id) return banned_users.append(user_id) loc.update_location_to_database() bot.send_message( chat_id=mes.chat_id, text="Пользователь успешно заблокирован.\nСнять блокировку: " "/unrestrict_feedback_{}".format(user_id), reply_to_message_id=mes.message_id) bot.send_message(chat_id=user_id, text="Вам запретили общаться в {}".format(loc.name))
def resource_return(bot, job): cursor = conn.cursor() if job.context[1].get("status") not in ["sawmill", "quarry"]: logging.warning( "Status not in [\"sawmill\", \"quarry\"], status = {}".format( job.context[1].get("status"))) return statuses_to_res = {"sawmill": "wood", "quarry": "stone"} res = statuses_to_res.get(job.context[1].get("status")) count = 1 throne = Location.get_location(2) throne.treasury.change_resource(res, count) player = Player.get_player(job.context[0]) player.reputation += 3 player.update_to_database() job.context[1].update({"status": "castle_gates"}) buttons = get_general_buttons(job.context[1], player) if job.context[0] in construction_jobs: try: construction_jobs.pop(job.context[0]) except Exception: logging.error(traceback.format_exc()) request = "insert into castle_logs(player_id, action, result, additional_info, date) values (%s, %s, %s, %s, %s)" cursor.execute( request, (player.id, "collect_resources", 1, json.dumps({ "resource": res, "count": count }), datetime.datetime.now(tz=moscow_tz).replace(tzinfo=None))) bot.send_message(chat_id=job.context[0], text="Вы успешно добыли {}. Казна обновлена. Получено 3 🔘" "".format("дерево" if res == "wood" else "камень"), reply_markup=buttons) on_resource_return(player, res)
def adding_general(bot, update, user_data): """ Добавление Генерала """ mes = update.message try: player_id = int(mes.text) except ValueError: bot.send_message(chat_id=update.message.from_user.id, text="Неверный синтаксис.") return if player_id in high_access_list: bot.send_message(chat_id=update.message.from_user.id, text="Этот человек уже являетсяс генералом.") return player = Player.get_player(player_id, notify_on_error=False) if player is None: bot.send_message(chat_id=update.message.from_user.id, text="Невозможно найти этого холопа. " "Убедитесь, что он зарегистрирован в боте") return throne = Location.get_location(2) mid_players = throne.special_info.get("mid_players") mid_players.append(player_id) throne.update_location_to_database() fill_mid_players() bot.send_message(chat_id=update.message.from_user.id, text="@{} теперь генерал!".format(player.username)) user_data.update({"status": "king_cabinet"})
def unrestrict_feedback(bot, update): """ Функция снятия ограничений с игрока по обращению в МИД """ mes = update.message user_id = re.search("_(\\d+)", mes.text) if user_id is None: bot.send_message(chat_id=mes.chat_id, text="Неверный синтаксис", reply_to_message_id=mes.message_id) return user_id = int(user_id.group(1)) location_id = None if mes.chat_id == MID_CHAT_ID: location_id = 2 elif mes.chat_id == SENTINELS_DUTY_CHAT_ID: location_id = 3 if location_id is None: return loc = Location.get_location(location_id) banned_users = loc.special_info.get("banned_in_feedback") if user_id not in banned_users: bot.send_message(chat_id=mes.chat_id, text="Этот человек не забанен!", reply_to_message_id=mes.message_id) return banned_users.remove(user_id) loc.update_location_to_database() bot.send_message(chat_id=mes.chat_id, text="Пользователь успешно разблокирован", reply_to_message_id=mes.message_id) bot.send_message(chat_id=user_id, text="Вам снова разрешено общаться в {}".format(loc.name))
def change_update_message(bot, update, user_data): user_data.update({"status": "technical_tower", "location_id": 5}) tower = Location.get_location(5) format_values = tower.special_info.get("enter_text_format_values") format_values[ 0] = "Последнее обновление: {}.\nДля просмотра возьмите страничку сверху 🗂Архива".format( great_format_time(get_current_datetime())) tower.special_info.update({"enter_text_format_values": format_values}) tower.update_location_to_database() last_update_id = tower.special_info.get("last_update_id") last_update_id += 1 tower.special_info.update({"last_update_id": last_update_id}) tower.update_location_to_database() request = "insert into bot_updates (text, date_created) VALUES (%s, %s)" cursor.execute(request, (update.message.text, datetime.datetime.now(tz=moscow_tz).replace(tzinfo=None))) bot.send_message( chat_id=update.message.from_user.id, text= "Обновление успешно опубликовано. Вы спускаетесь, чтобы проверить, что всё выглядит " "хорошо.\n\n<em>В случае, если после этого не последует сообщение с обновлением, " "измените его</em>", parse_mode='HTML') send_general_buttons(update.message.from_user.id, user_data, bot=bot) bot.send_message(chat_id=MY_CHANNEL_ID, text=update.message.text, parse_mode='HTML')
def fill_mid_players(other_process=False): high_access_list.clear() throne = Location.get_location(2) if other_process: throne.load_location(other_process=True) mid_players = throne.special_info.get("mid_players") for player_id in mid_players: high_access_list.append(player_id)
def revoke_all_class_links(bot, update): if not check_access(update.message.from_user.id): return barracks = Location.get_location(1) barracks.special_info.update({"class_links": {}}) barracks.update_location_to_database() bot.send_message(chat_id=update.message.chat_id, text="Все ссылки сброшены!")
def update_history(bot, update): tower = Location.get_location(5) last_update_id = tower.special_info.get("last_update_id") text, date = get_update_text_and_date(last_update_id) response = "Вы берёте из стопки верхний листок (№ {} — {})\n📜\n".format(last_update_id, date.strftime("%d/%m/%y %H:%M:%S")) response += text bot.send_message(chat_id=update.message.chat_id, text=response, parse_mode='HTML', reply_markup=get_update_history_buttons(last_update_id, last_update_id))
def castle_hello(bot, update): cp = Location.get_location(0) mes = update.message notified = cp.special_info.get("notified_on_join") if notified is None: notified = [] cp.special_info.update({"notified_on_join": notified}) if mes.from_user.id not in notified: notified.append(mes.from_user.id) cp.update_location_to_database() job.run_once(hello_check, 2, context={"mes": mes})
def construction_return(bot, job): cursor = conn.cursor() player_id = job.context[0] user_data = job.context[1] if user_data.get("status") not in ["construction"]: return location_id = user_data.get("construction_id") if location_id is None: bot.send_message(chat_id=player_id, text="Ошибка поиска локации.") return location = Location.get_location(location_id) if location is None: bot.send_message(chat_id=player_id, text="Ошибка поиска локации.") return print(location.name, location.state, location.building_process) if location.state is True or location.building_process < 0: bot.send_message( chat_id=player_id, text= "Локация уже построена или стройка не начиналась. Возможно, локацию " "построили в то время, пока вы добирались до стройки.") return location.building_process += 3 player = Player.get_player(job.context[0]) if location.building_process >= location.need_clicks_to_construct: location.state = True bot.send_message( chat_id=player_id, text="Локация успешно построена! Вы положили последний камень!") player.reputation += 50 - CONSTRUCTION_REPUTATION player.reputation += CONSTRUCTION_REPUTATION player.update_to_database() location.update_location_to_database() user_data.update({"status": "central_square"}) if "construction_id" in user_data: user_data.pop("construction_id") if job.context[0] in construction_jobs: try: construction_jobs.pop(job.context[0]) except Exception: logging.error(traceback.format_exc()) buttons = get_general_buttons(user_data, player) request = "insert into castle_logs(player_id, action, result, additional_info, date) values (%s, %s, %s, %s, %s)" cursor.execute(request, (player.id, "construction", 1, json.dumps({"location_id": location_id}), datetime.datetime.now(tz=moscow_tz).replace(tzinfo=None))) bot.send_message( chat_id=job.context[0], text="Вы вернулись со стройки. Получено <code>{}</code> 🔘".format( CONSTRUCTION_REPUTATION), reply_markup=buttons, parse_mode='HTML')
def change_castle_message(bot, update, user_data): """ Смена сообщения Короля """ central = Location.get_location(0) old_format = central.special_info.get("enter_text_format_values") old_format[0] = update.message.text central.update_location_to_database() user_data.update({"status": "king_cabinet"}) bot.send_message(chat_id=update.message.from_user.id, text="Новое сообщение:\n<em>{}</em>".format( update.message.text), parse_mode='HTML')
def ask_to_revoke_duty_link(): """ При запуске бота предлагает проверить ссылку в чат стражи и перевыпустить её при необходимости """ gates = Location.get_location(3) invite_link = gates.special_info.get("invite_link") dispatcher.bot.send_message( chat_id=SUPER_ADMIN_ID, text="<a href=\"{}\">Проверить ссылку</a>\n Сбросить ссылку: " "/revoke_duty_link".format( "https://t.me/joinchat/" + invite_link if invite_link is not None else ""), parse_mode='HTML')
def request_change_castle_message(bot, update, user_data): """ Запрос смены сообщения Короля (на Центральной Площади) """ central = Location.get_location(0) current_message = central.special_info.get("enter_text_format_values") user_data.update({"status": "changing_castle_message"}) buttons = get_general_buttons(user_data) bot.send_message( chat_id=update.message.from_user.id, text= "Текущее сообщение:\n<em>{}</em>\nВведите новое сообщение. Не делайте его слишком большим." "".format(current_message), parse_mode='HTML', reply_markup=buttons)
def revoke_duty_link(bot, update): """ Функция перевыпуска ссылки в чат стражи """ gates = Location.get_location(3) try: invite_link = bot.exportChatInviteLink(SENTINELS_DUTY_CHAT_ID) if invite_link is not None: invite_link = invite_link[22:] # Обрезаю https://t.me/joinchat/ gates.special_info.update({"invite_link": invite_link}) gates.update_location_to_database() bot.send_message(chat_id=update.message.chat_id, text="Ссылка на чат вахты сброшена") except TelegramError: logging.error(traceback.format_exc()) bot.send_message(chat_id=update.message.chat_id, text="Произошла ошибка.")
def change_update_history(bot, update): mes = update.callback_query.message tower = Location.get_location(5) last_update_id = tower.special_info.get("last_update_id") new_update_id = re.search("_(\\d+)", update.callback_query.data) new_update_id = int(new_update_id.group(1)) if "uhl" in update.callback_query.data: new_update_id -= 1 else: new_update_id += 1 text, date = get_update_text_and_date(new_update_id) response = "Вы берёте из стопки листок (№ {} — {})\n📜\n".format(new_update_id, date.strftime("%d/%m/%y %H:%M:%S")) buttons = get_update_history_buttons(new_update_id, last_update_id) bot.editMessageText(chat_id=mes.chat_id, message_id=mes.message_id, text=response + text, reply_markup=buttons, parse_mode='HTML') bot.answerCallbackQuery(callback_query_id=update.callback_query.id)
def plan_roulette_games(): """ Планирует ближайшую игру в рулетке. Запускается снова каждый раз по окончанию игры. """ logging.error("Planning roulette game") now = datetime.datetime.now(tz=moscow_tz).replace(tzinfo=None) roulette_time = now.replace(hour=9, minute=0, second=0) limit_time = now.replace(hour=21, minute=0, second=0) while roulette_time < now and roulette_time <= limit_time: roulette_time += datetime.timedelta(hours=3, minutes=0) if roulette_time > limit_time: roulette_time = datetime.datetime.combine( now.date() + datetime.timedelta(days=1), datetime.time(hour=9)) tea_party = Location.get_location(9) if tea_party.is_constructed(): job.run_once(roulette_game, when=roulette_time) logging.error("Roulette planned on {}".format(roulette_time))
def request_mid_feedback(bot, update, user_data): """ Функция запроса обращения в МИД """ mes = update.message if not check_mid_feedback_time_access(bot, update): return loc = Location.get_location(2) banned_users = loc.special_info.get("banned_in_feedback") if mes.from_user.id in banned_users: bot.send_message(chat_id=mes.chat_id, text="Вам запретили общаться здесь!", reply_to_message_id=mes.message_id) return user_data.update({"status": "mid_feedback"}) bot.send_message(chat_id=update.message.chat_id, text="Следующее сообщение будет отправлено в чат мида.", reply_markup=get_general_buttons(user_data))
def change_debrief(bot, update, user_data): """ Непосредственно смена дебрифа на новый """ user_data.update({"status": "throne_room", "location_id": 2}) throne = Location.get_location(2) format_values = throne.special_info.get("enter_text_format_values") format_values[1] = update.message.text throne.special_info.update({"enter_text_format_values": format_values}) throne.update_location_to_database() bot.send_message( chat_id=update.message.from_user.id, text= "Дебриф успешно изменён. Вы выходите в тронный зал, чтобы проверить, что всё выглядит " "хорошо.\n\n<em>В случае, если после этого не последует сообщение с дебрифом, " "измените его</em>", parse_mode='HTML') send_general_buttons(update.message.from_user.id, user_data, bot=bot)
def check_ban_in_duty_chat(bot, update): """ Функция, которая проверяет, можно ли игроку зайти (и писать) в чат стражи """ gates = Location.get_location(3) players_on_duty = gates.special_info.get("players_on_duty") user_id = update.message.from_user.id player = Player.get_player(user_id) if player is not None and player.game_class == 'Sentinel': # Временно разрешено находиться в чате всем стражам return if user_id not in players_on_duty and not check_access( user_id) and user_id != CASTLE_BOT_ID: bot.kickChatMember(chat_id=SENTINELS_DUTY_CHAT_ID, user_id=update.message.from_user.id) bot.send_message( chat_id=SENTINELS_DUTY_CHAT_ID, text="Только стражам на службе разрешён вход в этот чат")
def hall_of_fame(bot, update, user_data): """ Функция, вызываемая при входе в Зал Славы """ hall = Location.get_location(8) if not hall.is_constructed( ) and update.message.from_user.id != SUPER_ADMIN_ID: unknown_input(bot, update, user_data) return tops( bot, update, user_data, response= "Вы входите в Мандапу Славы - почетное место, где увековечены герои Скалы, " "их подвиги и заслуги перед замком. На стене развешаны лучшие из лучших.\n\n" ) """
def revoke_class_link(game_class): chat_id = class_chats.get(game_class) if chat_id is None: return -1 barracks = Location.get_location(1) class_links = barracks.special_info.get("class_links") if class_links is None: class_links = {} barracks.special_info.update({"class_links": class_links}) try: invite_link = dispatcher.bot.exportChatInviteLink(chat_id) if invite_link is not None: invite_link = invite_link[22:] # Обрезаю https://t.me/joinchat/ class_links.update({game_class: invite_link}) barracks.update_location_to_database() except TelegramError: logging.error(traceback.format_exc()) return 1
def begin_duty(bot, update, user_data): """ Функция начала вахты для игрока (стражника) """ mes = update.message player_id = mes.from_user.id player = Player.get_player(player_id) if player.game_class != 'Sentinel': bot.send_message(chat_id=mes.chat_id, text="Только стражники могут вставать на вахту!") return gates = Location.get_location(3) invite_link = gates.special_info.get("invite_link") if invite_link is None: try: invite_link = bot.exportChatInviteLink(SENTINELS_DUTY_CHAT_ID) if invite_link is not None: invite_link = invite_link[ 22:] # Обрезаю https://t.me/joinchat/ gates.special_info.update({"invite_link": invite_link}) gates.update_location_to_database() except TelegramError: logging.error(traceback.format_exc()) players_on_duty = gates.special_info.get("players_on_duty") if player_id in players_on_duty: bot.send_message(chat_id=mes.chat_id, text="Вы уже на вахте!") else: players_on_duty.append(player_id) gates.update_location_to_database() try: bot.unbanChatMember(chat_id=SENTINELS_DUTY_CHAT_ID, user_id=player_id) except TelegramError: logging.error(traceback.format_exc()) user_data.update({"on_duty": True}) reply_markup = get_general_buttons(user_data) bot.send_message( chat_id=mes.from_user.id, text="Вы заступили на вахту. <a href=\"{}\">Вступайте в чат!</a>" "".format("https://t.me/joinchat/" + invite_link), parse_mode='HTML', reply_markup=reply_markup)
def mobs_notify(bot, update): mes = update.message player = Player.get_player(mes.from_user.id) barracks = Location.get_location(1) chats = barracks.special_info.get("mobs_notify") if chats is None: chats = {} barracks.special_info.update({"mobs_notify": chats}) current = chats.get(str(mes.chat_id)) if current is None: current = [] chats.update({str(mes.chat_id): current}) try: current.remove(player.id) bot.send_message(chat_id=mes.chat_id, text="<b>{}</b> удалён из списка пинга чата на мобов.".format(player.nickname), parse_mode='HTML') except ValueError: current.append(player.id) bot.send_message(chat_id=mes.chat_id, text="<b>{}</b> добавлен в список пинга чата на мобов.".format(player.nickname), parse_mode='HTML') barracks.update_location_to_database()
def get_chat_helpers(chat_id: int, minus, plus, avg_lvl: float, player: Player) -> ['Player']: if chat_id is None: return [] barracks = Location.get_location(1) try: ping_list = barracks.special_info.get("mobs_notify").get(str(chat_id)).copy() except Exception: ping_list = None if not ping_list: ping_list = [] ping_list = set(ping_list) if player.guild is not None or ping_list: guild = Guild.get_guild(guild_id=player.guild) if guild.is_academy() and chat_id == guild.chat_id: # Пинги для академки отключены return if guild is not None and guild.chat_id == chat_id: ping_list.update(guild.members) ping_list.discard(player.id) ping_list = list(filter(lambda player: avg_lvl - minus <= player.lvl <= avg_lvl + plus, map(lambda player_id: Player.get_player(player_id), list(ping_list)))) ping_list.sort(key=lambda player: player.hp if player.hp is not None else -1, reverse=True) return ping_list
def end_duty(bot, update, user_data): """ Функция выхода со стражи (раньше кикала игрока из чата) """ mes = update.message player_id = mes.from_user.id player = Player.get_player(player_id) gates = Location.get_location(3) players_on_duty = gates.special_info.get("players_on_duty") if player_id in players_on_duty: players_on_duty.remove(player_id) gates.update_location_to_database() if "on_duty" in user_data: user_data.pop("on_duty") reply_markup = get_general_buttons(user_data, player=player) try: pass # bot.kickChatMember(chat_id=SENTINELS_DUTY_CHAT_ID, user_id=player_id) except TelegramError: logging.error(traceback.format_exc()) bot.send_message(chat_id=mes.from_user.id, text="Вы успешно покинули вахту. Спасибо за службу!", reply_markup=reply_markup)