Разбор карт 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!
Xbox Game Studios работает над тремя новыми играми после масштабной реструктуризации подразделения
Nintendo представила новую карту The Legend of Zelda Ocarina of Time с преобразившимся Хайрулом
Hot Toys показала коллекционную фигурку Завтра из игры Death Stranding 2: On the Beach
По градостроительному симулятору Against the Storm создадут настольную игру о возвращении Гнилой бури
JoyToy открыла предзаказ на фигурку боевого лидера Волчьей гвардии из ордена Космических Волков
В сети раньше времени появилась ПК-версия Control Resonant, тогда как игроки на PlayStation платили за ранний доступ
Фагнаты обновили кастомную карту GTA VI: она уменьшилась в размерах, но стала детализированнее
Hot Toys показала коллекционную фигурку Чёрной Вдовы в версии Artisan по фильму «Мстители: Эра Альтрона»