Ты написал такой код: import pygame
import sys
import random
import operator
import time

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

# 1) Размеры окна на весь экран
SCREEN_INFO = pygame.display.Info()
WIDTH, HEIGHT = SCREEN_INFO.current_w, SCREEN_INFO.current_h
GAME_WIDTH = int(WIDTH * 0.8)  # 80% ширины для игры
MAP_WIDTH = WIDTH - GAME_WIDTH
GAME_HEIGHT = HEIGHT - 100  # Оставляем место для консоли

WIN = pygame.display.set_mode((WIDTH, HEIGHT), pygame.FULLSCREEN)
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

# FPS
FPS = 60
clock = pygame.time.Clock()

# Шрифты
font = pygame.font.SysFont(None, 24)
large_font = pygame.font.SysFont(None, 32)
npc_font = pygame.font.SysFont(None, 20)
console_font = pygame.font.SysFont(None, 22)
map_font = pygame.font.SysFont(None, 16)

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

# Названия территорий распределенные по регионам
terrain_map = {}  # Ключ: (x, y), Значение: название местности

# Игровые параметры
player_size = 50
player_pos = [GAME_WIDTH // 2, GAME_HEIGHT // 2]
player_color = BLUE
player_speed = 5

# Карта мира
WORLD_SIZE = 30  # 30x30 регионов
MAP_TILE_SIZE = 4  # 2-4 раза уменьшен размер клетки (была 15, теперь 4)

# Уровни сложности задач и соответствующие территории
# 7) Уровень NPC зависит от расстояния от старта (центра)
def calculate_level(x, y):
    center = WORLD_SIZE // 2
    distance = max(abs(x - center), abs(y - center))
    # Уровень увеличивается по мере удаления от центра
    return min(1 + distance // 3, 10)  # Ограничение до 10

npc_levels = {}
for x in range(WORLD_SIZE):
    for y in range(WORLD_SIZE):
        level = calculate_level(x, y)
        if level <= 3:
            math_range = (1, 10)
            territory = "Засушливые земли"
        elif level <= 6:
            math_range = (10, 50)
            territory = "Великие равнины"
        elif level <= 8:
            math_range = (50, 100)
            territory = "Горные пастбища"
        else:
            math_range = (100, 1000)
            territory = "Туманная долина"
        npc_levels[(x, y)] = {"math_range": math_range, "territory": territory}

# Уникальные названия предметов (без изменений)
sword_names = [
    "Рубиголов", "Остроклюв", "Буревестник", "Темнокаменный клинок",
    "Звёздочёрный меч", "Лунный колун", "Солнечный разрубатель",
    "Грозовой крюк", "Теневой блеск", "Тиранический кромкогрив",
    "Изумрудный резак", "Пламеглот", "Кристальный рубанок",
    "Багровый пырсок", "Сапфировый прорезинитель"
]

shield_names = [
    "Чешуя Дракона", "Черепаший панцирь", "Обелисковый бастион",
    "Гранитная кулачность", "Ледяной заслон", "Мифриловый щит",
    "Эльфийская структура", "Баншейская маржа", "Древний барьер",
    "Стальной фундамент", "Титановый блеск", "Железный усадок",
    "Кожаный покров", "Магический заслон", "Адамантиновый щит"
]

armor_names = [
    "Непроницаемая кожа", "Стальной заслон", "Броня носорога",
    "Серебряный панцирь", "Драконья кожа", "Мифриловая броня",
    "Эльфийское обмундирование", "Гномская кольчуга",
    "Титановая латная рубаха", "Магическая мантия",
    "Закалённый факел", "Железный каркас", "Кожаный покров",
    "Духовная броня", "Кристальная защита"
]

# Типы предметов
items_types = [
    {
        'type': 'Меч',
        'category_names': sword_names,
        'stat': 'Атака',
        'stat_value_range': (5, 15)
    },
    {
        'type': 'Щит',
        'category_names': shield_names,
        'stat': 'Защита',
        'stat_value_range': (3, 10)
    },
    {
        'type': 'Доспех',
        'category_names': armor_names,
        'stat': 'Защита',
        'stat_value_range': (4, 12)
    }
]

# NPC профессии и имена (без изменений)
npc_professions = [
    {'profession': 'Дровосек', 'names': ['Иван', 'Пётр', 'Алексей', 'Николай', 'Ли']},
    {'profession': 'Кузнец', 'names': ['Софья', 'Мария', 'Елена', 'Анна', 'Хуа']},
    {'profession': 'Травник', 'names': ['Дмитрий', 'Максим', 'Виктор', 'Андрей', 'Тихон']},
    {'profession': 'Рыбак', 'names': ['Константин', 'Георгий', 'Василий', 'Михаил', 'Лун']},
    {'profession': 'Алхимик', 'names': ['Лора', 'Майкл', 'Сара', 'Джек', 'Мию']},
    {'profession': 'Мастер', 'names': ['Боб', 'Том', 'Лиза', 'Кэт', 'Нана']}
]

# Структура региона с добавленным cooldown для NPC
class Region:
    def __init__(self, x, y):
        self.coord = (x, y)
        self.npcs = []  # Список NPC в регионе
        self.generate_npcs()

    def generate_npcs(self):
        num_npcs = random.randint(1, 5)  # Ограничение от 1 до 5 NPC
        for _ in range(num_npcs):
            profession_entry = random.choice(npc_professions)
            profession = profession_entry['profession']
            name = random.choice(profession_entry['names'])
            # Генерация уровня NPC на основе региона
            level = calculate_level(*self.coord)
            # Генерация позиции NPC с учётом предотвращения наложения и отступа от границ
            pos = generate_npc_position(existing_npcs=self.npcs)
            # Название местности
            territory = npc_levels[self.coord]['territory']
            self.npcs.append({
                'pos': pos,
                'has_interacted': False,
                'profession': profession,
                'name': name,
                'level': level,
                'task_solved': False,
                'cooldown': 0  # Время, до которого NPC не может взаимодействовать после отказа
            })

def generate_npc_position(existing_npcs=None):
    if existing_npcs is None:
        existing_npcs = []
    attempts = 0
    margin = 50  # 5 пикселей от каждой стороны (увеличено для полноты)
    while attempts < 100:
        x = random.randint(margin, GAME_WIDTH - 200 - 50)  # 50 - размер NPC
        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)]

