diff --git a/src/bot/__init__.py b/src/bot/__init__.py index e69de29..aa8a8ef 100644 --- a/src/bot/__init__.py +++ b/src/bot/__init__.py @@ -0,0 +1,7 @@ +from . import callback +from . import handlers + +__all__ = [ + "callback", + "handlers" +] \ No newline at end of file diff --git a/src/bot/callback.py b/src/bot/callback.py new file mode 100644 index 0000000..f672a59 --- /dev/null +++ b/src/bot/callback.py @@ -0,0 +1,621 @@ +import random +from datetime import datetime, timedelta + +from telebot.util import quick_markup, chunks +from telebot.types import ( + CallbackQuery, + InlineKeyboardButton, + InlineKeyboardMarkup, + Message, +) +from telebot.apihelper import ApiTelegramException +import toml + +from helpers.enums import ItemRarity +from helpers.exceptions import NoResult +from helpers.markups import InlineMarkup +from base.player import ( + check_user_stats, + coin_top, + dog_level_top, + generate_quest, + get_or_add_user_item, + level_top, + use_item, + get_available_items_for_use, game, sleep, street, work +) +from base.items import items_list +from helpers.utils import ( + get_item_count_for_rarity, + get_item_emoji, + get_time_difference_string, + get_item, +) + +from database.models import DogModel +from database.funcs import database + +from config import GUIDE_FILE_PATH, bot + + +@bot.callback_query_handler(lambda c: c.data.startswith("dog")) +def dog_callback(call: CallbackQuery): + data = call.data.split(" ") + user = database.users.get(id=call.from_user.id) + + try: + dog = database.dogs.get(**{"owner": user._id}) + except NoResult: + dog = None + + if not isinstance(call.message, Message): + return + + if data[-1] != str(user.id): + return + elif data[1] == "leave": + bot.delete_message(call.message.chat.id, call.message.id) + bot.send_sticker( + call.message.chat.id, + "CAACAgIAAxkBAAEpvztl21ybsmS9RVqaYhV8ZtA353n4HgACJwEAAjDUnRGOYUDc7Hyw5TQE", + ) + bot.send_message(call.message.chat.id, "Прогнал бедную собачку(") + return + elif data[1] == "friend": + date = datetime.utcfromtimestamp(call.message.date) + current_time = datetime.utcnow() + time_difference = current_time - date + + if time_difference >= timedelta(minutes=1): + bot.delete_message(call.message.chat.id, call.message.id) + bot.answer_callback_query( + call.id, "Пока ты думал псина сбежала", show_alert=True + ) + return + + item = get_or_add_user_item(user, "кость") + + if item.quantity <= int(data[2]): + bot.answer_callback_query( + call.id, + f"Тебе не хватает 🦴, нужно {data[2]} а у тебя {item.quantity}", + show_alert=True, + ) + return + + dog = DogModel(user=user) + dog.name = f"Собачка-{user.id}" + database.dogs.add(**dog.to_dict()) + + bot.delete_message(call.message.chat.id, call.message.id) + bot.send_sticker( + call.message.chat.id, + "CAACAgIAAxkBAAEpvz9l211Kyfi280mwFR6XMKUhzMXbiwACGAEAAjDUnREiQ2-IziTqFTQE", + ) + bot.send_message( + call.message.chat.id, + "Завел собачку 🐶\n\nНапиши /rename_dog [имя] чтобы дать имя пёсику", + ) + return + elif data[1] == "feed" and dog: + if dog.hunger == 0: + bot.answer_callback_query( + call.id, f"{dog.name} не голоден", show_alert=True + ) + return + item = get_or_add_user_item(user, "мясо") + + quantity = dog.level * 2 + + if item.quantity < quantity: + bot.answer_callback_query( + call.id, + f"Тебе не хватает мяса, нужно {quantity} а у тебя {item.quantity}", + show_alert=True, + ) + return + item.quantity -= quantity + count = random.randint(1, 10) + dog.hunger -= count + dog.xp += random.uniform(0.1, 0.3) + bot.answer_callback_query( + call.id, + f"{dog.name} поел мяса и востановил {count} едениц голода", + show_alert=True, + ) + database.dogs.update(**dog.to_dict()) + database.items.update(**item.to_dict()) + + check_user_stats(user, call.message.chat.id) + + mess = ( + f"{dog.name}\n\n" + f"Здоровье: {dog.health}\n" + f"Усталость: {dog.fatigue}\n" + f"Голод: {dog.hunger}\n" + f"Уровень: {dog.level}\n" + f"Опыт {int(dog.xp)}/{int(dog.max_xp)}\n" + ) + + markup = quick_markup( + { + "Кормить": {"callback_data": f"dog feed {user.id}"}, + # "Уложить спать": {"callback_data": f"dog sleep {user.id}"} + } + ) + bot.edit_message_text( + mess, call.message.chat.id, call.message.id, reply_markup=markup + ) + elif data[1] == "sleep" and dog: + current_time = datetime.utcnow() + time_difference = current_time - dog.sleep_time + if time_difference <= timedelta(minutes=1): + bot.answer_callback_query( + call.id, + f"{dog.name} спит, жди {get_time_difference_string(time_difference - timedelta(minutes=1))}", + show_alert=True, + ) + return + + dog.sleep_time = datetime.utcnow() + time_difference = current_time - dog.sleep_time + + bot.answer_callback_query( + call.id, + f"{dog.name} пошел спать, проснется через {get_time_difference_string(time_difference - timedelta(hours=1))}", + show_alert=True, + ) + elif data[1] == "wakeup" and dog: + bot.answer_callback_query( + call.id, f"{dog.name} проснулся", show_alert=True) + dog.sleep_time = datetime.utcnow() + + database.users.update(**user.to_dict()) + if dog: + database.dogs.update(**dog.to_dict()) + check_user_stats(user) + + +@bot.callback_query_handler(lambda c: c.data.startswith("skip_quest")) +def new_quest_callback(call: CallbackQuery): + if call.data.split(" ")[-1] != str(call.from_user.id): + return + + if not isinstance(call.message, Message): + return + + user = database.users.get(id=call.from_user.id) + + if not user.new_quest_coin_quantity: + user.new_quest_coin_quantity = 2 + + if user.new_quest_coin_quantity > user.coin: + bot.answer_callback_query( + call.id, + f"У тебя недостатично бабла. Чтобы получить ноый квест надо иметь {user.new_quest_coin_quantity}", + show_alert=True, + ) + return + + generate_quest(user) + user.coin -= user.new_quest_coin_quantity + user.new_quest_coin_quantity += random.randint(10, 20) + database.users.update(**user.to_dict()) + + bot.answer_callback_query( + call.id, + "Ты получил новый квест, напиши /quest чтобы посмотреть", + show_alert=True, + ) + + +@bot.callback_query_handler(lambda c: c.data.startswith("finish_quest")) +def finish_quest_callback(call: CallbackQuery): + if call.data.split(" ")[-1] != str(call.from_user.id): + return + + if not isinstance(call.message, Message): + return + + user = database.users.get(id=call.from_user.id) + + try: + quest = database.quests.get(**{"owner": user._id}) + except NoResult: + quest = generate_quest(user) + + item = get_or_add_user_item(user, quest.name) + + if item.quantity < quest.quantity: + bot.answer_callback_query( + call.id, "Кудааа, тебе не хватает", show_alert=True) + return + + item.quantity -= quest.quantity + user.xp += quest.xp + user.coin += quest.reward + database.users.update(**user.to_dict()) + database.items.update(**item.to_dict()) + + mess = ( + "Ураа, ты завершил квест\n" + f"+ {int(quest.xp)} хп\n" + f"+ {quest.reward} бабло {get_item_emoji('бабло')}\n\n" + "Ты выполнил квест за " + ) + + total_time: timedelta = datetime.utcnow() - quest.start_time + mess += get_time_difference_string(total_time) + + generate_quest(user) + bot.delete_message(call.message.chat.id, call.message.id) + + user_message = call.message.reply_to_message + bot.send_sticker( + call.message.chat.id, + "CAACAgIAAxkBAAEpslFl2JwAAaZFMa3RM-3fKaHU7RYrOSQAAoIPAAJ73EFKS4aLwGmJ_Ok0BA", + ) + if user_message: + bot.reply_to(user_message, mess) + else: + bot.send_message(call.message.chat.id, mess) + + check_user_stats(user, call.message.chat.id) + + +@bot.callback_query_handler(lambda c: c.data.startswith("use")) +def use_callback(call: CallbackQuery): + if call.data.split(" ")[-1] != str(call.from_user.id): + return + + user = database.users.get(id=call.from_user.id) + + item = get_item(call.data.split(" ")[1]) + + if not call.message.reply_to_message: + return + + use_item(call.message.reply_to_message, item.name) + + markup = InlineKeyboardMarkup() + buttons = [] + items = get_available_items_for_use(user) + + for user_item in items: + item = get_item(user_item.name) + buttons.append( + InlineKeyboardButton( + f"{item.emoji} {user_item.quantity}", + callback_data=f"use {item.translit()} {user.id}", + ) + ) + + markup.add(*buttons) + + items = get_available_items_for_use(user) + + if not items: + mess = "Нет доступных придметов для юза" + bot.edit_message_text(mess, call.message.chat.id, call.message.id) + + bot.edit_message_reply_markup( + call.message.chat.id, call.message.id, reply_markup=markup + ) + + +@bot.callback_query_handler(lambda c: c.data.startswith("item_info_main")) +def item_info_main_callback(call: CallbackQuery): + if call.data.split(" ")[-1] != str(call.from_user.id): + return + + try: + user = database.users.get(id=call.from_user.id) + action = call.data.split(" ")[1] + pos = int(call.data.split(" ")[2]) + max_pos = len(list(chunks(items_list, 6))) - 1 + + if action == "next": + pos += 1 + elif action == "back": + pos -= 1 + elif action == "start": + pos = 0 + elif action == "end": + pos = max_pos + + if pos < 0: + raise IndexError + + mess = f"Предметы\n\n{pos + 1} / {max_pos + 1}" + markup = InlineMarkup.items_pager(user=user, index=int(pos)) + + bot.edit_message_text( + mess, call.message.chat.id, call.message.id, reply_markup=markup + ) + except (IndexError, ApiTelegramException): + bot.answer_callback_query(call.id, "Дальше ничо нету", show_alert=True) + + +@bot.callback_query_handler(lambda c: c.data.startswith("item_info")) +def item_info_callback(call: CallbackQuery): + if call.data.split(" ")[-1] != str(call.from_user.id): + return + + item = get_item(call.data.split(" ")[1]) + pos = call.data.split(" ")[2] + + markup = quick_markup( + {"Назад": {"callback_data": f"item_info_main None {pos} {call.from_user.id}"}} + ) + + craft = "" + if item.craft: + craft = ", ".join( + [ + f"{get_item_emoji(name)} {name} {count}" + for name, count in item.craft.items() + ] + ) + + mess = ( + f"{item.emoji} {item.name}\n\n" + f"Редкость: {item.rarity.value}\n\n" + f"Описание: {item.desc}\n\n" + + (f"Крафт: {craft}\n" if item.craft else "") + ) + + bot.edit_message_text( + mess, call.message.chat.id, call.message.id, reply_markup=markup + ) + + +@bot.callback_query_handler(lambda c: c.data.startswith("trader")) +def trader_callback(call: CallbackQuery): + data = call.data.split(" ") + if data[-1] != str(call.from_user.id): + return + + if not isinstance(call.message, Message): + return + user = database.users.get(id=call.from_user.id) + + if data[1] == "leave": + bot.delete_message(call.message.chat.id, call.message.id) + bot.send_sticker( + call.message.chat.id, + "CAACAgEAAxkBAAEpxYVl3KqB7JnvbmYgXQqVAhUQYbnyXwACngIAAv9iMUeUcUiHcCrhSTQE", + ) + bot.send_message(call.message.chat.id, "Пф... нехочешь как хочешь") + return + elif data[1] == "trade": + item = get_item(data[2]) + quantity = int(data[3]) + price = int(data[4]) + user_item = get_or_add_user_item(user, item.name) + + if user.coin < price: + bot.answer_callback_query( + call.id, f"Тебе нехватает {price - user.coin} бабла", show_alert=True + ) + return + + user.coin -= price + user_item.quantity += quantity + bot.delete_message(call.message.chat.id, call.message.id) + bot.send_message( + call.message.chat.id, + f"{user.name} купил у торговца {quantity} {item.name} {item.emoji} за {price}", + ) + return + + +@bot.callback_query_handler(lambda c: c.data.startswith("top")) +def top_callback(call: CallbackQuery): + data = call.data.split(" ") + print(data) + if data[-1] != str(call.from_user.id): + return + + markup = quick_markup( + { + "🪙": {"callback_data": f"top coin {call.from_user.id}"}, + "🏵": {"callback_data": f"top level {call.from_user.id}"}, + "🐶": {"callback_data": f"top dog_level {call.from_user.id}"}, + } + ) + + tops = {"coin": coin_top(), "level": level_top(), + "dog_level": dog_level_top()} + + try: + bot.edit_message_text( + tops[data[1]], call.message.chat.id, call.message.id, reply_markup=markup + ) + except ApiTelegramException: + pass + + +@bot.callback_query_handler(lambda c: c.data.startswith("chest")) +def chest_callback(call: CallbackQuery): + data = call.data.split(" ") + + if data[-1] != str(call.from_user.id): + return + + if not isinstance(call.message, Message): + return + user = database.users.get(id=call.from_user.id) + + if data[1] == "open": + key = get_or_add_user_item(user, "ключ") + if key.quantity < 1: + bot.answer_callback_query( + call.id, "У тебя нет ключа", show_alert=True) + return + key.quantity -= 1 + mess = "Открыл сундук\n\n" + items = [] + for _ in range(random.randint(2, 7)): + rarity = random.choice( + [ + ItemRarity.COMMON, + ItemRarity.UNCOMMON, + ] + ) + quantity = get_item_count_for_rarity(rarity) + item = random.choice( + [ + item + for item in items_list + if item.rarity == rarity and item.name != "бабло" + ] + ) + if item.name in items or quantity < 1: + continue + items.append(item.name) + mess += f"+ {quantity} {item.name} {item.emoji}\n" + user_item = get_or_add_user_item(user, item.name) + user_item.quantity += quantity + bot.delete_message(call.message.chat.id, call.message.id) + if call.message.reply_to_message: + bot.reply_to(call.message.reply_to_message, mess) + else: + bot.send_message(user.id, mess) + elif data[1] == "leave": + bot.delete_message(call.message.chat.id, call.message.id) + if call.message.reply_to_message: + bot.reply_to(call.message.reply_to_message, "*Ушел от сундука*") + + +@bot.callback_query_handler(lambda c: c.data.startswith("guide")) +def guide_callback(call: CallbackQuery): + data = call.data.split(" ") + + if data[-1] != str(call.from_user.id): + return + + main_markup = quick_markup( + { + "Для новичков ✨": {"callback_data": f"guide beginner {call.from_user.id}"}, + "Для продвинутых 🔫": { + "callback_data": f"guide advanced {call.from_user.id}" + }, + "Остальное 🧩": {"callback_data": f"guide other {call.from_user.id}"}, + }, + row_width=1, + ) + main_mess = "Гайд по LiveBot 🍃" + + markup = InlineKeyboardMarkup(row_width=2) + if data[1] in ["beginner", "advanced", "other"]: + guide = toml.load(GUIDE_FILE_PATH) + + buttons = [] + + for topic in guide[data[1]]: + buttons.append( + InlineKeyboardButton( + topic, + callback_data=f"guide {data[1]}_{topic.replace(' ', '-')} {call.from_user.id}", + ) + ) + + markup.add(*buttons) + markup.row( + InlineKeyboardButton( + "Назад", callback_data=f"guide back {call.from_user.id}" + ) + ) + bot.edit_message_text( + chat_id=call.message.chat.id, + message_id=call.message.message_id, + text=main_mess, + reply_markup=markup, + ) + elif "_" in data[1]: + category, topic = data[1].split("_", 1) + guide = toml.load(GUIDE_FILE_PATH) + + topic = topic.replace("-", " ") + + if category == "beginner": + ru_category = "Для новичков" + elif category == "advanced": + ru_category = "Для продвинутых" + elif category == "other": + ru_category = "Остальное" + + text = ( + f"{ru_category} >> {topic}\n\n" + f"{topic.upper()}\n\n" + f"{guide[category][topic]}" + ) + + markup.row( + InlineKeyboardButton( + text="Назад", callback_data=f"guide {category} {call.from_user.id}" + ) + ) + bot.edit_message_text( + chat_id=call.message.chat.id, + message_id=call.message.message_id, + text=text, + reply_markup=markup, + ) + elif data[1] == "back": + bot.edit_message_text( + chat_id=call.message.chat.id, + message_id=call.message.message_id, + text=main_mess, + reply_markup=main_markup, + ) + + +@bot.callback_query_handler(lambda c: c.data.startswith("actions")) +def actions_callback(call: CallbackQuery): + data = call.data.split(" ") + + if data[-1] != str(call.from_user.id): + return + + user = database.users.get(id=call.from_user.id) + + if data[1] == "choice": + markup = InlineMarkup.actions_choice(user) + + mess = "Чем хочешь заняться?" + + bot.edit_message_text( + mess, call.message.chat.id, call.message.id, reply_markup=markup + ) + elif data[1] == "back": + markup = InlineMarkup.home_main(user) + mess = "🏠 Дом милый дом" + bot.edit_message_text( + mess, call.message.chat.id, call.message.id, reply_markup=markup + ) + elif data[1] == "street": + street(call, user) + elif data[1] == "work": + work(call, user) + elif data[1] == "sleep": + sleep(call, user) + elif data[1] == "game": + game(call, user) + + +@bot.callback_query_handler(lambda c: c.data.startswith("open")) +def open_callback(call: CallbackQuery): + data = call.data.split(" ") + + if data[-1] != str(call.from_user.id): + return + + user = database.users.get(id=call.from_user.id) + + if data[1] == "home": + mess = "🏠 Дом милый дом" + markup = InlineMarkup.home_main(user) + bot.edit_message_text( + mess, call.message.chat.id, call.message.id, reply_markup=markup + ) diff --git a/src/bot/handlers.py b/src/bot/handlers.py index ec5eb84..17efe0d 100644 --- a/src/bot/handlers.py +++ b/src/bot/handlers.py @@ -1,16 +1,1048 @@ -from telebot.types import Message +import random +import string +from datetime import datetime, timedelta +from typing import List -from config import bot +from telebot.types import ( + Message, + InlineKeyboardButton, + InlineKeyboardMarkup, + ReplyKeyboardMarkup, + KeyboardButton,) +from telebot.util import ( + extract_arguments, + user_link, + quick_markup, + content_type_media, + antiflood, + chunks, +) +from telebot.apihelper import ApiTelegramException + +from helpers.exceptions import NoResult +from base.items import items_list +from helpers.markups import InlineMarkup +from helpers.utils import ( + get_time_difference_string, + get_item_emoji, + get_item, + Loading, +) +from base.player import ( + check_user_stats, + coin_top, + get_available_crafts, + generate_quest, + generate_exchanger, + get_available_items_for_use, + get_or_add_user_item, +) +from base.weather import get_weather + +from database.funcs import database +from database.models import ItemModel, PromoModel + +from config import bot, event_end_time, event_open, channel_id, chat_id, logger + + +START_MARKUP = ReplyKeyboardMarkup(resize_keyboard=True) +if event_open: + START_MARKUP.add(KeyboardButton("Ивент")) + +START_MARKUP.add( + *[ + KeyboardButton("Профиль"), + KeyboardButton("Дом"), + KeyboardButton("Инвентарь"), + KeyboardButton("Квест"), + KeyboardButton("Магазин"), + KeyboardButton("Верстак"), + KeyboardButton("Рейтинг"), + KeyboardButton("Юз"), + KeyboardButton("Статы"), + KeyboardButton("Погода"), + KeyboardButton("Обменник"), + KeyboardButton("Гайд"), + ] +) @bot.message_handler(commands=["start"]) -def start_cmd(message: Message): - bot.reply_to(message, f"Hello {message.from_user.full_name}") +def start(message: Message): + with Loading(message): + user_id = message.from_user.id + + user = database.users.get(id=message.from_user.id) + + mess = ( + f"Здарова {message.from_user.first_name}, добро пожаловать в игру\n\n" + "Канал: @LiveBotOfficial\n" + "Чат: @LiveBotOfficialChat\n" + "Гайд: /guide" + ) + + if len(message.text.split("/start ")) != 1: # pyright: ignore + param = message.text.split("/start ")[1] # pyright: ignore + users_id = [str(user.id) for user in database.users.get_all()] + + if param in users_id: + if str(user_id) == param: + bot.reply_to(message, mess) + return + if user is not None: + bot.reply_to(message, mess) + return + ref_user = user = database.users.get(id=param) + if not ref_user: + bot.reply_to(message, mess, reply_markup=START_MARKUP) + return + user = database.users.get(id=message.from_user.id) + + coin = random.randint(5000, 15000) + ref_user.coin += coin + database.users.update(**ref_user.to_dict()) + bot.send_message( + ref_user.id, + ( + f"{user.name} присоеденился к игре блогодаря твой реферальной ссылке\n" + f"Ты получил {coin} бабла {get_item_emoji('бабло')}" + ), + ) + return + + if message.chat.type != "private": + markup = ReplyKeyboardMarkup() + else: + markup = START_MARKUP + + bot.reply_to(message, mess, reply_markup=markup) + + +@bot.message_handler(commands=["help"]) +def help(message: Message): + mess = ( + "Помощь\n\n" + "Канал: @LiveBotOfficial\n" + "Чат: @LiveBotOfficialChat\n" + "Гайд: /guide\n" + ) + + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["profile"]) +def profile_cmd(message: Message): + with Loading(message): + if message.reply_to_message: + user = user = database.users.get( + id=message.reply_to_message.from_user.id) + else: + user = database.users.get(id=message.from_user.id) + + check_user_stats(user, message.chat.id) + + mess = ( + f"Профиль {user.name}\n\n" + f"❤️ Здоровье: {user.health}\n" + f"🎭 Настроение: {user.mood}\n" + f"💤 Усталость: {user.fatigue}\n" + f"🍞 Голод: {user.hunger}\n" + f"🪙 Бабло: {user.coin}\n" + f"🏵 Уровень: {user.level}\n" + f"🎗 Опыт {int(user.xp)}/{int(user.max_xp)}\n" + ) + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["bag"]) +def bag_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + mess = "Рюкзак\n\n" + inventory = database.items.get_all(**{"owner": user._id}) + if not inventory: + mess += "Пусто..." + else: + sorted_items = sorted( + inventory, key=lambda item: item.quantity, reverse=True + ) + + for item in sorted_items: + if item.quantity <= 0: + continue + mess += f"{get_item_emoji(item.name)} {item.name} - {item.quantity}\n" + + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["items"]) +def items_cmd(message: Message): + with Loading(message): + mess = f"Предметы\n\n1 / {len(list(chunks(items_list, 6)))}" + user = database.users.get(id=message.from_user.id) + markup = markup = InlineMarkup.items_pager(user=user) + + bot.reply_to(message, mess, reply_markup=markup) + + +@bot.message_handler(commands=["shop"]) +def shop_cmd(message: Message): + with Loading(message): + args = str(message.text).split(" ") + + if len(args) != 3: + mess = "🛍Магазин🛍\n\n" + for item in items_list: + if not item.price: + continue + + mess += f"{item.emoji} {item.name} - {item.price}/шт.\n" + bot.reply_to(message, mess) + return + + err_mess = "Что-то не так написал\n" "Надо: /shop буханка 10" + + if len(args) != 3: + bot.reply_to(message, err_mess) + return + + user = database.users.get(id=message.from_user.id) + + item_name = args[1] + try: + count = int(args[2]) + except (ValueError, IndexError): + count = 1 + + if not get_item(item_name): + bot.reply_to(message, "Такого придмета не существует") + return + + item = get_item(item_name) + + if not item.price: + bot.reply_to( + message, "Этот придмет нельзя купить, у него нет цены") + return + + price = item.price * count + if user.coin < price: + bot.reply_to(message, "У тебя нет столько бабла, иди работать") + return + + user.coin -= price + user_item = get_or_add_user_item(user, get_item(item.name).name) + + user_item.quantity += count + database.users.update(**user.to_dict()) + database.items.update(**user_item.to_dict()) + + bot.reply_to( + message, + f"Купил {count} {item.name} {get_item_emoji(item.name)} за {price} {get_item_emoji('бабло')}", + ) + + +@bot.message_handler(commands=["casino"]) +def casino(message: Message): + with Loading(message): + count = extract_arguments(str(message.text)) + + if count == "": + mess = ( + "🎰Казино🎰\n\n" + "Решил заработать легкие деньги? Ну давай\n" + "Шансы 50 на 50\n" + "Чтобы сыграть напиши /casino кол-во" + ) + bot.reply_to(message, mess) + return + + try: + count = int(count) + except ValueError: + count = 1 + + user = database.users.get(id=message.from_user.id) + + ticket = get_or_add_user_item(user, "билет") + + if (not ticket) or (ticket.quantity <= 0): + bot.reply_to( + message, + f"Чтобы сыграть в казино у тебя должен быть билет {get_item_emoji('билет')}", + ) + return + + chance = random.randint(0, 10) + + if count > user.coin: + bot.reply_to( + message, + f"Нифига се цифры, у тебя есть только {user.coin} {get_item_emoji('бабло')}", + ) + return + + if count <= 0: + count = 1 + + if user.coin <= 0: + bot.reply_to(message, "Кудаа, у тебя нет бабла, иди работать") + return + + bot.send_dice(message.chat.id, "🎲") + ticket.quantity -= 1 + if chance <= 5: + bot.send_message(message.chat.id, f"Блин, сорян\n——————\n-{count}") + user.coin -= count + user.casino_loose += count + + else: + bot.send_message( + message.chat.id, f"Нифига се\n——————\n+{count * 2}") + user.coin += count * 2 + user.casino_win += count * 2 + + database.users.update(**user.to_dict()) + database.items.update(**ticket.to_dict()) + check_user_stats(user, message.chat.id) + + +@bot.message_handler(commands=["workbench", "craft"]) +def workbench_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + mess = ( + "🧰Верстак🧰\n\n" + "Чтобы скрафтить чтото то напиши /craft буханка 1\n\n" + ) + + args = str(message.text).split(" ") + + if not args or len(args) < 2: + available_crafts = get_available_crafts(user) + if available_crafts: + mess += "Доступные крафты\n" + for craft_data in available_crafts: + item_name = craft_data["item_name"] + resources = craft_data["resources"] + + possible_crafts = min( + user_count // count for _, count, user_count in resources + ) + craft_str = ( + f"{get_item_emoji(item_name)} {item_name} - {possible_crafts}\n" + ) + mess += f"{craft_str}" + + bot.reply_to(message, mess) + return + + name = args[1].lower() + try: + count = int(args[2]) + except (ValueError, IndexError): + count = 1 + + if not get_item(name): + bot.reply_to(message, "Такого придмета не существует") + return + + item_data = get_item(name) + + if not item_data.craft: + bot.reply_to(message, f"У {item_data.emoji} нет крафта") + return + + craft = item_data.craft + + for craft_item in craft.items(): + user_item = get_or_add_user_item(user, craft_item[0]) + if ( + (not user_item) + or (user_item.quantity <= 0) + or (user_item.quantity < craft_item[1] * count) + ): + bot.reply_to(message, "Недостатично придметов") + return + + user_item.quantity -= craft_item[1] * count + database.items.update(**user_item.to_dict()) + + item = get_or_add_user_item(user, name) + + item.quantity += count + xp = random.uniform(5.0, 10.0) * count + user.xp += xp + + database.items.update(**item.to_dict()) + database.users.update(**user.to_dict()) + bot.reply_to( + message, f"Скрафтил {count} {name} {get_item_emoji(name)}\n+ {int(xp)} хп" + ) + + check_user_stats(user, message.chat.id) + + +@bot.message_handler(commands=["transfer"]) +def transfer_cmd(message: Message): + with Loading(message): + if not message.reply_to_message: + bot.reply_to(message, "Кому кидать собрался??") + return + + user = database.users.get(id=message.from_user.id) + reply_user = database.users.get( + id=message.reply_to_message.from_user.id) + + args = message.text.split(" ") + + err_mess = ( + "Что-то не так написал, надо так:\n" "/transfer буханка 10" + ) + + if len(args) < 2: + bot.reply_to(message, err_mess) + return + + item = args[1].lower() + try: + count = int(args[2]) + except (ValueError, IndexError): + count = 1 + + if item != "бабло": + item_data = get_or_add_user_item(user, item) + reply_user_item_data = get_or_add_user_item(reply_user, item) + logger.debug(item_data.quantity) + logger.debug(count) + + if item == "бабло": + if user.coin <= 0: + bot.reply_to(message, f"У тебя нет {item}") + return + elif user.coin <= count: + bot.reply_to( + message, "У тебя недостатично бабла, иди работать") + return + user.coin -= count + reply_user.coin += count + else: + if not get_item(item): + bot.reply_to( + message, f"{item}??\nСерёзно?\n\nТакого придмета не существует" + ) + return + if (item_data.quantity < count) or (item_data.quantity <= 0): + bot.reply_to(message, f"У тебя нет {item}") + logger.debug(item_data.quantity) + logger.debug(count) + return + + item_data.quantity -= count + reply_user_item_data.quantity += count + database.items.update(**reply_user_item_data.to_dict()) + database.items.update(**item_data.to_dict()) + + mess = ( + f"{user.name} подарил {reply_user.name}\n" + "----------------\n" + f"{get_item_emoji(item)} {item} {count}" + ) + + database.users.update(**user.to_dict()) + database.users.update(**reply_user.to_dict()) + + bot.send_message(message.chat.id, mess) + + +@bot.message_handler(commands=["event"]) +def event_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + if event_open is False: + bot.reply_to(message, "Ивент закончился") + return + + if event_end_time < datetime.utcnow(): + mess = "Ивент закончился, жди сообщение в новостном канале 💙" + bot.reply_to(message, mess) + return + + time_difference = event_end_time - datetime.utcnow() + time_left = get_time_difference_string(time_difference) + + mess = ( + "Ивент 🦋\n\n" + "Соберай 🦋 и побеждай\n\n" + "Бабочек можно получать во время прогулки, в боксе и в сундуке\n\n" + f"До окончания осталось: {time_left}\n\n" + "Топ 10 по 🦋\n\n" + ) + + butterflys = [ + get_or_add_user_item(user, "бабочка") for user in database.users.get_all() + ] + sorted_butterflys: List[ItemModel] = sorted( + butterflys, key=lambda butterfly: butterfly.quantity, reverse=True + ) + for index, butterfly in enumerate(sorted_butterflys, start=1): + if butterfly.quantity > 0: + owner = database.users.get(**{"_id": butterfly.owner}) + mess += f"{index}. {owner.name or 'неопознаный персонаж'} - {butterfly.quantity}\n" + if index == 10: + break + + butterfly = get_or_add_user_item(user, "бабочка") + mess += f"\n\nТы собрал: {butterfly.quantity}" + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["top"]) +def top_cmd(message: Message): + with Loading(message): + mess = coin_top() + + markup = quick_markup( + { + "🪙": {"callback_data": f"top coin {message.from_user.id}"}, + "🏵": {"callback_data": f"top level {message.from_user.id}"}, + "🐶": {"callback_data": f"top dog_level {message.from_user.id}"}, + } + ) + + bot.reply_to(message, mess, reply_markup=markup) + + +@bot.message_handler(commands=["use"]) +def use_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + args = str(message.text).split(" ") + + if len(args) < 2: + markup = InlineKeyboardMarkup() + buttons = [] + items = get_available_items_for_use(user) + + for user_item in items: + item = get_item(user_item.name) + buttons.append( + InlineKeyboardButton( + f"{item.emoji} {user_item.quantity}", + callback_data=f"use {item.translit()} {user.id}", + ) + ) + + markup.add(*buttons) + + if items: + mess = "Доступные придметы для юза\n\n" + else: + mess = "Нет доступных придметов для юза" + bot.reply_to(message, mess, reply_markup=markup) + return + + +@bot.message_handler(commands=["ref"]) +def ref(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + mess = ( + "Хочешь заработать?\n" + "Ты по адресу, пригласи друзей и получи от 5к до 15к бабла\n" + f"Вот твоя ссылочка: https://t.me/{bot.get_me().username}?start={user.id}" + ) + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["add_promo"]) +def add_promo(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + if not user.is_admin: + return + + chars = string.digits + string.ascii_letters + promo = "".join(random.choices(chars, k=6)) + try: + promo_code = database.promos.get(name=promo) + except NoResult: + promo_code = None + + if promo_code: + promo = "".join(random.choices(chars, k=6)) + mess = "Новый промокод\n\n" f"Код: {promo}\n" + + items = {} + usage_count = 1 + description = None + + line_num = 0 + for line in str(message.text).split("\n"): + if line_num == 0: + try: + usage_count = int(line.split(" ")[-1]) + except ValueError: + usage_count = 1 + mess += f"Кол-во использованый: {usage_count}\n" + elif line_num == 1: + description = None if line in ["None", "none"] else line + if description: + mess += f"Описание: {description}\n\n" + elif line_num == 2: + for item in line.split(", "): + name = item.split(" ")[0] + quantity = int(item.split(" ")[1]) + name = name.lower() + if get_item(name): + items[name] = quantity + mess += ( + f"{quantity} {get_item(name).name} {get_item(name).emoji}\n" + ) + + line_num += 1 + + code = PromoModel( + name=promo, usage_count=usage_count, description=description, items=items + ) + + database.promos.add(**code.to_dict()) + + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["promo"]) +def promo(message: Message) -> None: + with Loading(message): + user = database.users.get(id=message.from_user.id) + + tg_user = bot.get_chat_member(channel_id, message.from_user.id) + chat_info = bot.get_chat(channel_id) + bot.delete_message(message.chat.id, message.id) + if tg_user.status not in ["member", "administrator", "creator"]: + markup = quick_markup( + {"Подписатся": {"url": f"t.me/{chat_info.username}"}}) + bot.send_message( + message.chat.id, + "Чтобы активировать промо нужно подписатся на новостной канал", + reply_markup=markup, + ) + return + + text = str(message.text).split(" ") + + if len(text) != 1: + text = text[1] + + code = database.promos.get(name=text) + if code: + promo_users = code.users + if user.id in promo_users: + bot.send_message( + message.chat.id, "Ты уже активировал этот промокод" + ) + return + + if code.is_used: + bot.send_message( + message.chat.id, "Этот промокод уже активировали") + return + + code.usage_count -= 1 + + if code.usage_count <= 0: + code.usage_count = 0 + code.is_used = True + + mess = f"Ухтыы, {user.name} активировал промо и получил\n\n" + for item in code.items: + if item == "бабло": + user.coin += code.items[item] + database.users.update(**user.to_dict()) + else: + user_item = get_or_add_user_item(user, item) + user_item.quantity += code.items[item] + database.items.update(**user_item.to_dict()) + mess += f"+ {code.items[item]} {item} {get_item_emoji(item)}\n" + promo_users.append(user.id) + code.users = promo_users + + database.promos.update(**code.to_dict()) + bot.send_sticker( + message.chat.id, + "CAACAgIAAxkBAAEpjI9l0i13xK0052Ruta0D5a5lWozGBgACHQMAAladvQrFMjBk7XkPEzQE", + ) + bot.send_message(message.chat.id, mess) + else: + bot.send_message( + message.chat.id, "Такого промокода не существует") + + +@bot.message_handler(commands=["stats"]) +def stats_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + mess = ( + "Статистика\n\n\n" + f"[ Казино ]\n" + f"- Выиграл: {user.casino_win}\n" + f"- Просрал: {user.casino_loose}\n" + f"- Профит: {user.casino_win - user.casino_loose}\n\n" + f"[ Общее ]\n" + f"- Кол-во дней в игре: {(datetime.utcnow() - user.registered_at).days} д.\n" + f"- Забанен: {'да' if user.is_banned else 'нет'}\n" + f"- Админ: {'да' if user.is_admin else 'нет'}" + ) + + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["quest"]) +def quest_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + try: + quest = database.quests.get(**{"owner": user._id}) + except NoResult: + quest = None + + if not quest: + quest = generate_quest(user) + if not user.new_quest_coin_quantity: + user.new_quest_coin_quantity = 2 + + item = get_or_add_user_item(user, quest.name) + + finish_button_text = ( + f"{item.quantity} / {quest.quantity}" + if item.quantity < quest.quantity + else "Завершить" + ) + markup = InlineKeyboardMarkup() + markup.add( + *[ + InlineKeyboardButton( + finish_button_text, callback_data=f"finish_quest {user.id}" + ), + InlineKeyboardButton( + "Пропуск", callback_data=f"skip_quest {user.id}"), + ] + ) + + mess = ( + "Квест\n\n" + f"Собери {quest.quantity} {quest.name} {get_item_emoji(quest.name)}\n\n" + f"Награда: {quest.reward} {get_item_emoji('бабло')}" + ) + + bot.reply_to(message, mess, reply_markup=markup) + + +@bot.message_handler(commands=["weather"]) +def weather_cmd(message: Message): + with Loading(message): + weather = get_weather() + + mess = ( + f"Прогноз погоды\n\n" + f"{weather.main.temp} °C\n" + f"{weather.weather.ru_name}" + ) + + try: + bot.send_photo( + message.chat.id, + f"http://openweathermap.org/img/wn/{weather.weather.icon}@2x.png", + caption=mess, + ) + except Exception: + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["exchanger"]) +def exchanger_cmd(message: Message): + # if True: + # bot.reply_to(message, "Временно не работает изза багов :(") + # return + with Loading(message): + user = database.users.get(id=message.from_user.id) + + if user.level < 5: + bot.reply_to(message, "Обменник доступен с 5 уровня") + return + + try: + exchanger = database.exchangers.get(**{"owner": user._id}) + except NoResult: + exchanger = None + + if not exchanger: + exchanger = generate_exchanger(user) + database.exchangers.update(**exchanger.to_dict()) + + if (datetime.utcnow() - exchanger.last_update) >= timedelta(days=1): + exchanger = generate_exchanger(user) + database.exchangers.update(**exchanger.to_dict()) + + mess = ( + "Обменник 🔄\n\n" + f"Предмет: {exchanger.item} {get_item_emoji(exchanger.item)}\n" + f"Цена за 1 шт: {exchanger.price} {get_item_emoji('бабло')}\n\n" + f"Чтобы обеменять напиши /exchanger кол-во" + ) + + args = str(message.text).split(" ") + + if len(args) < 2: + bot.reply_to(message, mess) + return + + try: + quantity = int(args[1]) + except (ValueError, IndexError): + quantity = 1 + + user_item = get_or_add_user_item(user, exchanger.item) + + if not user_item: + bot.reply_to( + message, f"У тебя нет {get_item_emoji(exchanger.item)}") + return + + if user_item.quantity < quantity: + bot.reply_to(message, "Тебе не хватает") + return + + coin = quantity * exchanger.price + user.coin += coin + user_item.quantity -= quantity + + database.users.update(**user.to_dict()) + database.items.update(**user_item.to_dict()) + + bot.reply_to( + message, + f"Обменял {quantity} {get_item_emoji(exchanger.item)} за {coin} {get_item_emoji('бабло')}", + ) + + +@bot.message_handler(commands=["dog"]) +def dog_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + try: + dog = database.dogs.get(**{"owner": user._id}) + print(dog.to_dict()) + except NoResult: + dog = None + + if not dog: + bot.reply_to(message, "У тебя нет собачки") + return + + mess = ( + f"{dog.name}\n\n" + f"Здоровье: {dog.health}\n" + f"Усталость: {dog.fatigue}\n" + f"Голод: {dog.hunger}\n" + f"Уровень: {dog.level}\n" + f"Опыт {int(dog.xp)}/{int(dog.max_xp)}\n" + ) + + # current_time = datetime.utcnow() + # time_difference = current_time - user.dog.sleep_time + + # sleep_text = "Уложить спать" + # sleep_callback = f"dog sleep {user.id}" + # if time_difference <= timedelta(minutes=1): + # sleep_text = "Пробудить" + # sleep_callback = f"dog wakeup {user.id}" + + markup = quick_markup( + { + "Кормить": {"callback_data": f"dog feed {user.id}"}, + # sleep_text: {"callback_data": sleep_callback} + } + ) + + bot.reply_to(message, mess, reply_markup=markup) + + +@bot.message_handler(commands=["rename_dog"]) +def rename_dog_command(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + + try: + dog = database.dogs.get(**{"owner": user._id}) + except NoResult: + dog = None + + if not dog: + bot.reply_to(message, "У тебя нет собачки") + return + + try: + name = message.text.split(" ")[1] # pyright: ignore + except KeyError: + bot.reply_to(message, "По моему ты забыл написать имя") + return + + dog.name = name + database.dogs.update(**dog.to_dict()) + + bot.reply_to(message, "Переименовал собачку") + + +@bot.message_handler(commands=["price"]) +def price_cmd(message: Message): + with Loading(message): + try: + name = str(message.text).split(" ")[1].lower() + except KeyError: + bot.reply_to(message, "По моему ты чтото забыл...") + return + + item = get_item(name) + if not item: + mess = "Такого придмета не существует" + elif item.price: + mess = f"Прайс {item.name} {item.emoji} ⸻ {item.price} {get_item_emoji('бабло')}" + else: + mess = f"У {item.emoji} нет прайса" + + bot.reply_to(message, mess) + + +@bot.message_handler(commands=["home"]) +def home_cmd(message: Message): + with Loading(message): + user = database.users.get(id=message.from_user.id) + mess = "🏠 Дом милый дом" + + markup = InlineMarkup.home_main(user) + + bot.reply_to(message, mess, reply_markup=markup) + + +@bot.message_handler(commands=["guide"]) +def guide_cmd(message: Message): + with Loading(message): + mess = "Гайд по LiveBot 🍃" + + markup = quick_markup( + { + "Для новичков ✨": { + "callback_data": f"guide beginner {message.from_user.id}" + }, + "Для продвинутых 🔫": { + "callback_data": f"guide advanced {message.from_user.id}" + }, + "Остальное 🧩": { + "callback_data": f"guide other {message.from_user.id}" + }, + }, + row_width=1, + ) + + bot.send_message(message.chat.id, mess, reply_markup=markup) + + +@bot.message_handler(commands=["market"]) +def market_cmd(message: Message): + user = database.users.get(id=message.from_user.id) + + if user.level < 10: + bot.reply_to(message, "Нужно иметь 10+ лвл") + return + + database.markets.get_all() + database.markets.get(owner=user._id) # ---------------------------------------------------------------------------- # -@bot.message_handler(func=lambda m: True) -def message_handler(message: Message): - bot.reply_to(message, message.text) +@bot.message_handler(content_types=["new_chat_members"]) +def new_chat_member(message: Message): + if not message.new_chat_members: + return + + for new_member in message.new_chat_members: + if message.chat.id == chat_id: + mess = f"Привет {user_link(new_member)}, добро пожаловать в оффицеальный чат по лайвботу 💙\n\n" + bot.send_message(message.chat.id, mess) + + +@bot.channel_post_handler(content_types=content_type_media) +def handle_channel_post(message: Message): + if str(message.chat.id) != channel_id: + return + + for user in database.users.get_all(): + try: + antiflood(bot.forward_message, user.id, + message.chat.id, message.id) + antiflood( + bot.send_message, + user.id, + "Клавиатура обновлена", + reply_markup=START_MARKUP, + ) + except ApiTelegramException: + continue + + +@bot.message_handler(content_types=["text"]) +def text_message_handler(message: Message): + user = database.users.get(id=message.from_user.id) + + text = str(message.text).lower() + + if text == "профиль": + profile_cmd(message) + elif text in ["инвентарь", "портфель", "инв"]: + bag_cmd(message) + elif text.startswith(("магазин", "шоп")): + shop_cmd(message) + elif text.startswith(("крафт", "верстак")): + workbench_cmd(message) + elif text in ["топ", "рейтинг"]: + top_cmd(message) + elif text == "ивент": + event_cmd(message) + elif text.startswith("юз"): + use_cmd(message) + elif text == "придметы": + items_cmd(message) + elif text == "бабло": + with Loading(message): + bot.reply_to( + message, f"{get_item_emoji('бабло')} Бабло: {user.coin}") + elif text == "статы": + stats_cmd(message) + elif text == "квест": + quest_cmd(message) + elif text == "погода": + weather_cmd(message) + elif text == "обменник": + exchanger_cmd(message) + elif text.startswith("передать"): + transfer_cmd(message) + elif text == "собака": + dog_cmd(message) + elif text.startswith("прайс"): + price_cmd(message) + elif text == "гайд": + guide_cmd(message) + elif text == "дом": + home_cmd(message) diff --git a/src/main.py b/src/main.py index 5e86152..a697542 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,4 @@ -from bot import handlers # noqa +import bot as _ # noqa from middlewares.register import RegisterMiddleware from config import bot, DEBUG, logger