Я думаю, большинство людей, кто застал времена DOS и ранних Windows 9x, играли или хотя-бы слышали о такой замечательной игре, как Supaplex. Лично для меня — это игра-легенда. Я до сих пор с трепетом вспоминаю долгие зимние вечера, проведённые в попытке пройти какой-нибудь сложный уровень на стареньком 286-м.
Так сложилось, что я программист. И не просто программист, а программист компьютерных игр. Так что, где-то в 2008 году я занялся написанием движка-«убийцы крузиса» (или что там было круто на тот момент, я уже не помню). Примерно через год меня настигло прозрение, что моих человеко-часов на проект уровня Unreal Engine не хватит. И я решил сделать легкую, «казуальную», версию движка и написать на ней пару простеньких игрушек.
Мой выбор пал на клон Supaplex. Правда, на тот момент уже существовало несколько клонов под Windows и другие платформы, поэтому просто писать все с нуля было неинтересно. Зато в мою голову заползла крамольная мысль: а что, если дизассемблировать оригинальный Supaplex и сделать игру с логикой, «идентичной натуральной». Такая задача казалась крайне заманчивой, и я взялся за её осуществление. Я заказал 3D-модельки у одного хорошего знакомого фрилансера и, пока он был занят моделлингом, я приступил к изучению пациента. Сразу предупреждаю, что я уже не помню многих деталей и могу что-то забыть или приврать, всё-таки это было довольно давно.
Дизассемблирование
Немного забегая вперёд отмечу, что всё, что у меня осталось по этому проекту (скрипты дизассемблера, исходники прототипа) я выложил на гитхаб. Ссылку ищите в конце статьи.
Началось всё с того, что исполняемый файл то ли запакован, то ли зашифрован. После безуспешного поиска чего-нибудь, что сможет его распаковать (хотя я не особо старательно искал), было принято решение писать свой распаковщик. Наверное, велосипедостроение у меня в крови. Я уже не помню досконально, как он работал, но идея заключалась в эмуляции инструкций CPU до точки, когда программа успешно запустилась, после чего содержимое памяти сохранялось на диск в виде EXE-файла. Этот замечательный декомпрессор можно найти в материалах к статье.
Для дизассемблирования я использовал IDA. Насколько я помню, мне приходилось пересоздавать базу данных несколько раз, поэтому вместо неё я использовал idc-скрипт, проставляющий имена символам. Его вы тоже сможете найти на гитхабе. Если вам было интересно покопаться в кишках Supaplex, но было сложно разобраться в мешанине ассемблерных инструкций, этот скрипт очень сильно поможет (даже если у вас нет IDA, можно использовать указанные там смещения в любом другом дизассемблере).
По мере дизассемблирования я начал составлять C++-псевдокод, пытаясь понять что делает тот или иной участок ассемблерного кода. С самыми сложными и непонятными блоками я разбирался с помощью самописного отладчика, который отслеживал попадание в те или иные участки кода Supaplex в процессе игры и оповещал меня об этом. Таким способом я проверял гипотезы о предназначении некоторых участков. На более позднем этапе я начал переписывать участки кода на С++, продолжая обращаться к другим участкам из оригинала, что позволило проверить корректность дизассемблирования каждого блока.
Результатом всего этого стал почти чистый C++ код игровой логики, с небольшим вкраплением goto и переменных со странными именами типа byte_403C3. Его вы тоже найдете в материалах к статье.
3D-версия
Выглядит прототип вот так:
Немного про движок. Код самого движка довольно объёмный, хотя он прост и нефункционален до безобразия. Оригинальный, «большой», движок писался с использованием библиотеки Qt. Потом по какой-то причине я решил от нее отказаться (не помню уже деталей) и написал собственную замену классов Qt.
Для отрисовки используется старый OpenGL с расширениями. В движке есть интересная деталь: если я правильно помню, в то время OpenGL 2.0 и GLSL были не очень распространены (как минимум, мой ноутбук с видеокартой Intel их не умел). Я взял из Mesa (open-source реализация OpenGL) компилятор из GLSL в ассемблерные шейдеры. В итоге, шейдеры пишутся на GLSL, но движок работает даже на очень старом железе.
В игре нет меню или хоть какого-то пользовательского интерфейса. В ресурсах лежит оригинальный levels.dat от Supaplex. По умолчанию игра запускается на первом уровне, но если создать в директории с бинарником файл level.cfg и написать там номер уровня (от 1 до 111), то игра запустится на выбранном уровне. Управление такое же, как и в оригинале — стрелки перемещают персонажа (кстати, его зовут Murphy) в выбранном направлении, пробел+стрелка съедает объект в указанном направлении без перемещения персонажа, длительное удержание пробела устанавливает красный диск (если они у вас есть, конечно). Нажатие Esc приводит к моментальному суициду (привет, Роскомнадзор!).
Исходники
На момент разработки я пользовался SVN репозиторием. Я перезалил всё в Git и немножко «причесал» код, чтобы он собирался не только на Windows, но и на Linux с OSX. Все доступно на гитхабе: github.com/zapolnov/superplex3d_prototype, собирается CMake'ом. Там же есть бинарники для особо нетерпеливых.
Я пока не планирую развивать этот проект. Весь свой код я перевожу в публичное достояние, весь арт доступен под лицензией CС Attribution-NonCommercial-ShareAlike. Звуки и музыка скачаны с этих ваших Интернетов и их лицензия мне неизвестна.
По очевидным причинам, дизассемблированный код игровой логики (supaplex_game.cpp, а также его версии в директории disassembly) предоставляется исключительно в ознакомительных целях, после прочтения его необходимо сжечь или съесть, а также забыть всё, что вы там увидели.