# Генерация и хранение регионов
world_regions = {}

def get_region(x, y):
    if (x, y) not in world_regions and 0 <= x < WORLD_SIZE and 0 <= y < WORLD_SIZE:
        world_regions[(x, y)] = Region(x, y)
    return world_regions.get((x, y), None)

# Текущий регион игрока
current_region_coord = (WORLD_SIZE // 2, WORLD_SIZE // 2)  # Начинаем в центре
current_region = get_region(*current_region_coord)

# Инициализация имен местностей
def assign_territories(x, y):
    if (x, y) not in terrain_map:
        region_level = npc_levels[(x, y)]['territory']
        terrain_map[(x, y)] = region_level

# Вызов функции для начальной территории
assign_territories(*current_region_coord)

# Инвентарь
inventory = []

# Активное снаряжение
equipped = {
    'Меч': [],
    'Щит': None,
    'Доспех': None
}

# Игрокские параметры
attack = 0
defense = 0
knowledge_level = 1
tasks_solved = 0
tasks_total = 0  # Общее количество решенных задач
tasks_needed = 10  # Необходимое количество для повышения уровня

# Процент верных решений
def calculate_percentage():
    if tasks_total == 0:
        return 0
    return int((tasks_solved / tasks_total) * 100)

# Состояния игры
state = 'move'  # Возможные состояния: 'move', 'dialog', 'inventory'

# Диалоговые окна
current_npc = None
current_question = None
correct_answer = None
player_answer = ''

# Информационная консоль
console_message = ""

# Функция для пересчёта параметров игрока
def recalculate_stats():
    global attack, defense
    attack = sum([item['value'] for item in equipped['Меч']])
    shield_def = equipped['Щит']['value'] if equipped['Щит'] else 0
    armor_def = equipped['Доспех']['value'] if equipped['Доспех'] else 0
    defense = shield_def + armor_def

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

# Функция для открытия окна инвентаря
def open_inventory():
    inventory_running = True
    while inventory_running:
        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:
                    inventory_running = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                # Проверяем нажатие на кнопки "Взять"
                for idx, item in enumerate(inventory.copy()):
                    button_rect = pygame.Rect(GAME_WIDTH + 20, 80 + idx * 30, 80, 25)
                    if button_rect.collidepoint(mouse_pos):
                        equip_item(idx)
                        inventory_running = False

        # Отрисовка инвентаря
        WIN.fill(WHITE)
        inventory_title = large_font.render("Инвентарь", True, BLACK)
        WIN.blit(inventory_title, (GAME_WIDTH + MAP_WIDTH//2 - inventory_title.get_width()//2, 20))

        for idx, item in enumerate(inventory):
            item_text = font.render(f"{idx+1}. {item['name']} ({item['type']}: {item['stat']} +{item['value']})", True, BLACK)
            WIN.blit(item_text, (GAME_WIDTH + 10, 80 + idx * 30))
            # Рисуем кнопку "Взять"
            button_rect = pygame.Rect(GAME_WIDTH + 20, 80 + idx * 30, 80, 25)
            pygame.draw.rect(WIN, GRAY, button_rect)
            button_text = font.render("Взять", True, BLACK)
            WIN.blit(button_text, (button_rect.x + 15, button_rect.y + 3))

            # Изменение цвета кнопки при наведении
            mouse_pos = pygame.mouse.get_pos()
            if button_rect.collidepoint(mouse_pos):
                pygame.draw.rect(WIN, YELLOW, button_rect, 2)

        # Отображение активного снаряжения
        equipped_text = font.render("Активное снаряжение:", True, BLACK)
        WIN.blit(equipped_text, (GAME_WIDTH + 10, GAME_HEIGHT - 160))
        swords = ', '.join([item['name'] for item in equipped['Меч']]) if equipped['Меч'] else "Нет"
        shield = equipped['Щит']['name'] if equipped['Щит'] else "Нет"
        armor = equipped['Доспех']['name'] if 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, (GAME_WIDTH + 30, GAME_HEIGHT - 140))
        WIN.blit(shield_text, (GAME_WIDTH + 30, GAME_HEIGHT - 120))
        WIN.blit(armor_text, (GAME_WIDTH + 30, GAME_HEIGHT - 100))

        pygame.display.update()

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

# Функция для рисования карты
def draw_map():
    # Отрисовка карты на правой части окна
    pygame.draw.rect(WIN, DARK_GRAY, (GAME_WIDTH, 0, MAP_WIDTH, GAME_HEIGHT))
    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(WORLD_SIZE):
        for x in range(WORLD_SIZE):
            region_coord = (x, y)
            color = GRAY  # По умолчанию тёмный "туман"
            if region_coord in terrain_map:
                color = WHITE  # Посещённые регионы
                if region_coord == current_region_coord:
                    color = YELLOW  # Текущий регион
            rect_x = GAME_WIDTH + 10 + x * MAP_TILE_SIZE
            rect_y = 40 + y * MAP_TILE_SIZE
            pygame.draw.rect(WIN, color, (rect_x, rect_y, MAP_TILE_SIZE, MAP_TILE_SIZE))
            pygame.draw.rect(WIN, BLACK, (rect_x, rect_y, MAP_TILE_SIZE, MAP_TILE_SIZE), 1)

    # Отображение координат текущего региона
    coord_text = map_font.render(f"Координаты: {current_region_coord}", True, WHITE)
    WIN.blit(coord_text, (GAME_WIDTH + 10, GAME_HEIGHT - 30))

# Функция для рисования основного окна
def draw_window():
    WIN.fill(WHITE)

    # Отрисовка текущей территории фоном
    territory = terrain_map.get(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:
        # 6) Цвет NPC зависит от состояния
        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'][0], npc['pos'][1], 50, 50))
        # Отображаем имя, уровень и профессию
        npc_text = npc_font.render(f"{npc['profession']} (ур.{npc['level']}): {npc['name']}", True, BLACK)
        WIN.blit(npc_text, (npc['pos'][0], npc['pos'][1] - 20))

        # 5) NPC находятся дальше от границ экрана, уже реализовано через generate_npc_position

        # Если игрок рядом и можно получить предмет, показываем информацию
        if state == 'move' and not npc['task_solved'] and current_time >= npc['cooldown']:
            player_rect = pygame.Rect(player_pos[0], player_pos[1], player_size, player_size)
            npc_rect = pygame.Rect(npc['pos'][0], npc['pos'][1], 50, 50)
            # 8) Взаимодействие только при близком расстоянии (3 пикселя)
            if player_rect.colliderect(npc_rect.inflate(6, 6)):  # Расстояние примерно 3 пикселя
                # Предположим, что каждый NPC может дать один случайный предмет
                possible_item = generate_item(npc['level'])
                item_type = possible_item['type']
                item_name = possible_item['name']
                item_stat = possible_item['stat']
                stat_value = possible_item['value']
                info_text = f"{item_type} {item_name} ({item_stat} +{stat_value})"
                info_render = font.render(info_text, True, YELLOW)
                WIN.blit(info_render, (npc['pos'][0], npc['pos'][1] + 60))

    # Рисуем игрока
    pygame.draw.rect(WIN, player_color, (player_pos[0], player_pos[1], player_size, player_size))

    # Отображаем параметры игрока
    attack_text = font.render(f"Атака: {attack}", True, BLACK)
    defense_text = font.render(f"Защита: {defense}", True, BLACK)
    percentage_text = font.render(f"Процент верных: {calculate_percentage()}%", True, BLACK)
    knowledge_text = font.render(f"Уровень Знаний: {knowledge_level} ({tasks_solved}/{tasks_needed})", True, BLACK)
    WIN.blit(attack_text, (GAME_WIDTH - 200, 20))
    WIN.blit(defense_text, (GAME_WIDTH - 200, 50))
    WIN.blit(percentage_text, (GAME_WIDTH - 200, 80))
    WIN.blit(knowledge_text, (GAME_WIDTH - 200, 110))

    # Рисуем кнопку инвентаря под параметрами
    inventory_button = pygame.Rect(GAME_WIDTH - 120, 140, 100, 30)
    pygame.draw.rect(WIN, GRAY, inventory_button)
    inventory_text = font.render("Инвентарь", True, BLACK)
    WIN.blit(inventory_text, (inventory_button.x + 15, inventory_button.y + 5))
    # Проверка наведения на кнопку
    mouse_pos = pygame.mouse.get_pos()
    mouse_pressed = pygame.mouse.get_pressed()
    if inventory_button.collidepoint(mouse_pos):
        pygame.draw.rect(WIN, YELLOW, inventory_button, 2)
        if mouse_pressed[0]:
            open_inventory()

    # Рисуем карту
    draw_map()

    # Информационная консоль внизу
    pygame.draw.rect(WIN, LIGHT_BLUE, (0, GAME_HEIGHT, GAME_WIDTH, HEIGHT - GAME_HEIGHT))
    console_text = console_font.render(console_message, True, BLACK)
    WIN.blit(console_text, (10, GAME_HEIGHT + 10))

    pygame.display.update()

# 3) Избегаем нецелочисленного деления и 4) ограничиваем возведение в степень до 2
def generate_math_question(npc_level):
    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 = []
    operations_sequence = []
    num1 = random.randint(*num_range)
    question_parts.append(str(num1))
    for _ in range(num_operations):
        operation = random.choice(operations)
        # Если операция деления, гарантируем целочисленный результат
        if operation == '/':
            num = random.randint(*num_range)
            # Чтобы деление было целочисленным
            num1 = num1 * num
            question_parts = [str(num1)]  # Пересчитываем первый операнд
            question_parts.append('/')
            question_parts.append(str(num))
            break  # Ограничиваем до одного деления для безопасности
        else:
            num = random.randint(*num_range)
            question_parts.append(operation)
            question_parts.append(str(num))
            num1 = eval(f"{num1} {operation} {num}")
    question = ' '.join(question_parts)
    try:
        # Безопасное вычисление, ограничим операции
        allowed_ops = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv}
        expr = question
        # Рассчитываем ответ
        answer = eval(expr, {"__builtins__": None}, allowed_ops)
        if isinstance(answer, float):
            if answer.is_integer():
                answer = int(answer)
            else:
                # Если результат не целый, повторяем генерацию
                return generate_math_question(npc_level)
    except:
        # В случае ошибки повторяем генерацию
        return generate_math_question(npc_level)
    return question, answer

# Функция для генерации предмета на основе уровня NPC
def generate_item(npc_level):
    # Выбираем случайный тип предмета
    item_type_entry = random.choice(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 {
        'type': item_type,
        'name': item_name,
        'stat': stat,
        'value': stat_value
    }

# Функция обработки диалога с NPC
def handle_dialog(npc):
    global state, current_question, correct_answer, player_answer, inventory, console_message, tasks_solved, tasks_total
    # Генерируем вопрос
    current_question, correct_answer = generate_math_question(npc['level'])
    state = 'question'
    player_answer = ''
    # Определяем предмет, который даст NPC в зависимости от уровня знания
    received_item = generate_item(npc['level'])
    console_message = f"{npc['name']} предлагает вам {received_item['type']} {received_item['name']} ({received_item['stat']} +{received_item['value']}). Решите задачу, чтобы получить его."

    # Главный цикл диалога
    while state == 'question':
        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:
                    console_message = "Диалог завершён без решения задачи."
                    state = 'move'
                    npc['cooldown'] = time.time() + 60  # Устанавливаем 1 минуту cooldown
                elif event.key == pygame.K_RETURN:
                    if player_answer:
                        try:
                            user_answer = int(player_answer)
                            if user_answer == correct_answer:
                                inventory.append(received_item)
                                console_message = f"Вы заслужили этот предмет: {received_item['name']}."
                                tasks_solved +=1
                                tasks_total +=1
                                # Обновление процента верных
                                update_level()
                                # Обновляем статус NPC
                                npc['task_solved'] = True
                                state = 'move'
                            else:
                                console_message = f"Неправильный ответ! Правильный ответ: {correct_answer}."
                                tasks_total +=1
                                state = 'move'
                                npc['cooldown'] = time.time() + 60  # Устанавливаем 1 минуту cooldown
                        except:
                            console_message = "Пожалуйста, введите корректный ответ."
                            player_answer = ''
                    else:
                        # Если нет ответа, выходим из диалога
                        console_message = "Диалог завершён без решения задачи."
                        state = 'move'
                        npc['cooldown'] = time.time() + 60  # Устанавливаем 1 минуту cooldown
                elif event.key == pygame.K_BACKSPACE:
                    player_answer = player_answer[:-1]
                else:
                    if event.unicode.isdigit() or (event.unicode == '-' and len(player_answer)==0):
                        player_answer += event.unicode

        # Рисуем основной экран
        draw_window()
        # Отображаем информацию диалога в консоли
        pygame.draw.rect(WIN, LIGHT_BLUE, (0, GAME_HEIGHT, GAME_WIDTH, HEIGHT - GAME_HEIGHT))
        # Первая строка: предложение предмета
        dialog_line1 = console_font.render(f"{npc['name']} предлагает вам {received_item['type']} {received_item['name']} ({received_item['stat']} +{received_item['value']}). Решите задачу, чтобы получить его.", True, BLACK)
        WIN.blit(dialog_line1, (10, GAME_HEIGHT + 10))
        # Вторая строка: сама задача
        if current_question and correct_answer is not None:
            dialog_line2 = console_font.render(f"Задача: {current_question}", True, BLACK)
            WIN.blit(dialog_line2, (10, GAME_HEIGHT + 40))
        # Третья строка: поле ввода ответа
        input_prompt = console_font.render("Ответ:", True, BLACK)
        input_field = console_font.render(player_answer, True, BLACK)
        WIN.blit(input_prompt, (10, GAME_HEIGHT + 70))
        WIN.blit(input_field, (80, GAME_HEIGHT + 70))

        pygame.display.update()

# Функция для взаимодействия с NPC
def interact_with_npc(npc):
    global state, current_npc
    current_npc = npc
    handle_dialog(npc)

# Функция для перехода между регионами
def move_to_region(new_x, new_y, direction):
    global current_region_coord, current_region, player_pos, console_message
    # Проверяем границы мира
    if not (0 <= new_x < WORLD_SIZE and 0 <= new_y < WORLD_SIZE):
        console_message = "Вы не можете выйти за пределы мира."
        return

    # Устанавливаем новую позицию игрока в зависимости от направления
    if direction == 'right':
        player_pos[0] = 0
    elif direction == 'left':
        player_pos[0] = GAME_WIDTH - player_size
    elif direction == 'down':
        player_pos[1] = 0
    elif direction == 'up':
        player_pos[1] = GAME_HEIGHT - player_size

    current_region_coord = (new_x, new_y)
    current_region = get_region(*current_region_coord)
    assign_territories(new_x, new_y)
    console_message = "Вы перешли в новый регион."

# Основной игровой цикл
def main():
    global state, player_pos
    running = True
    while running:
        clock.tick(FPS)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        keys = pygame.key.get_pressed()
        if state == 'move':
            movement = False
            direction = None
            new_x, new_y = current_region_coord
            # Перемещение игрока
            if keys[pygame.K_LEFT]:
                if player_pos[0] - player_speed > 0:
                    player_pos[0] -= player_speed
                else:
                    # Переход в левый регион
                    new_x = current_region_coord[0] -1
                    new_y = current_region_coord[1]
                    direction = 'left'
                    movement = True
            if keys[pygame.K_RIGHT]:
                if player_pos[0] + player_speed + player_size < GAME_WIDTH:
                    player_pos[0] += player_speed
                else:
                    # Переход в правый регион
                    new_x = current_region_coord[0] +1
                    new_y = current_region_coord[1]
                    direction = 'right'
                    movement = True
            if keys[pygame.K_UP]:
                if player_pos[1] - player_speed > 0:
                    player_pos[1] -= player_speed
                else:
                    # Переход в верхний регион
                    new_x = current_region_coord[0]
                    new_y = current_region_coord[1] -1
                    direction = 'up'
                    movement = True
            if keys[pygame.K_DOWN]:
                if player_pos[1] + player_speed + player_size < GAME_HEIGHT:
                    player_pos[1] += player_speed
                else:
                    # Переход в нижний регион
                    new_x = current_region_coord[0]
                    new_y = current_region_coord[1] +1
                    direction = 'down'
                    movement = True

            if movement:
                move_to_region(new_x, new_y, direction)

            # Проверяем близость к NPC
            for npc in current_region.npcs:
                player_rect = pygame.Rect(player_pos[0], player_pos[1], player_size, player_size)
                npc_rect = pygame.Rect(npc['pos'][0], npc['pos'][1], 50, 50)
                # 8) Взаимодействие только при близком расстоянии (уже реализовано в draw_window)
                if player_rect.colliderect(npc_rect.inflate(6, 6)) and not npc['task_solved'] and time.time() >= npc['cooldown']:
                    interact_with_npc(npc)
                    break  # Один NPC за раз

        draw_window()

    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()

Надо изменить следующее: 1)Надо вернуть кнопки закрытия и сворачивания окна, 2)При открытии инвентаря пространство слева должно продолжать отрисовываться. 3)В инвентаре кнопки "Взять" отображаются прямо поверх текста. Можно заменить большую кнопку на меленькую со значком "+",  и отображать ее слева от текста. 4)Карту справа можно сделать в два раза крупнее (иначе совсем плохо видно). Отображать надо только открытые квадраты, остальное пространство 30 на 30 квадратов должно быть просто скрыто черным. 5)На основном экране кроме квадратов местных жителей нужно отрисовывать в полтора раза большие квадраты - входы в подземелья (1-2 на некоторых экранах). Если подойти к подземелью, попадаешь в него (это тоже экран, разлинованный на 25x25 квадратов), 6)Из подземелья можно выйти и снова войти. Оно не перестает быть активным.