Проверь этот код на наличие внутренних ошибок:
import pygame
import sys
import random
import operator
import time
from dataclasses import dataclass, field

# Инициализация Pygame
pygame.init()

# Получение размеров экрана
SCREEN_INFO = pygame.display.Info()
WIDTH, HEIGHT = SCREEN_INFO.current_w, SCREEN_INFO.current_h

# Установка размеров игровых и инвентарных областей
GAME_WIDTH = int(WIDTH * 0.7)  # 70% ширины для игры
MAP_WIDTH = WIDTH - GAME_WIDTH  # 30% для карты и инвентаря
GAME_HEIGHT = HEIGHT - 100  # Оставляем место для консоли

# Установка оконного режима и заголовка
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Математическая Игра с NPC")

# Определение цветов
BLUE = (0, 0, 255)
GREEN = (0, 200, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
YELLOW = (255, 255, 0)
LIGHT_BLUE = (173, 216, 230)
GRAY = (200, 200, 200)
DARK_GRAY = (50, 50, 50)
LIGHT_GRAY = (230, 230, 230)
ORANGE = (255, 165, 0)  # Цвет для 'обиженных' NPC
DUNGEON_COLOR = (128, 0, 128)  # Фиолетовый цвет для подземелий
HEALTH_BAR_COLOR = (255, 0, 0)  # Красный цвет для полосы здоровья
HEALTH_BAR_BG_COLOR = (100, 100, 100)  # Серый фон для полосы здоровья

# Установка FPS и создание таймера
FPS = 60
clock = pygame.time.Clock()

# Настройка шрифтов
font = pygame.font.SysFont(None, 20)
large_font = pygame.font.SysFont(None, 28)
npc_font = pygame.font.SysFont(None, 18)
console_font = pygame.font.SysFont(None, 20)
map_font = pygame.font.SysFont(None, 14)

# Фоновые цвета для территорий
terrain_backgrounds = {
    "Засушливые земли": LIGHT_GRAY,
    "Великие равнины": (144, 238, 144),  # Светло-зеленый
    "Горные пастбища": (169, 169, 169),  # Темно-серый
    "Туманная долина": (176, 224, 230),  # Светло-голубой
}

@dataclass
class Item:
    type: str
    name: str
    stat: str
    value: int

@dataclass
class NPC:
    pos: list
    profession: str
    name: str
    level: int
    task_solved: bool = False
    cooldown: float = 0.0

    def is_interactable(self):
        """Проверяет, может ли игрок взаимодействовать с NPC."""
        return not self.task_solved and time.time() >= self.cooldown

@dataclass
class Region:
    x: int
    y: int
    npcs: list = field(default_factory=list)
    dungeon_entrances: list = field(default_factory=list)

    def generate_npcs(self, npc_professions, calculate_level_fn, generate_npc_position_fn):
        """Генерирует NPC для региона."""
        num_npcs = random.randint(1, 5)
        for _ in range(num_npcs):
            profession = random.choice(npc_professions)
            name = random.choice(Game.names_list)
            level = calculate_level_fn(self.x, self.y)
            pos = generate_npc_position_fn(existing_npcs=self.npcs)
            self.npcs.append(NPC(pos=pos, profession=profession, name=name, level=level))

    def generate_dungeon_entrances(self, generate_dungeon_entrance_position_fn):
        """Генерирует входы в подземелья для региона."""
        if random.random() < 0.2:
            num_entrances = random.randint(1, 2)
            for _ in range(num_entrances):
                pos = generate_dungeon_entrance_position_fn(existing_entrances=self.dungeon_entrances)
                self.dungeon_entrances.append(pos)

@dataclass
class Player:
    pos: list
    color: tuple = BLUE
    size: int = 50
    speed: int = 5
    attack: int = 0
    defense: int = 0
    health: int = 10  # Добавлен параметр Жизнь
    knowledge_level: int = 1
    tasks_solved: int = 0
    tasks_total: int = 0
    tasks_needed: int = 10
    equipped: dict = field(default_factory=lambda: {'Меч': [], 'Щит': None, 'Доспех': None})
    inventory: list = field(default_factory=list)

    def recalculate_stats(self):
        """Пересчитывает параметры атаки и защиты игрока на основе экипированного снаряжения."""
        self.attack = sum(item.value for item in self.equipped['Меч'])
        shield_def = self.equipped['Щит'].value if self.equipped['Щит'] else 0
        armor_def = self.equipped['Доспех'].value if self.equipped['Доспех'] else 0
        self.defense = shield_def + armor_def

@dataclass
class Game:
    world_size: int = 30
    map_tile_size: int = 8
    current_region_coord: tuple = (15, 15)  # Начальная позиция в центре
    regions: dict = field(default_factory=dict)
    terrain_map: dict = field(default_factory=dict)
    console_message: str = ""
    state: str = 'move'  # Возможные состояния: 'move', 'dialog', 'dungeon'
    player: Player = field(default_factory=lambda: Player(pos=[0, 0]))
    inventory_scroll_offset: int = 0
    scroll_step: int = 20
    active_dungeons: dict = field(default_factory=dict)
    current_npc: NPC = None
    current_question: str = ''
    correct_answer: int = 0
    player_answer: str = ''

    # Предопределенные данные для генерации предметов и NPC
    sword_names = [
        "Рубиголов", "Остроклюв", "Буревестник", "ТемнокаменныйКлинок",
        "ЗвёздочёрныйМеч", "ЛунныйКолун", "СолнечныйРазрубатель",
        "ГрозовойКрюк", "ТеневойБлеск", "ТираническийКромкогрив",
        "ИзумрудныйРезак", "Пламеглот", "КристальныйРубанок",
        "БагровыйПырсок", "СапфировыйПрорезинитель"
    ]
    shield_names = [
        "ЧешуяДракона", "ЧерепашийПанцирь", "ОбелисковыйБастион",
        "ГранитнаяКулачность", "ЛедянойЗаслон", "МифриловыйЩит",
        "ЭльфийскаяСтруктура", "БаншейскаяМаржа", "ДревнийБарьер",
        "СтальнойФундамент", "ТитановыйБлеск", "ЖелезныйУсадок",
        "КожаныйПокров", "МагическийЗаслон", "АдамантиновыйЩит"
    ]
    armor_names = [
        "НепроницаемаяКожа", "СтальнойЗаслон", "БроняНосорога",
        "СеребряныйПанцирь", "ДраконьяКожа", "МифриловаяБроня",
        "ЭльфийскоеОбмундирование", "ГномскаяКольчуга",
        "ТитановаяЛатнаяРубаха", "МагическаяМантия",
        "ЗакалённыйФакел", "ЖелезныйКаркас", "КожаныйПокров",
        "ДуховнаяБроня", "КристальнаяЗащита"
    ]
    items_types = [
        {
            'type': 'Меч',
            'category_names': None,  # Будет инициализироваться позже
            'stat': 'Атака',
            'stat_value_range': (5, 15)
        },
        {
            'type': 'Щит',
            'category_names': None,  # Будет инициализироваться позже
            'stat': 'Защита',
            'stat_value_range': (3, 10)
        },
        {
            'type': 'Доспех',
            'category_names': None,  # Будет инициализироваться позже
            'stat': 'Защита',
            'stat_value_range': (4, 12)
        }
    ]

    # Расширенные списки профессий и имен (100 вариантов каждый)
    professions = [
        "Стоматолог", "Зоотехник", "Крановщик", "Газосварщик", "Программист",
        "Инженер", "Учитель", "Врач", "Архитектор", "Повар",
        "Механик", "Фармацевт", "Бухгалтер", "Писатель", "Дизайнер",
        "Менеджер", "Юрист", "Пилот", "Агроном", "Психолог",
        "Режиссер", "Музыкант", "Пожарный", "Полицейский", "Библиотекарь",
        "Эколог", "Биолог", "Химик", "Геолог", "Слесарь",
        "Физик", "Социолог", "Электрик", "Водитель", "Парикмахер",
        "Космонавт", "Солдат", "Терапевт", "Хирург", "Художник",
        "Актёр", "Логист", "Экономист", "Инструктор", "Таксист",
        "Фотограф", "Воспитатель", "Нотариус", "ГлавныйБухгалтер", "Биотехнолог",
        "IT-Специалист", "Маркетолог", "Риэлтор", "Агент", "Организатор",
        "Светотехник", "Веб-дизайнер", "Секретарь", "Массажист", "Парикмахерист",
        "Техник", "Сантехник", "Кондитер", "Флорист", "Фермер",
        "Летчик", "Кинорежиссер", "Сценарист", "Прокурор", "Руководитель",
        "Директор", "Координатор", "Консультант", "Секретарь", "Официант",
        "Бармен", "Психотерапевт", "Кардиолог", "Онколог", "Невролог",
        "Ортопед", "Терапевт", "Педиатр", "Гастроэнтеролог", "Диетолог",
        "Нефролог", "Офтальмолог", "Отоларинголог", "Рентгенолог", "Стоматолог"
    ]

    names_list = [
        "Иван", "Мария", "Джон", "Ли", "Алексей", "Софья", "Майкл", "Елена", "Дмитрий", "Анастасия",
        "Лукас", "Татьяна", "Чэнь", "Александр", "Наталья", "Кевин", "Алина", "Михаил", "Виктория", "Чжан",
        "Роман", "Екатерина", "Луиза", "Борис", "Анна", "Томас", "Людмила", "Эдвард", "Ольга", "Карл",
        "Светлана", "Даниэль", "Василий", "Ирина", "Грегор", "Надежда", "Тимур", "Полина", "Эмма", "Максим",
        "Валерия", "Леонард", "Юлия", "Филипп", "Кира", "Константин", "Лилия", "Андрей", "Анжелика", "Петр",
        "Марина", "Кристоф", "Дарья", "Георгий", "Оксана", "Руслан", "Александра", "Денис", "Вера", "Сергей",
        "Нина", "Бенджамин", "Лариса", "Владимир", "Наташа", "Фёдор", "Галина", "Николай", "Алёна", "Леонид",
        "Кристина", "Артур", "Жанна", "Станислав", "Волга", "Джулия", "Владислав", "Вероника", "Лев", "Василиса",
        "Павел", "Люся", "Олег", "Снежана", "Тигран", "Илона", "Кирилл", "Полина", "Арсений", "Лена",
        "Валентин", "Милана", "Юрий", "Ева", "Игорь", "Иванна", "Мартин", "Леся", "Виталий", "Ксения"
    ]

    def __post_init__(self):
        """Инициализация дополнительных параметров после создания объекта."""
        # Установка категорий имен для типов предметов
        self.items_types[0]['category_names'] = self.sword_names
        self.items_types[1]['category_names'] = self.shield_names
        self.items_types[2]['category_names'] = self.armor_names

        # Установка начальной позиции игрока
        self.player.pos = [GAME_WIDTH // 2, GAME_HEIGHT // 2]

        # Генерация начального региона
        self.generate_initial_region()

    def calculate_level(self, x, y):
        """Вычисляет уровень сложности на основе координат региона."""
        center = self.world_size // 2
        distance = max(abs(x - center), abs(y - center))
        return min(1 + distance // 3, 10)  # Ограничение до 10

    def generate_npc_position(self, existing_npcs=None):
        """Генерирует позицию NPC, избегая наложений."""
        if existing_npcs is None:
            existing_npcs = []
        attempts = 0
        margin = 50
        while attempts < 100:
            x = random.randint(margin, GAME_WIDTH - 200 - 50)
            y = random.randint(margin, GAME_HEIGHT - 150 - 50)
            new_rect = pygame.Rect(x, y, 50, 50)
            overlap = False
            for npc in existing_npcs:
                existing_rect = pygame.Rect(npc.pos[0], npc.pos[1], 50, 50)
                if new_rect.colliderect(existing_rect.inflate(50, 50)):
                    overlap = True
                    break
            if not overlap:
                return [x, y]
            attempts += 1
        # Возвращает случайную позицию, если не удалось найти неналоженную
        return [random.randint(margin, GAME_WIDTH - 200 - 50), random.randint(margin, GAME_HEIGHT - 150 - 50)]

    def generate_dungeon_entrance_position(self, existing_entrances=None):
        """Генерирует позицию входа в подземелье, избегая наложений."""
        if existing_entrances is None:
            existing_entrances = []
        attempts = 0
        margin = 60
        while attempts < 100:
            x = random.randint(margin, GAME_WIDTH - 60)
            y = random.randint(margin, GAME_HEIGHT - 60)
            new_rect = pygame.Rect(x, y, 40, 40)
            overlap = False
            for entrance in existing_entrances:
                existing_rect = pygame.Rect(entrance[0], entrance[1], 40, 40)
                if new_rect.colliderect(existing_rect.inflate(50, 50)):
                    overlap = True
                    break
            if not overlap:
                return [x, y]
            attempts += 1
        # Возвращает случайную позицию, если не удалось найти неналоженную
        return [random.randint(margin, GAME_WIDTH - 60), random.randint(margin, GAME_HEIGHT - 60)]

    def generate_item(self, npc_level):
        """Генерирует предмет на основе уровня NPC."""
        item_type_entry = random.choice(self.items_types)
        item_type = item_type_entry['type']
        item_name = random.choice(item_type_entry['category_names'])
        stat = item_type_entry['stat']
        # Добавляем уровень NPC к диапазону значений
        stat_value = random.randint(
            item_type_entry['stat_value_range'][0] + npc_level,
            item_type_entry['stat_value_range'][1] + npc_level
        )
        return Item(type=item_type, name=item_name, stat=stat, value=stat_value)

    def generate_math_question(self, npc_level):
        """Генерирует математический вопрос на основе уровня NPC."""
        operations = ['+', '-', '*', '/']
        if 1 <= npc_level <= 3:
            num_range = (1, 10)
            num_operations = 1
        elif 4 <= npc_level <=6:
            num_range = (10, 50)
            num_operations = 2
        elif 7 <= npc_level <=9:
            num_range = (50, 100)
            num_operations = 3
        else:
            num_range = (100, 1000)
            num_operations = 4

        question_parts = []
        current_result = random.randint(*num_range)
        question_parts.append(str(current_result))
        for _ in range(num_operations):
            operation = random.choice(operations)
            num = random.randint(*num_range)
            if operation == '/':
                # Обеспечиваем целочисленное деление
                num = random.randint(1, num_range[1])  # избегаем деления на ноль
                current_result *= num
            question_parts.append(operation)
            question_parts.append(str(num))
            try:
                # Используем безопасное выполнение
                current_result_eval = eval(f"{current_result} {operation} {num}")
                if operation == '/' and current_result_eval != int(current_result_eval):
                    # Если результат не целый, генерируем заново
                    return self.generate_math_question(npc_level)
                current_result = int(current_result_eval)
            except ZeroDivisionError:
                # Избегаем деления на ноль
                return self.generate_math_question(npc_level)
            except Exception:
                # В случае других ошибок генерируем заново
                return self.generate_math_question(npc_level)
        question = ' '.join(question_parts)
        answer = current_result
        return question, answer

    def assign_territories(self, x, y):
        """Присваивает территорию региону на основе уровня."""
        if (x, y) not in self.terrain_map:
            territory_info = self.get_territory_info(x, y)
            self.terrain_map[(x, y)] = territory_info['territory']

    def get_territory_info(self, x, y):
        """Получает информацию о территории на основе координат."""
        level = self.calculate_level(x, y)
        if level <= 3:
            territory = "Засушливые земли"
        elif level <= 6:
            territory = "Великие равнины"
        elif level <= 8:
            territory = "Горные пастбища"
        else:
            territory = "Туманная долина"
        return {'territory': territory}

    def get_region(self, x, y):
        """Возвращает регион по координатам, создавая его при необходимости."""
        if (x, y) not in self.regions and 0 <= x < self.world_size and 0 <= y < self.world_size:
            region = Region(x, y)
            region.generate_npcs(self.professions, self.calculate_level, self.generate_npc_position)
            region.generate_dungeon_entrances(self.generate_dungeon_entrance_position)
            self.regions[(x, y)] = region
            # Присваиваем территорию региону
            self.assign_territories(x, y)
        return self.regions.get((x, y), None)

    def generate_initial_region(self):
        """Генерирует начальный регион и устанавливает начальную позицию игрока."""
        self.get_region(*self.current_region_coord)
        self.player.pos = [GAME_WIDTH // 2, GAME_HEIGHT // 2]

    def recalculate_player_stats(self):
        """Пересчитывает параметры игрока."""
        self.player.recalculate_stats()

    def update_level(self):
        """Обновляет уровень знаний игрока."""
        levels_requirements = {1:10, 2:20, 3:30, 4:40, 5:50, 6:60, 7:70, 8:80, 9:90, 10:100}
        if self.player.knowledge_level in levels_requirements:
            if self.player.tasks_solved >= levels_requirements[self.player.knowledge_level]:
                self.player.knowledge_level +=1
                self.player.tasks_needed = levels_requirements.get(self.player.knowledge_level, self.player.tasks_needed)
                self.console_message += f" Поздравляем! Вы достигли уровня {self.player.knowledge_level} знаний."

    def interact_with_npc(self, npc):
        """Обрабатывает взаимодействие с NPC."""
        self.current_npc = npc
        self.state = 'dialog'
        # Генерация вопроса
        self.current_question, self.correct_answer = self.generate_math_question(npc.level)
        # Генерация предмета
        self.received_item = self.generate_item(npc.level)
        # Обновление консоли
        self.console_message = f"{npc.name}\n{npc.profession} предлагает вам {self.received_item.type} {self.received_item.name} ({self.received_item.stat} +{self.received_item.value}). Решите задачу, чтобы получить его."
        # Сброс ответа игрока
        self.player_answer = ''

    def handle_dialog(self):
        """Обрабатывает диалог с NPC."""
        while self.state == 'dialog':
            clock.tick(FPS)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        self.console_message = "Диалог завершён без решения задачи."
                        self.current_npc.cooldown = time.time() + 60  # Устанавливаем cooldown
                        self.state = 'move'
                    elif event.key == pygame.K_RETURN:
                        if self.player_answer:
                            self.handle_math_input(self.player_answer)
                        else:
                            self.console_message = "Диалог завершён без решения задачи."
                            self.current_npc.cooldown = time.time() + 60  # Устанавливаем cooldown
                            self.state = 'move'
                    elif event.key == pygame.K_BACKSPACE:
                        self.player_answer = self.player_answer[:-1]
                    else:
                        if event.unicode.isdigit() or (event.unicode == '-' and len(self.player_answer)==0):
                            self.player_answer += event.unicode
            # Рисуем игровой интерфейс
            self.draw_window()
            # Отображаем информацию диалога в консоли
            pygame.draw.rect(WIN, LIGHT_BLUE, (0, GAME_HEIGHT, WIDTH, HEIGHT - GAME_HEIGHT))
            # Делим консольное сообщение на две строки
            lines = self.console_message.split('\n')
            for idx, line in enumerate(lines):
                dialog_line = console_font.render(line, True, BLACK)
                WIN.blit(dialog_line, (10, GAME_HEIGHT + 10 + idx * 30))
            # Вторая строка: сама задача
            if self.current_question and self.correct_answer is not None:
                dialog_line2 = console_font.render(f"Задача: {self.current_question}", True, BLACK)
                WIN.blit(dialog_line2, (10, GAME_HEIGHT + 70))
            # Третья строка: поле ввода ответа
            input_prompt = console_font.render("Ответ:", True, BLACK)
            input_field = console_font.render(self.player_answer, True, BLACK)
            WIN.blit(input_prompt, (10, GAME_HEIGHT + 100))
            WIN.blit(input_field, (70, GAME_HEIGHT + 100))
            pygame.display.update()

    def interact_with_npc_action(self, npc):
        """Запускает взаимодействие с выбранным NPC."""
        self.interact_with_npc(npc)

    def equip_item(self, idx):
        """Экипирует предмет из инвентаря по индексу."""
        if idx < 0 or idx >= len(self.player.inventory):
            self.console_message = "Некорректный индекс предмета."
            return
        item = self.player.inventory.pop(idx)
        if item.type == 'Меч':
            if len(self.player.equipped['Меч']) < 2:
                self.player.equipped['Меч'].append(item)
                self.console_message = f"Вы экипировали меч: {item.name} (Атака +{item.value})"
            else:
                self.console_message = "Максимум два меча уже экипированы."
                self.player.inventory.insert(idx, item)  # Возвращаем предмет назад
        elif item.type == 'Щит':
            if self.player.equipped['Щит']:
                self.console_message = f"Сейчас экипирован щит: {self.player.equipped['Щит'].name}. Смените его перед экипировкой нового щита."
                self.player.inventory.insert(idx, item)  # Возвращаем предмет назад
            else:
                self.player.equipped['Щит'] = item
                self.console_message = f"Вы экипировали щит: {item.name} (Защита +{item.value})"
        elif item.type == 'Доспех':
            if self.player.equipped['Доспех']:
                self.console_message = f"Сейчас экипированы доспехи: {self.player.equipped['Доспех'].name}. Смените их перед экипировкой новых доспехов."
                self.player.inventory.insert(idx, item)  # Возвращаем предмет назад
            else:
                self.player.equipped['Доспех'] = item
                self.console_message = f"Вы экипировали доспехи: {item.name} (Защита +{item.value})"
        self.recalculate_player_stats()

    def move_to_region(self, new_x, new_y, direction):
        """Перемещает игрока в новый регион."""
        # Проверка границ мира
        if not (0 <= new_x < self.world_size and 0 <= new_y < self.world_size):
            self.console_message = "Вы не можете выйти за пределы мира."
            return
        # Устанавливаем новую позицию игрока в зависимости от направления движения
        if direction == 'right':
            self.player.pos[0] = 0
        elif direction == 'left':
            self.player.pos[0] = GAME_WIDTH - self.player.size
        elif direction == 'down':
            self.player.pos[1] = 0
        elif direction == 'up':
            self.player.pos[1] = GAME_HEIGHT - self.player.size
        # Обновляем текущий регион
        self.current_region_coord = (new_x, new_y)
        self.get_region(new_x, new_y)
        self.console_message = "Вы перешли в новый регион."

    def enter_dungeon(self, entrance_pos):
        """Вход в подземелье."""
        self.state = 'dungeon'
        # Сохраняем позицию игрока в надземном мире
        self.overworld_player_pos = self.player.pos.copy()
        # Устанавливаем позицию игрока в подземелье
        self.player.pos = entrance_pos.copy()

    def exit_dungeon(self):
        """Выход из подземелья."""
        self.state = 'move'
        # Восстанавливаем позицию игрока в надземном мире и смещаемся
        offset = 10  # Количество пикселей смещения
        self.player.pos = [self.overworld_player_pos[0] + offset, self.overworld_player_pos[1] + offset]

    def check_dungeon_entry(self):
        """Проверяет, находится ли игрок рядом с входом в подземелье."""
        current_region = self.get_region(*self.current_region_coord)
        for entrance in current_region.dungeon_entrances:
            entrance_rect = pygame.Rect(entrance[0], entrance[1], 40, 40)
            player_rect = pygame.Rect(self.player.pos[0], self.player.pos[1], self.player.size, self.player.size)
            if player_rect.colliderect(entrance_rect.inflate(10, 10)):
                self.enter_dungeon_prompt(entrance)
                break  # Взаимодействие только с одним входом

    def enter_dungeon_prompt(self, entrance_pos):
        """Отображает приглашение войти в подземелье."""
        prompt_running = True
        while prompt_running and self.state == 'move':
            clock.tick(FPS)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_y:
                        # Войти в подземелье
                        self.enter_dungeon(entrance_pos)
                        prompt_running = False
                    elif event.key == pygame.K_n or event.key == pygame.K_ESCAPE:
                        # Отказаться
                        self.console_message = "Вы отказались войти в подземелье."
                        prompt_running = False
            # Обновление экрана
            self.draw_window()
            # Отрисовка запроса
            prompt_text = font.render("Войти в подземелье? (Y/N)", True, BLACK)
            WIN.blit(prompt_text, (10, GAME_HEIGHT + 40))
            pygame.display.update()

    def calculate_percentage(self):
        """Вычисляет процент правильных решений задач."""
        if self.player.tasks_total == 0:
            return 0
        return int((self.player.tasks_solved / self.player.tasks_total) * 100)

    def draw_game_area(self):
        """Отрисовка игровой области."""
        current_region = self.get_region(*self.current_region_coord)
        territory = self.terrain_map.get(self.current_region_coord, "Засушливые земли")
        bg_color = terrain_backgrounds.get(territory, WHITE)
        pygame.draw.rect(WIN, bg_color, (0, 0, GAME_WIDTH, GAME_HEIGHT))
        # Название территории
        territory_title = large_font.render(territory, True, BLACK)
        WIN.blit(territory_title, (GAME_WIDTH//2 - territory_title.get_width()//2, 10))
        # Отрисовка NPC
        for npc in current_region.npcs:
            current_time = time.time()
            if current_time < npc.cooldown:
                color = ORANGE
            else:
                color = YELLOW if npc.task_solved else GREEN
            pygame.draw.rect(WIN, color, (*npc.pos, 50, 50))
            # Информация о NPC на двух строках
            profession_text = npc_font.render(npc.profession, True, BLACK)
            name_text = npc_font.render(npc.name, True, BLACK)
            WIN.blit(profession_text, (npc.pos[0], npc.pos[1] - 25))
            WIN.blit(name_text, (npc.pos[0], npc.pos[1] - 10))
        # Отрисовка входов в подземелья
        for entrance in current_region.dungeon_entrances:
            pygame.draw.rect(WIN, BLACK, ((*entrance, 40, 40)))
            exit_rect = pygame.Rect(entrance[0], entrance[1], 40, 40)
            entrance_text = font.render("Подз.", True, WHITE)  # Сокращение для компактности
            WIN.blit(entrance_text, (entrance[0]+10, entrance[1]+10))
        # Отрисовка игрока
        pygame.draw.rect(WIN, self.player.color, (*self.player.pos, self.player.size, self.player.size))
        # Отрисовка полосы здоровья над игроком
        health_bar_width = self.player.size
        health_bar_height = 5
        health_ratio = max(self.player.health / 10, 0)  # Предполагаем max health = 10
        pygame.draw.rect(WIN, HEALTH_BAR_BG_COLOR, (self.player.pos[0], self.player.pos[1] - 10, health_bar_width, health_bar_height))
        pygame.draw.rect(WIN, HEALTH_BAR_COLOR, (self.player.pos[0], self.player.pos[1] - 10, health_bar_width * health_ratio, health_bar_height))
        # Отображение параметров игрока с рамкой
        params_width = 200
        params_height = 170
        params_x = GAME_WIDTH - params_width - 10
        params_y = 20
        pygame.draw.rect(WIN, BLACK, (params_x - 2, params_y - 2, params_width + 4, params_height + 4), 2)  # Рамка
        pygame.draw.rect(WIN, LIGHT_GRAY, (params_x, params_y, params_width, params_height))
        # Отображение параметров
        attack_text = font.render(f"Атака: {self.player.attack}", True, BLACK)
        defense_text = font.render(f"Защита: {self.player.defense}", True, BLACK)
        health_text = font.render(f"Жизнь: {self.player.health}", True, BLACK)
        percentage = self.calculate_percentage()
        percentage_text = font.render(f"Процент верных: {percentage}%", True, BLACK)
        knowledge_text = font.render(f"Уровень: {self.player.knowledge_level} ({self.player.tasks_solved}/{self.player.tasks_needed})", True, BLACK)
        # Расположение параметров с уменьшенным расстоянием
        WIN.blit(attack_text, (params_x + 10, params_y + 10))
        WIN.blit(defense_text, (params_x + 10, params_y + 30))
        WIN.blit(health_text, (params_x + 10, params_y + 50))
        WIN.blit(percentage_text, (params_x + 10, params_y + 70))
        WIN.blit(knowledge_text, (params_x + 10, params_y + 90))
        # Отображение списка экипированного снаряжения
        equipped_text = font.render("Снаряжение:", True, BLACK)
        WIN.blit(equipped_text, (params_x + 10, params_y + 110))
        swords = ', '.join([item.name for item in self.player.equipped['Меч']]) if self.player.equipped['Меч'] else "Нет"
        shield = self.player.equipped['Щит'].name if self.player.equipped['Щит'] else "Нет"
        armor = self.player.equipped['Доспех'].name if self.player.equipped['Доспех'] else "Нет"
        swords_text = font.render(f"Мечи: {swords}", True, BLACK)
        shield_text = font.render(f"Щит: {shield}", True, BLACK)
        armor_text = font.render(f"Доспех: {armor}", True, BLACK)
        WIN.blit(swords_text, (params_x + 20, params_y + 130))
        WIN.blit(shield_text, (params_x + 20, params_y + 150))
        WIN.blit(armor_text, (params_x + 20, params_y + 170))

    def draw_map(self):
        """Отрисовка карты мира."""
        # Фон карты
        pygame.draw.rect(WIN, DARK_GRAY, (GAME_WIDTH, 0, MAP_WIDTH, 280))
        map_title = large_font.render("Карта", True, WHITE)
        WIN.blit(map_title, (GAME_WIDTH + MAP_WIDTH//2 - map_title.get_width()//2, 10))
        # Отрисовка регионов на карте
        for y in range(self.world_size):
            for x in range(self.world_size):
                region_coord = (x, y)
                if region_coord in self.terrain_map:
                    if region_coord == self.current_region_coord:
                        color = YELLOW  # Текущий регион
                    else:
                        color = WHITE  # Посещённые регионы
                    region = self.regions.get(region_coord)
                    if region and region.dungeon_entrances:
                        rect_color = DUNGEON_COLOR
                    else:
                        rect_color = color
                    pygame.draw.rect(
                        WIN, rect_color,
                        (GAME_WIDTH + 10 + x * self.map_tile_size, 40 + y * self.map_tile_size,
                         self.map_tile_size, self.map_tile_size))
                else:
                    # Незаполненные регионы отображаются чёрным
                    pygame.draw.rect(
                        WIN, BLACK,
                        (GAME_WIDTH + 10 + x * self.map_tile_size, 40 + y * self.map_tile_size,
                         self.map_tile_size, self.map_tile_size))
        # Отображение координат текущего региона
        coord_text = map_font.render(f"Координаты: {self.current_region_coord}", True, WHITE)
        WIN.blit(coord_text, (GAME_WIDTH + 10, 280 - 20))

    def draw_inventory(self):
        """Отрисовка инвентаря."""
        # Область инвентаря
        inventory_area_rect = pygame.Rect(GAME_WIDTH, 280, MAP_WIDTH, HEIGHT - 280)
        pygame.draw.rect(WIN, LIGHT_GRAY, inventory_area_rect)
        # Заголовок инвентаря
        inventory_title = large_font.render("Инвентарь", True, BLACK)
        WIN.blit(inventory_title, (GAME_WIDTH + MAP_WIDTH // 2 - inventory_title.get_width() // 2, 280 + 10))
        # Отображение предметов с прокруткой
        item_start_y = 280 + 50 - self.inventory_scroll_offset
        for idx, item in enumerate(self.player.inventory):
            y_pos = item_start_y + idx * 30
            # Проверка, находится ли предмет в видимой области
            if y_pos < 280 + 50 or y_pos > HEIGHT - 30:
                continue
            # Кнопка "+"
            button_rect = pygame.Rect(GAME_WIDTH + 10, y_pos, 20, 20)
            pygame.draw.rect(WIN, GRAY, button_rect)
            plus_text = font.render("+", True, BLACK)
            WIN.blit(plus_text, (button_rect.x + 5, button_rect.y + 2))
            # Текст предмета
            item_text = font.render(f"{idx+1}. {item.name} ({item.type}: {item.stat} +{item.value})", True, BLACK)
            WIN.blit(item_text, (GAME_WIDTH + 35, y_pos))
            # Проверка наведения на кнопку
            mouse_pos = pygame.mouse.get_pos()
            if button_rect.collidepoint(mouse_pos):
                pygame.draw.rect(WIN, YELLOW, button_rect, 2)
                if pygame.mouse.get_pressed()[0]:
                    self.equip_item(idx)
        # Отображение экипированного снаряжения уже перенесено в блок параметров

    def draw_dungeon_area(self):
        """Отрисовка подземелья."""
        # Фон подземелья
        pygame.draw.rect(WIN, DARK_GRAY, (0, 0, GAME_WIDTH, GAME_HEIGHT))
        # Внешние стены
        pygame.draw.rect(WIN, BLACK, (0, 0, GAME_WIDTH, GAME_HEIGHT), 10)
        # Игрок в подземелье
        pygame.draw.rect(WIN, self.player.color, (*self.player.pos, self.player.size, self.player.size))
        # Кнопка выхода из подземелья
        exit_button = pygame.Rect(GAME_WIDTH - 110, 10, 100, 30)
        pygame.draw.rect(WIN, LIGHT_GRAY, exit_button)  # Светлый квадрат для выхода
        exit_text = font.render("Выйти", True, BLACK)
        WIN.blit(exit_text, (exit_button.x + 25, exit_button.y + 5))
        # Проверка наведения на кнопку
        mouse_pos = pygame.mouse.get_pos()
        if exit_button.collidepoint(mouse_pos):
            pygame.draw.rect(WIN, YELLOW, exit_button, 2)
            if pygame.mouse.get_pressed()[0]:
                self.exit_dungeon()

    def draw_window(self):
        """Отрисовка всего окна."""
        if self.state == 'move':
            self.draw_game_area()
        elif self.state == 'dungeon':
            self.draw_dungeon_area()
        # Отрисовка карты и инвентаря всегда
        self.draw_map()
        self.draw_inventory()
        # Отображение консоли внизу
        pygame.draw.rect(WIN, LIGHT_BLUE, (0, GAME_HEIGHT, WIDTH, HEIGHT - GAME_HEIGHT))
        console_text = console_font.render(self.console_message, True, BLACK)
        WIN.blit(console_text, (10, GAME_HEIGHT + 10))
        pygame.display.update()

    def handle_math_input(self, player_input):
        """Обрабатывает ввод игрока в диалоге."""
        try:
            user_answer = int(player_input)
            if user_answer == self.correct_answer:
                # Правильный ответ
                self.player.inventory.append(self.received_item)
                self.console_message = f"Вы заслужили этот предмет: {self.received_item.name}."
                self.player.tasks_solved += 1
                self.player.tasks_total +=1
                self.update_level()
                # Обновление статуса NPC
                self.current_npc.task_solved = True
                self.state = 'move'
            else:
                # Неправильный ответ
                self.console_message = f"Неправильный ответ! Правильный ответ: {self.correct_answer}."
                self.player.tasks_total +=1
                self.state = 'move'
                self.current_npc.cooldown = time.time() + 60  # Устанавливаем cooldown
        except ValueError:
            self.console_message = "Пожалуйста, введите корректный ответ."

    def run_dialog(self):
        """Запускает цикл диалога с NPC."""
        while self.state == 'dialog':
            clock.tick(FPS)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        self.console_message = "Диалог завершён без решения задачи."
                        self.current_npc.cooldown = time.time() + 60  # Устанавливаем cooldown
                        self.state = 'move'
                    elif event.key == pygame.K_RETURN:
                        if self.player_answer:
                            self.handle_math_input(self.player_answer)
                        else:
                            self.console_message = "Диалог завершён без решения задачи."
                            self.current_npc.cooldown = time.time() + 60  # Устанавливаем cooldown
                            self.state = 'move'
                    elif event.key == pygame.K_BACKSPACE:
                        self.player_answer = self.player_answer[:-1]
                    else:
                        if event.unicode.isdigit() or (event.unicode == '-' and len(self.player_answer)==0):
                            self.player_answer += event.unicode
            # Рисуем игровой интерфейс
            self.draw_window()
            # Отображаем информацию диалога в консоли
            pygame.draw.rect(WIN, LIGHT_BLUE, (0, GAME_HEIGHT, WIDTH, HEIGHT - GAME_HEIGHT))
            # Делим консольное сообщение на две строки
            lines = self.console_message.split('\n')
            for idx, line in enumerate(lines):
                dialog_line = console_font.render(line, True, BLACK)
                WIN.blit(dialog_line, (10, GAME_HEIGHT + 10 + idx * 30))
            # Вторая строка: сама задача
            if self.current_question and self.correct_answer is not None:
                dialog_line2 = console_font.render(f"Задача: {self.current_question}", True, BLACK)
                WIN.blit(dialog_line2, (10, GAME_HEIGHT + 70))
            # Третья строка: поле ввода ответа
            input_prompt = console_font.render("Ответ:", True, BLACK)
            input_field = console_font.render(self.player_answer, True, BLACK)
            WIN.blit(input_prompt, (10, GAME_HEIGHT + 100))
            WIN.blit(input_field, (70, GAME_HEIGHT + 100))
            pygame.display.update()

    def interact_with_npc_action(self, npc):
        """Запускает взаимодействие с выбранным NPC."""
        self.interact_with_npc(npc)

    def run(self):
        """Основной игровой цикл."""
        running = True
        while running:
            clock.tick(FPS)
            keys = pygame.key.get_pressed()
            if self.state == 'move':
                self.handle_movement(keys)
                self.check_npc_interaction()
                self.check_dungeon_entry()
            elif self.state == 'dialog':
                self.run_dialog()
                continue  # Пропускаем нижние части цикла при диалоге
            elif self.state == 'dungeon':
                # Управление внутри подземелья
                if keys[pygame.K_LEFT] and self.player.pos[0] - self.player.speed > 10:
                    self.player.pos[0] -= self.player.speed
                if keys[pygame.K_RIGHT] and self.player.pos[0] + self.player.speed + self.player.size < GAME_WIDTH - 10:
                    self.player.pos[0] += self.player.speed
                if keys[pygame.K_UP] and self.player.pos[1] - self.player.speed > 10:
                    self.player.pos[1] -= self.player.speed
                if keys[pygame.K_DOWN] and self.player.pos[1] + self.player.speed + self.player.size < GAME_HEIGHT - 10:
                    self.player.pos[1] += self.player.speed
            # Обработка событий (нажатия клавиш, мыши и т.д.)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 4:  # Прокрутка вверх
                        self.inventory_scroll_offset = max(self.inventory_scroll_offset - self.scroll_step, 0)
                    elif event.button == 5:  # Прокрутка вниз
                        self.inventory_scroll_offset += self.scroll_step
            # Отрисовка всех элементов
            self.draw_window()
        pygame.quit()
        sys.exit()

    def handle_movement(self, keys):
        """Обрабатывает движение игрока."""
        movement = False
        direction = None
        new_x, new_y = self.current_region_coord
        # Перемещение игрока влево
        if keys[pygame.K_LEFT]:
            if self.player.pos[0] - self.player.speed > 0:
                self.player.pos[0] -= self.player.speed
            else:
                new_x = self.current_region_coord[0] -1
                new_y = self.current_region_coord[1]
                direction = 'left'
                movement = True
        # Перемещение игрока вправо
        if keys[pygame.K_RIGHT]:
            if self.player.pos[0] + self.player.speed + self.player.size < GAME_WIDTH:
                self.player.pos[0] += self.player.speed
            else:
                new_x = self.current_region_coord[0] +1
                new_y = self.current_region_coord[1]
                direction = 'right'
                movement = True
        # Перемещение игрока вверх
        if keys[pygame.K_UP]:
            if self.player.pos[1] - self.player.speed > 0:
                self.player.pos[1] -= self.player.speed
            else:
                new_x = self.current_region_coord[0]
                new_y = self.current_region_coord[1] -1
                direction = 'up'
                movement = True
        # Перемещение игрока вниз
        if keys[pygame.K_DOWN]:
            if self.player.pos[1] + self.player.speed + self.player.size < GAME_HEIGHT:
                self.player.pos[1] += self.player.speed
            else:
                new_x = self.current_region_coord[0]
                new_y = self.current_region_coord[1] +1
                direction = 'down'
                movement = True
        if movement:
            self.move_to_region(new_x, new_y, direction)

    def check_npc_interaction(self):
        """Проверяет возможность взаимодействия с NPC."""
        current_region = self.get_region(*self.current_region_coord)
        player_rect = pygame.Rect(self.player.pos[0], self.player.pos[1], self.player.size, self.player.size)
        for npc in current_region.npcs:
            npc_rect = pygame.Rect(npc.pos[0], npc.pos[1], 50, 50)
            if player_rect.colliderect(npc_rect.inflate(6, 6)) and npc.is_interactable():
                self.interact_with_npc_action(npc)
                break  # Взаимодействие только с одним NPC за раз

    @staticmethod
    def load_professions_and_names():
        """
        Загружает большие списки профессий и имен.
        Для демонстрации используются заранее определенные списки.
        """
        # В реальной ситуации можно загрузить из файлов или использовать генераторы
        pass  # Здесь уже используются встроенные списки

def main():
    game = Game()
    game.run()

if __name__ == "__main__":
    main()