Я препарировал игру из детства: геймдизайн 90-х, забытые механики и виртуальные машины в одной капсуле времени

Я препарировал игру из детства: геймдизайн 90-х, забытые механики и виртуальные машины в одной капсуле времени
Fire & Forget II: логотип Titus, антагонист из заставки, заезд и таблица лидеров

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

Далее вас ждет глубокий анализ пиксель-арта, серия визуальных головоломок «найди отличия» и разбор механики синхронизации, благодаря которой враги оживали на экране усилиями двух виртуальных машин.

Сравнение кадров

Оригинальный бинарник, запущенный в QEMU, ведет себя как в 1990 году, попиксельно записывая данные в видеопамять EGA. Отладчик делает «слепки» каждого кадра, которые я сравниваю с выводом моего порта. Малейшее расхождение — сигнал о том, что в оригинальном коде скрыта еще не разгаданная логика. Из этих сравнений и родилась статья. Взгляните на примеры ниже.

Сцена первая: уничтожение босса.

Смерть босса: оригинал vs порт
Смерть босса: оригинал vs порт

Дифференциал кадра: розовым отмечены расхождения
Дифференциал кадра: розовым отмечены расхождения

Розовый цвет указывает на ошибки отрисовки:

  1. Надпись «STAGE 1 COMPLETED» собирается из алфавитно-цифровых спрайтов. Мой порт поначалу игнорировал этот флаг завершения уровня.

  2. Визуализация взрыва: босс «распадается» на пять частей, которые рисуются одновременно. Порядок их наложения зависит от ключа в списке отрисовки. Моя версия ошибочно инвертировала этот порядок.

  3. Пыль из-под колес при торможении: отдельный спрайт, который движок подгружает динамически.

Сцена вторая: типичный фрагмент трассы.

Будничный кадр: сравнение
Будничный кадр: сравнение

Дифф: пропавшие подсистемы
Дифф: пропавшие подсистемы
  1. Канистры, спавнящиеся скриптовой машиной.

  2. Камень на обочине.

  3. Куст справа. Декор обрабатывается отдельным циклом.

  4. Индикатор жизней: каждая «сфера» отрисовывается пошагово.

  5. Шкала топлива: она обновляется инкрементально прямо в видеопамяти.

Язык сценариев уровня

В недрах данных игры нашлась таблица команд: 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. Для запуска вам потребуются оригинальные ресурсы игры — скрипт автоматически извлечет их и настроит среду.

 

Источник

Читайте также