Разбор карт Heroes of Might and Magic III: HotA и разработка парсера на Python
Введение
Мне стало любопытно, можно ли создать парсер карт HotA, способный «на лету» отвечать на игровые вопросы: «Где искать свиток «Городского портала»?», «В каком месте спрятан Чёрный шар?» или «Томится ли герой Джелу в тюрьме?».
Вместо поиска готовых спецификаций в сети я решил пойти сложным путем — разобраться во внутреннем устройстве формата самостоятельно. Будем считать, что интернета не существует, а в распоряжении есть только сами карты, hex-редактор и здоровое любопытство.
Эта статья — отчет о моих «низкоуровневых мучениях»: изучении байт-кода, сопоставлении файлов, поиске закономерностей и извлечении полезной информации. Если эта цифровая археология покажется вам утомительной, можете смело переходить к финалу — там лежит готовое решение, которое поможет вам находить нужные заклинания без лишних усилий.
Сразу оговорюсь: я не претендую на звание эксперта по реверс-инжинирингу, просто захотелось немного поиграть с шестнадцатеричным редактором, да и вручную «ковырять» карты в редакторе надоело.
Подготовка
Для работы я взял ImHex и HxD. Чтобы не запутаться в огромном массиве данных, я создал серию тестовых карт, меняя в каждой ровно один параметр: название, наличие подземелья или сложность. Если менять всё сразу, разобраться в «простыне» байтов будет невозможно, а при пошаговых изменениях файл сам начинает «рассказывать», где спрятаны нужные настройки.
Открыв первую карту через ImHex, я столкнулся с ожидаемым препятствием.

Карта упакована в gzip. Распаковав все файлы через WinRAR, я приступил к их сравнительному анализу.
Проверка на «шум»
Сначала я убедился, что редактор карт предсказуем: создал карту, сохранил её, а затем сделал копию под другим именем. Побайтное сравнение подтвердило, что файлы идентичны — лишнего «мусора», метаданных или случайных таймстампов программа не добавляет.


Отлично, фундамент чист.
Извлечение заголовка: название карты
Сравнивая карты с разными названиями (например, «A» и «ABC»), я заметил изменение в ячейке 0x2B. В первом случае там стояло 01, во втором — 03. Попробовав более длинное название, я увидел значение 10, что в шестнадцатеричной системе как раз соответствует десятичному 16 (количеству символов). Логика проста: этот байт хранит длину названия.

С русскими названиями всё также предсказуемо — используется стандартная кодировка Windows-1251.
Первые шаги в Python
Определив, что длина названия лежит по адресу 0x2B, а само имя начинается с 0x2F, я написал базовый скрипт для его извлечения.
import gzip
data = gzip.open("hota_lab_03_name_LONG.h3m", "rb").read()
# Читаем длину, используя little-endian
n = int.from_bytes(data[0x2B:0x2F], "little")
name = data[0x2F:0x2F + n]
print(name.decode("cp1251"))
Использование little-endian здесь критично: именно так младший байт числа записывается первым. Это универсальное правило для формата H3M.
Исследование объектов: свитки и заклинания
Самое интересное началось, когда я перешел к объектам. Положив на карту свиток с «Волшебной стрелой», а затем заменив его на «Городской портал», я вычислил байт, отвечающий за ID заклинания. Сравнивая другие заклинания, я подтвердил закономерность.
Magic Arrow -> Town Portal : 0F -> 09
Magic Arrow -> Lightning Bolt : 0F -> 11
Magic Arrow -> Implosion : 0F -> 12
...
Удивительно, но даже при смене типа объекта (скажем, со свитка на объект «Ученый») логика хранения данных сохраняется, хотя и усложняется наличием дополнительных флагов.
Итоговый парсер
Последовательно изучая каждый блок данных — координаты объекта, тип награды, наличие подземелья — я собрал библиотеку для анализа файлов.
Полный код доступен на GitHub: hota-map-parser.
Запуск предельно прост:
python .\analyze_h3m.py "my_map.h3m" spell "Town Portal"
Помимо прямого поиска, я интегрировал систему взаимодействия через ИИ-агентов (Codex). Теперь можно просто спросить у консоли: «Где на этой карте Джелу?», и агент сам просканирует файл, используя мой парсер.

Надеюсь, этот опыт поможет тем, кто тоже любит заглядывать «под капот» любимых игр. Enjoy!
AISLPC открыла предзаказ на портативную консоль для ретрогеймеров Pocket AIS
Для Cyberpunk 2077 создают кооперативный режим и выпустили геймплейный трейлер модификации
Разработчики анонсировали сиквел Drova — Forsaken Kin под названием Drova II Torn Lands и показали первые кадры игры
CD Projekt RED не ожидала столь высокого интереса к ремастеру The Witcher 3 на фоне установки игрой нового рекорда
Для игры SPINE выпустили новый трейлер о кастомизации главной героини
Глава DC Studios назвал условие для продления сериала Фонари на второй сезон
Разработка GTA VI повлияла на будущее Rockstar и сократит ожидание следующих игр
Для Final Fantasy VII Remake разрабатывают фанатский мод с поддержкой кооператива