Привет, я основатель Video Game History Foundation Фрэнк Сифалди. Сегодня мы с Ричем Уайтхаусом расскажем вам историю о том, как восстановили и собрали заново Days of Thunder — невыпущенную, никем ранее не виденную игру, соавтором которой был Крис Оберт из Mindscape.
Ушедший от нас в 2012 году программист и дизайнер Крис Оберт (Chris Oberth) сделал долгую и разнообразную карьеру в индустрии видеоигр. Думаю, для большинства из нас главной игрой Криса Оберта была Anteater — аркадный проект, который он придумал и разработал во время работы в Stern (или, возможно, вы знаете клон этой игры под названием Ardy the Aardvark, который сам Крис написал для домашних компьютеров, или ещё один клон, Oil’s Well, созданный другими людьми). Для остальных такой игрой может быть Winter Games для Commodore 64 или, возможно, его последние проекты для аркадных автоматов наподобие Time Killers или World Class Bowling, которые он разрабатывал в Incredible Technologies; или же такими знаковыми играми для вас могли стать несколько проектов, которые он разработал на своём Apple II в конце 70-х и начале 80-х (как он сам любил хвастаться, его Apple II имел серийный номер 201).
В начале 2020 года с Video Game History Foundation связался друг семьи Оберта, попросив помочь разобраться с оставшимися после него материалами. В подвале его дома, где он часто работал, хранились годами нетронутые кучи старых компьютеров, резервных копий на CD-R, гибких дисков, записей, кассет, EPROM и данных на ленточных накопителях, копившиеся со времён его работы с Apple II в конце 70-х. Его семья согласилась временно передать нам эти архивы для разбора.
Как часто бывает с такими архивами, самым важным для нас было попытаться восстановить все утерянные работы Криса — разработанные им игры, которые по тем или иным причинам остались неизданными. К сожалению, мы почти не нашли остатков его работ со времени сотрудничества со Stern, то есть невыпущенная аркадная игра Crypt, источником вдохновения для которой послужила Hunt the Wumpus, скорее всего, навсегда утеряна. Но остальная часть коллекции дала нам надежду на сохранение его последующих работ для домашних компьютеров и консолей.
Загадочная «Hot Rod Taxi» стала первым признаком того, что в архиве кода Оберта могут храниться неопубликованные работы.
Особенно любопытным нам показался 5,25-дюймовый гибкий диск с рукописной пометкой «NINTENDO HOT ROD TAXI FINAL». Название этой игры неизвестно, но мы знали, что Крис разработал по крайней мере одну игру для Nintendo Entertainment System — American Gladiators. Нам не были известны подробности о его работе того времени, но, к счастью, позже Оберт дал по крайней мере два интервью первым сайтам поклонников ретро-игр — одно сайту Derek’s Basement Arcade, а второе интервью в трёх частях в 2006 году сайту Retrogaming Times (оно опубликовано в выпусках 21, 24 и 27 «Retrogaming Times Monthly»). В последнем Крис вкратце упомянул о невыпущенной игре для NES — неопубликованной версии Days of Thunder, разработанной для Mindscape (в конечном итоге вместо него был издан ещё один проект, созданный Beam Software). Была ли «Hot Rod Taxi» той самой утерянной Days of Thunder? Возможно, из неё убрали название по кинолицензии?
Hot Rod Taxi для NES, скомпилированная из исходного кода Оберта. Это не совсем игра, она больше напоминает первое технологическое демо. Days of Thunder опять от нас ускользнула.
Вероятно. Возможно. Сделав чистый рип диска и собрав двоичный файл из исходного кода и графических данных, мы получили играбельную игру для NES, которая, хотя и была интересной с исторической точки зрения, не очень походила на игру. Больше она напоминала первую проверку концепции; вероятно, с её помощью Оберт впервые знакомился с совершенно незнакомой ему платформой.
У нас был ещё один объект для поисков: огромная куча резервных копий жёстких дисков (по большей части подписанных), создававшихся на протяжении нескольких лет и сохранённых примерно на 40 гибких дисках. Это не были просто сохранённые на дисках файлы — резервное копирование выполнялось разными инструментами для копирования жёстких дисков, то есть файлы оказались разбиты на части и зашифрованы. Единственный способ их восстановления заключался в оцифровке всей кучи и сборке всех данных.
Теперь я передаю слово Ричу.
Часть из сотен дисков, оставшихся от Криса Оберта. Возможно ли, что где-то в этой куче есть Days of Thunder?
Восстановление накопителей
Нашей первой задачей в процессе поиска остатков Days of Thunder стало восстановление максимально возможного количества данных с различных носителей, в основном представленных старыми дисками на 5,25 дюйма. На некоторых из этих дисков были нечитаемые секторы, но в многие по-прежнему оставались целыми. Кроме того, часть этих дисков сразу удалось считать после создания под MS-DOS файловых систем FAT12. Однако самой многообещающей частью был набор из 21 дисков, содержащий резервные копии четырёх отдельных разделов жёсткого диска в проприетарном формате, сгенерированном PC Tools 5.1. Нам помогли в этом разобраться надписи «PCTools 5.10. Backup» на этикетках дисков.
Наша первая попытка воссоздания жёсткого диска Оберта 1989 года с помощью инструмента резервного копирования закончилась неудачей — эмуляция через DOSBox не была способна выполнить эту задачу.
Сначала я попробовал запустить программу резервного копирования PC Tools через DOSBox, надеясь, что смогу восстановить резервные копии при помощи эмуляции. Мне не удалось заставить программу распознать образы дисков под DOSBox, и я решил, что для движения по этому пути может потребоваться внесение изменений в сам эмулятор. В этот момент я решил подойти с другой стороны, чтобы понять данные напрямую, и приступил к изучению сырых данных секторов в этих образах резервных дисков.
Структура данных оказалась не особо сложной. Каждая запись о папках и файлах хранилась в упакованном потоке, в котором для обозначения одного из трёх вариантов использовались командные байты. 0xDA означает, что к текущему стеку папок будет добавлена «запись папки». 0xDB означает «запись файла», за которой сразу же следуют сами данные файла. 0xDC означает «извлечение папки», то есть удаление самой последней папки из стека папок. В самих записях мне удалось выявить слова даты/времени в стиле MS-DOS, что позволило нам определить точные даты каждого из файлов в резервной копии.
Начало оказалось многообещающим, оно позволило нам сгенерировать список содержащихся в резервных копиях файлов. Мы быстро нашли кучу исходного кода и данные, которые с высокой вероятностью представляли собой наш большой приз: Days of Thunder. К сожалению, у нас всё равно оставалась проблема: даже несмотря на то, что мне удалось сгенерировать полный список путей из резервных копий, большинство интересующих нас данных было сжато проприетарным алгоритмом. Было бы легко на глаз понять используемое здесь сжатие, но поверх уже сжатых данных было использовано ещё и шифрование. К счастью, применённое к данным шифрование было стандартным и не зависело от вводимого пользователем ключа — в противном случае я бы до сих пор восстанавливал данные, а не писал эту статью!
Далее я рассматривал возможность использования нескольких подходов. Первый заключался в создании собственной сборки DosBox, чтобы заставить программу резервного копирования PC Tools правильно работать с исходными образами копий через эмуляцию. Второй подход заключался в обратной разработке используемых в PC Tools шифрования и сжатия, для этого бы потребовалось потратить много времени на дизассемблирование (и, в идеале, на отладку) самой программы. Я умею дизассемблировать системы более масштабные и сложные, чем эта, но решил, что собственная сборка DosBox в любом случае будет полезным инструментом. Можно будет использовать её до того момента, пока не выяснится, что данные резервных копий каким-то образом повреждены. В таком случае мне придётся разобрать каждый их бит, чтобы собрать из обломков всё полезное.
К нам на помощь пришёл волонтёр VGHF с ником Foone. Для правильного восстановления резервной копии жёсткого диска Оберта он воссоздал соответствующую той эпохе аппаратную среду.
Третий подход был намного проще, чем два предыдущих: использовать реальное «железо»! К сожалению, у меня под рукой не оказалось нужного оборудования, но мы сразу же смогли воспользоваться помощью того, у кого оно было. Волонтёру Foone удалось собрать и запустить аппаратную систему, и хотя нам пришлось заново рипнуть один из наборов дисков с резервными копиями, чтобы PC Tools понял их, в конечном итоге мы смогли восстановить каждый бит данных каждого из этих четырёх разделов жёсткого диска.
Так как третье решение сработало, мне так и не пришлось погружаться в дебри реверс-инжиниринга использованного в PC Tools алгоритма сжатия. Однако по слухам, это скорее всего было что-то типа LZSS. Я провёл несколько простых тестов с программой pcsecure.exe из набора PC Tools; похоже, она использует сжатие (хоть и не совершенно такое же, если судить результаты, полученные при сжатии соответствующих данных), очень похожее на сжатие, применяемое программой резервного копирования. Также я заметил, что в некоторых случаях сжатие сбоило и создавалоь файлы большего размера, чем можно было бы ожидать в наихудшем для LZSS случае. Например, такая ситуация возникала при сжатии последовательностей совершенно уникальных байтов, которое увеличивало размер файла; предположу, что это вызвано добавлением в данные контрольных байтов.
Сборка исходного кода
После кратного изучения я не нашёл ничего напоминающего уже собранный образ ROM. Разумеется, ведь это было бы слишком просто. Итак, у меня были данные, располагавшиеся на четырёх разделах жёсткого диска. Я начал с папки с названием C:ROMXBTR. Её мы больше всего рады были увидеть тогда, когда изучали полученный список имён файлов. Казалось, что в этой папке находится весь исходный код и какие-то данные для Days of Thunder. В папке C:UTIL содержались резервные копии многих инструментов, использовавшихся для разработки игры, в том числе ассемблер/компоновщик. При разработке использовался ассемблер X6502 — кросс-ассемблер 6502, созданный 2500 A.D. Software, Inc. И ассемблер, и компоновщик имели версию 4.03b.
Я собрал исходники и скомпоновал все объекты, при этом были созданы 6 отдельных двоичных файлов. Это переносит нас к следующей части процесса — к программе под названием ROMX. Эта программа является частью пакета ROMulator, созданного GTEK, Inc. Примечательно, что веб-сайт компании до сих пор работает. В нашем случае программа ROMX использовалась для передачи данных через компьютерный порт RS232 прямиком в память PRG/CHR картриджа разработки NES. Он позволял разработчикам быстро обновлять и тестировать изменения в коде и графике на реальном «железе». Ещё удобнее то, что они могли выборочно обновлять нужный набор банков, чтобы снизить время итераций при обновлении определённого фрагмента кода или набора тайлов. В исходном коде было довольно много пакетных файлов, выполнявших команды ROMX по загрузке конкретных файлов в конкретные области в PRG/CHR. Вот пакетный файл, из которого можно понять полную схему PRG ROM:
ROMX PB0.TSK[TS,M,%%0000,@0000-ffff] ROMX PB1.TSK[%%0000,@4000-7fff] ROMX PB2.TSK[%%0000,@8000-bfff] ROMX PB3.TSK[%%0000,@C000-ffff] ROMX PB4.TSK[%%0000,@10000-13fff] ROMX PB7.tsk[%%0000,@1C000-1ffff] ROMX CRASHL2.SND[%%0000,@1F000-1ffff] ROMX SKIDF.SND[%%0030,@1FC80-1fff0,TE]
Приведённые выше команды сообщают нам, куда нужно помещать 6 двоичных файлов кода (те, о компоновке которых я говорил выше) вместе с двумя предварительно сгенерированными двоичными файлами звуков. Когда один из разработчиков хотел создать простой двоичный файл из памяти PRG или CHR, то вместо копирования всей этой информации с PC он мог просто запустить ROMX с параметрами, позволяющими выполнить дамп всех данных прямо из «железа» и сохранить их в файл.
На этом этапе сборки игры, уже исходя из одного количества банков PRG стало очевидно, что нам потребуется какой-то мэппер, поэтому и просмотрел исходники и встретил код, явным образом работающий с регистрами MMC1. Я изготовил заголовок iNES с моим 128-килобайтным PRG ROM, соответствующим образом задал биты мэппера, а затем просто забросил в CHR ROM случайный мусор для тестирования. Игра успешно загрузилась в эмуляторе и начала воспроизводить музыку, отображая хаотичные данные из случайных тайлов. Насколько я понял, они должны были обозначать экран заставки.
Отсутствующие символы
После запуска игры с набором случайных данных в CHR ROM я понял, что мы увидели довольно уникальные данные тайлов. Часть следов этих данных сохранились в исходном коде. В частности, там был самописный инструмент, предназначенный для парсинга блоков тайлов из файлов CLP программы Pictor, запись их во временный файл и загрузка его при помощи ROMX в явно заданные адреса CHR. Этот процесс вызывался для небольших наборов тайлов с машиной и разводным ключом. Однако основная часть данных CHR никак не упоминалась, и не было никаких признаков того, как данные CHR обычно загружались через ROMX.
В ещё одной папке, C:ROMXCHEDIT, я обнаружил самодельный редактор тайлов NES с остатками данных, которые, кажется, относились к Days of Thunder. Мне удалось сопоставить часть экспортированных сюда данных .map и .pal с данными, собиравшимися в PRG, а поскольку они совпали, я предположил, что находящиеся здесь файлы .chr тоже будут соответствовать чему-то, относящемуся к CHR. Я начал с файла с именем CAR.CHR и занялся разбором того, где же конкретно он должен находиться в памяти CHR. Оказалось, что это адрес 0x3000. Мне удалось убедиться в этом, взглянув на экран заставки, несмотря на то, что остальная часть CHR была заполнена случайными данными:
Мы нашли и скомпилировали данные программы, но бОльшая часть графики отсутствовала! К большому сожалению, мы проделали такой большой путь, но всё равно не смогли пересечь финишную черту.
Мы убедились, что эти конкретные данные принадлежали CHR ROM, но многих данных всё равно не хватало. Я обнаружил в скриптах какой-то утилиты для анимирования ссылки, указывающие на изображения дороги и тайлов в местах, которые отсутствовали в восстановленной нами резервной копии. Я боялся худшего — что мы потеряли большой набор данных CHR вместе с данными исходников для их восстановления.
Зная, что у меня уже есть вероятный кандидат на нахождение большой части данных CHR ROM, я взял уникальную строку байтов из CAR.CHR и выполнил её двоичный поиск в каждом из файлов резервной копии, надеясь, что мне повезёт и я найду уже собранный фрагмент CHR ROM. Первая попытка не увенчалась успехом. После этого я решил применить «ядерное» решение — извлёк каждый архив в каждом известном формате из каждой резервной копии жёстких дисков, и проделал то же самое с каждым образом диска, которые мне удалось восстановить. Я выполнил ещё один поиск по всему этому массиву информации, и нашлось единственное совпадение в 128-килобайтном двоичном файле. О да!
Соединяем всё вместе
Я был очень аккуратен, ведь не факт, что этот двоичный файл с таким удобным размером 128 КБ на самом деле будет совпадать с исходниками и тайлами, с которыми я работаю. Особенно меня настораживало то, что совпадение строки нашлось в другом наборе дисков. Однако на этом этапе у меня уже не было других вариантов, поэтому я взял файл и использовал его для заполнения всего CHR ROM в созданном мной NES ROM. Оказалось, всё находится на тех местах, где и должно быть!
Наконец-то мы впервые за тридцать лет увидели давно утерянную игру Days of Thunder!
На этом нашу миссию можно считать успешно завершённой. К сожалению, похоже, что нам не хватает множества исходных данных, и я всё ещё подозреваю, что эти данные хранятся где-то на других разделах жёсткого диска, которые не вошли в восстановленную нами основную резервную копию. Если бы нам не удалось найти двоичный файл CHR из казавшегося независимым набора данных, то мы бы никогда не смогли полностью восстановить игру или в конечном итоге создали бы собственные тайлы, чтобы сохранить какое-то подобие оригинальной игры. Это доказывает, что важен каждый гибкий диск!
Соберите игру и сыграйте сами!
С разрешения семьи Криса Оберта мы загрузили на GitHub исходный код Days of Thunder вместе с собственным инструментом сборки и уже собранными двоичными файлами.
Программист видеоигр Крис Оберт (1953-2012 гг.)