
В 1990 году компания Titus представила Fire & Forget II — динамичную гонку, в которой вооруженный пулеметом спорткар мог подниматься в воздух. В детстве я пропадал в этой игре, а недавно решил заглянуть в её «внутренности», чтобы изучить архитектуру. Увиденное поразило: проект содержал кооперативную многозадачность на базе чистого 8086, проприетарный скриптовый язык с французской номенклатурой, две параллельные виртуальные машины, исполняющие единый байткод, и, как выяснилось, нетронутую запись авторского геймплея. Эта скрытая демонстрация была недоступна игрокам десятилетиями. В процессе исследования я перенес игру на C11, и теперь она ожила в браузере: если не трогать управление в меню, вы сможете увидеть тот самый секретный прогон разработчика. Но эта заметка не столько о порте, сколько о «археологии» кода.
Далее вас ждет глубокий анализ пиксель-арта, серия визуальных головоломок «найди отличия» и разбор механики синхронизации, благодаря которой враги оживали на экране усилиями двух виртуальных машин.
–
Сравнение кадров
Оригинальный бинарник, запущенный в QEMU, ведет себя как в 1990 году, попиксельно записывая данные в видеопамять EGA. Отладчик делает «слепки» каждого кадра, которые я сравниваю с выводом моего порта. Малейшее расхождение — сигнал о том, что в оригинальном коде скрыта еще не разгаданная логика. Из этих сравнений и родилась статья. Взгляните на примеры ниже.
Сцена первая: уничтожение босса.


Розовый цвет указывает на ошибки отрисовки:
-
Надпись «STAGE 1 COMPLETED» собирается из алфавитно-цифровых спрайтов. Мой порт поначалу игнорировал этот флаг завершения уровня.
-
Визуализация взрыва: босс «распадается» на пять частей, которые рисуются одновременно. Порядок их наложения зависит от ключа в списке отрисовки. Моя версия ошибочно инвертировала этот порядок.
-
Пыль из-под колес при торможении: отдельный спрайт, который движок подгружает динамически.
Сцена вторая: типичный фрагмент трассы.


-
Канистры, спавнящиеся скриптовой машиной.
-
Камень на обочине.
-
Куст справа. Декор обрабатывается отдельным циклом.
-
Индикатор жизней: каждая «сфера» отрисовывается пошагово.
-
Шкала топлива: она обновляется инкрементально прямо в видеопамяти.
Язык сценариев уровня
В недрах данных игры нашлась таблица команд: CLEAR, GETCHAR, PUT, WHILE, GOTO и прочие. Завершается список французским словом ERREUR, что подтверждает происхождение игры. Я восстановил дизассемблер, чтобы расшифровать 3090 байт скриптов. Вот фрагмент первого уровня:
script0:
SETDIST 10000 ; дистанция до лидера конвоя
loc_003:
GOSUB loc_671 ; подпрограмма: размещение канистр
CLEAR
GETCHAR JUMPER ; ожидание готовности спрайта врага
GETCHAR T54
PUT recs_ada_jumper ; высадка противников
GOSUB loc_671
CLEAR
GETCHAR RIDER
PUT recs_975_rider ; волны байкеров
PUT recs_98a_rider
PUT recs_975_rider
Дизайнеры использовали PUT не только для врагов, но и для синхронизации геометрии трассы. В коде также остались «мертвые» фрагменты: неиспользуемые подпрограммы и целые волны врагов, которые были закомментированы автором, но не удалены из финального билда.
Создание врага «Джампер»
Джампер — это мех, который прыгает на игрока. Его спрайты хранятся в виде левых «половинок», которые движок зеркально отражает при отрисовке. Для экономии ресурсов движок использует готовую лестницу уменьшенных спрайтов (от 64×33 до 16×4), имитируя перспективу без затратных вычислений в реальном времени. Вторая виртуальная машина, работающая на шаг впереди, подготавливает эти спрайты заранее, «размазывая» процесс сборки на десятки кадров.
Тайм-капсула
Демо-режим — это не записанное видео, а последовательность команд ввода (217 пар байт). Она разворачивается в 2667 кадров геймплея. Удивительно, но запись содержит 34 секунды «скрытого» контента: после гибели босса, которую видит игрок, запись продолжается, демонстрируя мастерское прохождение второго уровня разработчиком. Эти 34 секунды никогда не проигрывались в игре до сегодняшнего дня. Я разблокировал их, и теперь их можно увидеть в браузере: titustribute.com/ff2/demo2.
Исходный код порта и восстановленные данные доступны на GitHub. Для запуска вам потребуются оригинальные ресурсы игры — скрипт автоматически извлечет их и настроит среду.


