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 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 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 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 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 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 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 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 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 request_change_update_message(bot, update, user_data): user_data.update({"status": "editing_update_message"}) buttons = get_general_buttons(user_data) bot.send_message(chat_id=update.message.from_user.id, text="Следующее сообщение будет отображено в башне. Оно должен влезть в это сообщение:\n\n" "{}".format(Location.get_location_enter_text_by_id(5, without_format=True).format( "")), reply_markup=buttons)
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 get_text_to_general_buttons(user_data, player=None): """ Возвращает текст, который нужно отправить по умолчанию с статусом в user_data :param user_data: Словарь user_data, функция использует значения 'status' и 'rp_off' :param player: Player :return: Str """ status = user_data.get("status") location_id = user_data.get("location_id") rp_off = user_data.get("rp_off") if location_id is None: user_data.update({"location_id": 0}) print(rp_off, status) if rp_off and status in ["central_square", "rp_off"]: return "Доброго времени суток!\nВыберите действие:" if status is None or status == "default": return "Вы входите в замок Скалы. Выберите, куда направиться!" if status in ["construction", "sawmill", "quarry"]: if player is not None: j = construction_jobs.get(player.id) if j is not None: seconds_left = j.get_time_left() return "Вы заняты делом. Окончание через <b>{:02.0f}:{:02.0f}</b>".format( seconds_left // 60, (seconds_left % 60) // 1) if location_id is not None: return Location.get_location_enter_text_by_id(location_id, player=player)
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 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 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 request_change_debrief(bot, update, user_data): """ Функция запроса смены дебрифа в Тронном Зале """ user_data.update({"status": "editing_debrief"}) buttons = get_general_buttons(user_data) bot.send_message( chat_id=update.message.from_user.id, text= "Следующее сообщение будет новым дебрифом. Он должен влезть в это сообщение:\n\n" "{}".format( Location.get_location_enter_text_by_id(2, without_format=True).format( "DjedyBreaM", "")), reply_markup=buttons)
def castle_gates(bot, update, user_data): """ Функция, вызываемая при подходе к вратам замка """ location_id = 3 user_data.update({"status": "castle_gates", "location_id": 3}) response = Location.get_location_enter_text_by_id(location_id) player = Player.get_player(update.message.from_user.id) buttons = get_general_buttons(user_data, only_buttons=True, player=player) if player is not None and player.game_class == "Sentinel": # Только для стражей, захардкожено response += "\nКак страж, ты имеешь возможность заступить на вахту\n" reply_markup = ReplyKeyboardMarkup(buttons, resize_keyboard=True) bot.send_message(chat_id=update.message.chat_id, text=response, parse_mode='HTML', reply_markup=reply_markup)
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 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 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 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 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 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