/
github_better
/
GenAI
Обзор
Документация
Войти
/
github_better
/
GenAI
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Stats.py
300 строк
10 KB
github_better
New
22 дек 2025, 08:52
22 дек 2025, 08:52
b68d8c4
Код
Авторство
О чём код?
import re import logging import json import ast from Lib.Translate_text import translate_text from Lib.Debugger import debug_print logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def pretty_stats(stats: str, lang: str) -> str: debug_print(logger) """ Красиво форматирует характеристики персонажа с переводом названий. :param stats: строка со статами в формате ключ:значение :param lang: язык для локализации :return: отформатированная строка характеристик """ # соответствие ключей и человекочитаемых названий labels = { "HP": "Health", "STR": "Strength", "DEX": "Agility", "CON": "Character's physique", "INT": "Mental abilities", "WIS": "Wisdom", "CHA": "Charisma", "MAX_SLOTS": "Max slots", "MAX_WEIGHT": "Max weight" } # находим все пары ключ: значение pairs = re.findall(r'["\']?([A-Z_]+)["\']?\s*[:=]\s*(-?\d+)', stats) if not pairs: return translate_text("Invalid stats format", "en", lang) # собираем красиво lines = [] for key, val in pairs: label = labels.get(key, key) label_tr = translate_text(label, "en", lang) lines.append(f"{label_tr}: {val}") return "\n".join(lines) def pretty_stats_with_numbers(stats: str, lang: str) -> str: debug_print(logger) """ Красиво форматирует характеристики персонажа с переводом названий. :param stats: строка со статами в формате ключ:значение :param lang: язык для локализации :return: отформатированная строка характеристик """ # соответствие ключей и человекочитаемых названий labels = { "HP": "Health", "STR": "Strength", "DEX": "Agility", "CON": "Character's physique", "INT": "Mental abilities", "WIS": "Wisdom", "CHA": "Charisma", "MAX_SLOTS": "Max slots", "MAX_WEIGHT": "Max weight" } # находим все пары ключ: значение pairs = re.findall(r'["\']?([A-Z_]+)["\']?\s*[:=]\s*(-?\d+)', stats) if not pairs: return translate_text("Invalid stats format", "en", lang) # собираем красиво lines = [] i=1 for key, val in pairs: label = labels.get(key, key) label_tr = str(i) + ") " + translate_text(label, "en", lang) lines.append(f"{label_tr}: {val}") i+=1 return "\n".join(lines) def change_stats(old_stats: str, new_stats: str, lang: str) -> str: debug_print(logger) """ Сравнивает старые и новые статы, возвращает список изменений. :param old_stats: старые характеристики :param new_stats: новые характеристики :param lang: язык для локализации :return: строка с изменениями или "-1" если изменений нет """ labels = { "HP": "Health", "STR": "Strength", "DEX": "Agility", "CON": "Body type", "INT": "Mental abilities", "WIS": "Wisdom", "CHA": "Charisma", "MAX_SLOTS": "Max slots", "MAX_WEIGHT": "Max weight" } def __parse_stats(stats_str): """ Парсит строку статов в словарь. :param stats_str: строка со статами :return: словарь характеристик """ return { k: float(v) if "." in v else int(v) for k, v in re.findall(r'["\']?([A-Z_]+)["\']?\s*[:=]\s*(-?\d+(?:\.\d+)?)', stats_str) } old_dict = __parse_stats(old_stats) new_dict = __parse_stats(new_stats) changes = [] for key, old_val in old_dict.items(): new_val = new_dict.get(key, old_val) if new_val != old_val: label = labels.get(key, key) label_tr = translate_text(label, "en", lang) diff = new_val - old_val sign = f"+{diff}" if diff > 0 else str(diff) changes.append(f"{label_tr} {sign}") if not changes: return "-1" header = translate_text("🧭 Changes:", "en", lang) return header + "\n" + "\n".join(changes) def check_hp(stats: str) -> bool: debug_print(logger) """ Проверяет, равно ли HP персонажа нулю (смерть). :param stats: строка характеристик :return: True если HP == 0, иначе False """ match = re.search(r'"?HP"?\s*:\s*(-?\d+)', stats) if match: hp = int(match.group(1)) return hp == 0 return False def get_name_of_stats_from_number(stats_with_number: str, number: int) -> str: debug_print(logger) """ Получаем имя стат исходя из номера :param stats_with_number: красиво отформатированный текст стат с номерами :param number: номер выбранной статы :return: имя статы под нужным номером """ # Ищем все пары (номер, название) matches = re.findall(r"(\d+)[\)\.]?\s*([A-Za-zА-Яа-яЁё\s\-]+):", stats_with_number) for num, name in matches: if int(num) == number: return name.strip() return "-1" def _parse_stats_flexible(stats_raw): debug_print(logger) """ Попытка безопасно распарсить stats из разных возможных форматов: - None -> {} - dict -> вернуть как есть - valid JSON -> json.loads - python-literal (одинарные кавычки) -> ast.literal_eval - fallback: пустой dict :param stats_raw: строка стат (непонятно в каком формате) :return: пытается вернуть нормальный словарь """ if stats_raw is None: return {} if isinstance(stats_raw, dict): return stats_raw if isinstance(stats_raw, (int, float)): # странный случай — не словарь return {} # если это уже строка if isinstance(stats_raw, str): # попытка JSON try: parsed = json.loads(stats_raw) if isinstance(parsed, dict): return parsed except Exception: pass # попытка ast.literal_eval (безопаснее чем eval) try: parsed = ast.literal_eval(stats_raw) if isinstance(parsed, dict): return parsed except Exception: pass # ничего не получилось return {} def change_stats_from_number(sess, stat_number: int, new_stat_value): debug_print(logger) """ Меняет значение нужного стат-параметра по номеру. Возвращает: 1 - успех -1 - неверный номер / параметр отсутствует 0 - общая ошибка / не удалось распарсить :param sess: сессия юзера :param stat_number: номер статы, которую нужно менять :param new_stat_value: новое значение на которое надо менять :return: выше описано """ try: raw = getattr(sess, "current_stats", None) stats = _parse_stats_flexible(raw) except Exception as e: debug_print(logger, "ERROR") return 0 if not isinstance(stats, dict): stats = {} # Сопоставление номеров со статами mapping = { 1: "HP", 2: "STR", 3: "DEX", 4: "CON", 5: "INT", 6: "WIS", 7: "CHA", 8: "MAX_SLOTS", 9: "MAX_WEIGHT" } key = mapping.get(stat_number) if key not in stats: debug_print(logger, f"change_stats_from_number: key %s not found in stats, initializing with 0{key}") stats[key] = 0 # если ключа в stats нет — возвращаем ошибку, но не падаем if key not in stats: logger.warning("change_stats_from_number: key %s not found in stats %r", key, stats) return -1 # Меняем значение — приводим к числу (int если возможно) try: if isinstance(new_stat_value, str) and "." in new_stat_value: val = float(new_stat_value) else: # если число в строке без точки — попробуем int val = int(new_stat_value) except Exception: try: val = float(new_stat_value) except Exception: val = new_stat_value # оставим как есть stats[key] = val # Обновляем строку JSON в сессии — сохраняем как JSON строку try: sess.current_stats = json.dumps(stats, ensure_ascii=False) except Exception: # если нельзя сохранить как JSON — сохраним как repr sess.current_stats = repr(stats) # Если нужно — пересчитать инвентарь (если изменили лимиты) if key in ("MAX_SLOTS", "MAX_WEIGHT"): try: from Lib.Inventory import recalc_inventory_stats sess.current_weight, sess.current_slots = recalc_inventory_stats(sess.current_inventory) except Exception: logger.exception("Failed to recalc inventory after stat change") return 1