На момент своего выхода в 1993 году Disney’s Aladdin на Sega Genesis (или Mega Drive, если в начале 90-х вы жили с другой стороны лужи) была удивительно красивой игрой.
Благодаря использованию технологии, которая позже стала известной, как Digicel, правильному выбору промежуточного ПО и впечатляющему таланту авторов Aladdin смогла выделиться на фоне других игр Genesis той эпохи. Красивая нарисованная от руки графика Aladdin установила новую планку качества для того, чего можно добиться на «железе» Genesis. Это стало возможным не с помощью особенно интересных растровых эффектов или тайных аппаратных приёмов, а благодаря сочетанию эффектной графики, дизайна и правильно выбранной технологии.
Эта уникальная смесь графики и технологий стала основной причиной, позволившей игре Aladdin занять особое место в истории видеоигр. Поэтому мне так радостно было найти архив с полным исходным кодом игры в коллекции Video Game History Foundation! Кроме бесценного источника данных, этот архив является для меня отличной возможностью создать стандарты для сохранения исходного кода, отслеживания зависимостей инструментов и многих других процессо-ориентированных аспектов в VGHF.
В этом архиве сохранились невредимыми почти все инструменты и материалы разработки. Я быстро начал объединять их фрагменты, и приступил к работе над получением исходного кода (который полностью написан на ассемблерном языке M68K), встроенного в работающий двоичный файл. Я расскажу вам о моём путешествия и об открытиях, сделанных на каждом из его этапов. В том числе нахождение множества неизданных материалов, и даже повторная реализация объектов и врагов, удалённых перед коммерческим выпуском игры!
Надеюсь, вам нравятся технические рассказы, потому что я не буду ничего утаивать. Если не нравятся, то тут есть картинки (и вы можете сразу перейти к части 3.0 Скрытое сокровище)! Можете также скачать копию Noesis, чтобы исследовать проект вместе со мной. Если этот инструмент вам неизвестен, то вкратце объясню: он построен на основе фреймворка и помогает в реверс-инжиниринге и изучении всех типов данных. В нём есть скрипт fmt_virginmd_chopper.py, позволяющий извлечть все данные тайлов Chopper из всех известных (коммерческих и иных) ROM-образов Aladdin. Полученные данные можно просматривать в самом Noesis. Хоть он и не позволит вам получить доступ к данным, не дошедшим до релиза, зато вы сможете просмотреть кадры и понаблюдать за тем, как используются тайлы в завершённом продукте.
Стоит также заметить, что Noesis может извлекать резервную копию данных Chopper из демо-сборки Aladdin для CES. В этой сборке есть пара уникальных вещей, в том числе дополнительные наброски, которые недоступны в сборке при обычном процессе игры.
Демо-сборка для CES помечена как Chicago CES, но как указано в статье TCRF о сборке, в сгенерированной SNASM метке времени указана дата 27 июня 1993 года. Это доказывает, что сборка была создана через несколько недель после проведения выставки.
Обратившись к архиву исходного кода, мы можем увидеть, что часть графики исходников была изменена уже в июне, и удалена из ROM в демо-сборке для CES. Из этого нельзя делать выводы (мы никак не можем узнать, изменялась ли графика исходников после удаления из базы данных Chopper), но это подтверждает мысль о том, что демо-сборка для CES могла быть создана из активной ветки разработки 27 июня 1993 года, а не была дальнейшей разработкой более раннего снэпшота проекта. Однако для простоты при обсуждении связанных с этой сборкой материалов мы будем продолжать называть её «демо-сборкой для CES».
1. Обзор
Архив с игрой Aladdin имеет такой вид, как будто это чья-то рабочая копия исходного кода и данных игры, а не какой-то общий репозиторий. В архиве отсутствует часть зависимостей данных, что немного удивляет, ведь на каком-то этапе игра собиралась на этом же самом рабочем месте. Однако мне удалось почти без проблем воспроизвести отсутствующие данные и получить работающий двоичный файл.
Хотя контент во всём остальном, похоже, соответствует распространяемым в розницу копиям Aladdin, изменения в файлах некоторых исходников датируются аж 30 сентября 1993 года. Это на десять дней позже, чем дата сборки японской розничной версии, выпущенной 20 сентября 1993 года. Заметных изменений данных нет, но при побайтовом сравнении появляются проблемы из-за значительно отличающихся условий сборки.
Очень интересно здесь то, что в этом архиве содержится большой кусок исходного графического материала! Здесь скрывается то, что никогда не было в игре. Этот материал обычно собран в более идеальную/компактную форму каким-то другим инструментом, а потом включён в сам ROM. В статье мы рассмотрим все эти инструменты и процессы.
Пример исходных данных кадров анимации.
Ещё одним большим открытием в этом архиве Aladdin стали большие участки закомментированного кода для прототипированных и/или удалённых функций. В наши дни, если программист убирает в комментарии сотни строк уже неиспользуемого кода, а не удаляет их полностью, то его, скорее всего, вырежет программа анализа кода. Но благодаря этой удивительной практике мы спустя 24 года сможем насладиться возможностями, врагами и многим другим, что должно было войти в игру! Выкусите, стандарты написания кода!
2. Инструменты
Для всего процесса, от сборки кода до создания и подготовки данных к использованию, в Aladdin используется довольно объёмный набор инструментов, помещённый в удобную среду MS-DOS. Этот архив позволяет нам эффективно изучить настоящий процесс создания контента, использованный в Virgin для реализации этой игры. В этом разделе я расскажу, что делает каждый инструмент и изложу хронику моего исследования и использования этих инструментов.
2.1. SNASM68K
Старый лог в архиве сообщает, что исходным ассемблером для Aladdin была версия 1.29 (или 1.30, как указано в некоторых комментариях к коду) SNASM68K. Я уже немного познакомился с SNASM после краткого экскурса в разработку для Sega CD много лет назад, но у меня был доступ к более новым версиям этого инструмента. Это значило, что для сборки исходников мне потребовалось внести некоторые изменения. Наиболее неприятным изменением было то, что в какой-то момент SNASM решил перейти от "!" и "|" к оператору OR, что привело к значительным изменениям в макросах. Также потребовалось добавить несколько операторов ветвления, несмотря на то, что архитектура памяти осталась относительно неизменной относительно коммерческого двоичного файла.
При изучении кода стало сразу понятно, что файл под названием FOLDER.68K должен был стать точкой входа для ассемблера. В этом файле определяется несколько переменных, что-то вроде «конфигурации сборки». Многие из переменных условно включают/исключают биты кода и определяют, какие данные должны быть записаны в ROM: PAL или NTSC. Разобравшись с этим и решив проблемы, связанные с различием версий SNASM, я попробовал запустить получившийся бинарник, и был рад увидеть это:
Этот фрагмент экрана читов, который, как оказалось, активен в розничной версии. Он по умолчанию появляется при запуске кода этого архива с обновлённой меткой времени, добавляемой SNASM. Его появление при запуске тоже зависит от одной из этих переменных «конфигурации сборки».
Я радостно двинулся дальше в игру, но был встречен зависанием при загрузке первого уровня. Пришло время взяться за отладчик! Так, стоп, у меня же нет отладчика. После пары попыток решения проблемы вставкой переходов на себя, чтобы сузить рамки возникновения зависания, я решил перестать мучить игру и посмотреть, существуют ли эмуляторы Genesis с встроенными отладчиками, которые не требуют скачивания 50 отдельных библиотек для создания собственной сборки с отладчиком. В этот момент я наткнулся на сборку Regen с включенным отладчиком, и дело пошло!
Поставив в Regen точку останова уже после зависшего состояния, я увидел, что счётчик программы находится в непонятном месте, состояния регистров перепутаны, а в стеке находится хлам, поэтому мне не удалось обнаружить последнее нормальное место выполнения кода, даже после попытки использования встроенного обработчика исключений Aladdin. Тут стало понятно, что будет не до веселья.
Создав с помощью SNASM адресную схему, чтобы понять, что же происходит, я получил адрес в точке кода, который походил на место, где начинается загрузка уровня. Я установил контрольную точку PC на этом адресе и запустил программу. После остановки на контрольной точке я пошагово продолжил программу и обнаружил, что она уходит в забвение где-то возле процедуры ProPack распаковки в ОЗУ. А именно, при распаковке данных FLOOR уровня. Они соответствуют своему названию — это таблица поиска, задающая тайлы пола уровня.
Я довольно долго пошагово выполнял цикл распаковки, не наблюдая никаких проблем, пока наконец не заметил адрес назначения. Процедура распаковывала данные пола по всему стеку пользователя. Похоже, что это ошибка! Я посмотрел на метки, определяющие положение активного пола в ОЗУ, и действительно, они была прямо над стеком пользователя.
Как оказалось, здесь происходила какая-то магия с макросами для получения максимального размера всех распакованных тайлов пола и использования его для определения размера области пола в ОЗУ. Эта магия макросов в моей версии SNASM в результате вычисляла отличное значение — 0. Я исправил эту ошибку и поискал в коде другие места, в которых бы использовалась такая же магия, и с этого момента всё пошло гладко. При поверхностном прохождении игры не возникло никаких очевидных ошибок.
2.2. Chopper
Chopper — это невоспетый герой, ставший фундаментом того, что Virgin называла технологией Digicel. К сожалению, у меня нет никакой информации о процессе, использованном для ручной отрисовки графики и её оцифровывания, кроме того факта, что на каком-то этапе графика импортировалась в DeluxePaint Animation. Не знаю, использовались ли в основном стандартные аппаратные/программные решения, или Virgin добавила собственные разработки. Всё что я знаю — после того, как данные поступали в DeluxePaint Animation, их оттуда получал Chopper.
Chopper — это полностью проприетарный управляемый с помощью интерфейса инструмент, работающий на основе собственного формата баз данных спрайтов. Его главным разработчиком был Энди Астор, но похоже, что в разработке участвовали и другие люди. В том числе Дэвид Перри, придумавший выходной формат данных Genesis. К сожалению, в архиве нет исходного кода Chopper, поэтому мы можем изучить его разработку только по сопроводительной документации.
Основной задачей Chopper была нарезка импортированных анимаций на тайлы, имеющих размер от 1×1 до 4×4 (в том числе и прямоугольных размеров, при которых каждый тайл имеет размер 8×8 пикселей). У него было множество вариантов нарезки, а также опций задания границ коллизий каждого кадра анимации и выбора нарезания кадра, последовательности кадров или целой базы данных. Сам интерфейс выглядел так:
На рисунке выше я импортировал заключённого (Prisoner), который исключён из розничной версии игры. Мы видим чёткие границы, по которым текущий кадр разрезался на группы тайлов. Жёлтый прямоугольник представляет собой границы коллизии кадра, а каждое число определяет, сколько раз используется группа тайлов.
Хотя Chopper работает с собственным форматом баз данных, он может экспортировать данные тайлов в разные целевые форматы идеальной платформы с основным упором на Genesis и SNES. В случае Aladdin/Genesis Chopper записывает несколько файлов .SEG (от слова Sega, а не «segment», как мог подумать ваш внутренний программист или создатель карт для Doom), которые представляют собой весь объём «сырых» данных тайлов для каждого размера с 1×1 по 4×4. Chopper также генерирует несколько файлов .68K, которые должны собираться как код и задавать дополнительные свойства каждого кадра (номер части, коллизия и свойства каждой части, такие как размер тайла, смещение и индекс). Эти файлы также определяют нужный порядок вложения данных, отражающий конечное расположение данных в ROM и задающий все необходимые ограничения расположения самих тайлов данных.
Упомянутый выше в статье скрипт Noesis fmt_virginmd_chopper.py пытается найти данные кадров в ожидаемом формате Genesis и преобразовать их обратно в набор файлов .SEG и текстовый файл .68K, ссылающийся на файлы .SEG, используя тот же формат названий, что и нативные данные Sega Chopper. Можете поэкспериментировать с текстовым файлом, чтобы понаблюдать, как изменение свойств влияет на использование тайлов так же, как это было бы на настоящем «железе».
Ещё один интересный аспект Chopper заключается в том, что он настроен на поиск однопиксельного прямоугольника для задания границ анимационной последовательности. Я также закодировал опцию параметров, чтобы повторить это в импортёре DeluxePaint Animation в Noesis. Поэтому многие исходники анимации выглядят примерно так:
Многие исходники содержат активные данные изображений за пределами нужного прямоугольника, который, вероятно, стандартно использовался для записи примечаний и сравнения. После того, как Chopper импортирует последовательность с обработкой по умолчанию, она в результате выглядит так:
Для использования в процессе импорта Chopper для игры Aladdin был написан ещё один инструмент, который простейшим образом обрабатывает нативные выходные данные .68K Chopper для выдачи дополнительных покадровых таблиц/списков. В них входит линейный список указателей на каждый кадр. Возможно, так сделано из-за желания увеличивать счётчик кадров переходами между указателями, а не обработкой переменного размера (так как имеется разное количество частей) каждого кадра.
2.3. tUME
В Aladdin используется тайловый редактор карт общего назначения tUME. Как и в любой другой игре той эры, использовавшей tUME, в Aladdin есть собственный упаковщик tUME. Упаковщик — это отдельный инструмент, экспортирующий данные в набор форматов, идеально подходящих к платформе и конкретной игре.
В случае Aladdin упаковщик tUME называется «tPJungle». Вероятно, он назван так, потому что был предназначен для использования в The Jungle Book. tPJungle создаёт множество файлов, в том числе данные блоков/персонажей, данные контуров (которые обычно являются общими для уровней), данные поиска/тайлов пола, различные типы данных комнат (в зависимости от того, является ли уровень традиционной комнатой или комнатой-картинкой, как бонусный экран Джинна и другие экраны камео, используемые в игре), файлы палитр и параллакса, которые позволяют нескольким слоям комнат ссылаться на данные персонажей/тайлов.
Выходные данные упаковщика tUME обычно затем сжимаются в отдельном пакетном процессе, после чего ссылки на сжатые (или в некоторых случаях на несжатые) данные вручную вносятся в файл .68K.
Враги и объекты располагаются в соответствии с номерами их тайлов. Это значит, что представленная ниже битовая карта таблицы тайлов соответствует непосредственно таблице в коде, запускающей выполнение спаунера/генератора соответствующего объекта на основании индекса тайла:
В таблице есть много неиспользованных ячеек, а также ячеек, которые раньше ссылались на удалённые теперь объекты (такие как заключённый (Prisoner) или глотатель мечей (Sword Swallower)), которые теперь перенаправляют исполнение на функции-пустышки. К сожалению, удалённые враги, похоже, не добавлены в исходники tUME, то есть кроме упоминаний в дизайн-документе у нас нет никакой информации о том, где и как должны были располагаться эти враги.
2.4. GEMS
В Aladdin применяется звуковой драйвер GEMS, использующий для воспроизведения музыки патчи FM и PSG. Также в PAL-версии есть отдельно сгенерированный набор данных. В нашем архиве нет промежуточных исходников GEMS, а сгенерированные с помощью GEMS код/данные сопровождаются пакетным файлом, из которого видно, что они скопированы локально из сетевого каталога. Это значит, что всё, что мы можем получить из этого архива, мы также можем получить из розничной версии игры, покопавшись в резервной копии данных секвенсора/сэмплов/патчей GEMS из двоичного файла.
Однако в этом архиве присутствует настоящий исходник Cakewalk MIDI (используемый для передачи секвенсору, который передаёт данные GEMS) и линейные сэмплы PCM, предоставленные самим Томми Талларико! Подробнее об этом можно прочитать в разделе 3.5 Звуки и музыка.
2.5. ProPack
Во множестве типов данных Aladdin активно используется ProPack Роба Нортена, в том числе для тайлов данных таблиц поиска пола и персонажей (но не анимированных/разрезанных). Как сказано в статье на Sega Retro, ссылку на которую я только что давал, в Aladdin используется только метод 1. Благодаря большому количеству справочной документации на декодеры (среди прочих, на языках ассемблера 8086, M68K и 6502), я также написал реализацию декодера для Noesis.
В архиве Aladdin есть множество пакетных файлов, которые, похоже, изменялись вручную для преобразования и сжатия всех нужных данных уровней, которые включались непосредственно в ROM. Предполагаю, что процесс создания уровней был примерно таким: «изменяем в tUME, сохраняем, выходим из tUME, выполняем пакетный файл, собираем, запускаем игру».
3.0. Скрытое сокровище
Самым потрясающим при изучении этого архива было открытие большого количества материалов, не вошедших в розничную версию игры. Меня очень удивило, что осталось невредимыми так много вещей, и ещё больше я удивился, когда выяснил, что в кодовой базе до сих есть куча соответствующего им кода (хотя он и не собран в образ розничного ROM).
Освоившись с Chopper и остальными инструментами, я решил заново импортировать часть удалённых ресурсов и добавить разные части кода для таких элементов, как старые генераторы объектов, анимации и логика элементов (которых в наши дни обычно называют акторами, или сущностями (entities), если вы фанат Quake). Я расширил размер ROM до 4 мегабайт (32 мегабита), чтобы в нём было достаточно места для возврата той части «плёнки», которая была вырезана на «монтажном столе» и чтобы не пришлось тщательно выбирать то, что я хочу вернуть. Часть кода была сразу готова к работе, но в других случаях мне приходилось что-то подправлять и настраивать, чтобы восстановить полный функционал.
Ещё одним потрясающим бонусом, найденным среди этих файлов, стала копия оригинального дизайн-документа игры версии 3.3, датированная 27 апреля 1993 года. Я использовал этот документ как справку, чтобы разобраться с истинным назначением незавершённого кода и функций, которые я нашёл в своём путешествии.
Я не буду описывать здесь все материалы, а поделюсь самыми большими на сегодня открытиями. Я также нашёл готовые для игры анимации скелета из демо-сборки для CES с дополнительной анимацией ходьбы. Похоже, что создатели намеревались сделать так, чтобы он падал в направлении игрока, а потом взрывался. В архиве нет кода для этого, и я ещё не настолько освоился, чтобы писать совершенно новую логику анимаций/состояний для него, поэтому я оставил это на будущее.
3.1. Бонусный раунд
Почти в первую очередь я наткнулся на код старого бонусного раунда Джинна. В нём в явном виде задаётся элемент «рука», которая представляет собой рычаг слот-машины, а также используется дополнительный код движения и состояния. Я полностью вернул код слот-машины Джинна и заново импортировал все зависимости анимаций через Chopper. Я также заметил, что в исходниках графики была анимация вращающейся монетки с Джинном, что имеет смысл с учётом тематики игрового автомата, поэтому я вернул и её тоже. Вот результат:
Можно заметить, что фон не совсем соответствует рычагу слот-машины. К счастью, мне удалось найти исходник карты tUME для фона, к которому он принадлежит, он был погребён в каталоге TRASH. Я экспортировал старую карту tUME с помощью tPJungle и вставил обратно в игру:
Однако у этого фона есть свои собственные проблемы. Передний слой настроен не совсем правильно, и в коде не осталось логики, соответствующей идее слот-машине с тремя барабанами, которую должен изображать фон. Сложно сказать, может быть, этот фон не добрался до этапа прототипирования, прежде чем попал в разрезанный блок, или связанный с ним код был полностью удалён. Возможно также, что эта копия в TRASH не является окончательным фоном, который использовался до удаления этого тематического бонусного раунда со слот-машиной.
Чтобы вернуть эту бонусную игру, нам придётся самостоятельно исправить довольно многое так, чтобы она выглядела логичной и сочеталась с исходной темой слот-машины. Однако у нас всё-таки есть все данные, которые необходимы для правдоподобного воссоздания исходной задумки в новой реализации. Версия этой бонусной игры со слот-машиной очень подробно описана в дизайн-документе игры. В нём также описана игра «камень, ножницы, бумага», но нигде нет ни следа её исходого кода или графики, так что, похоже, эту идею даже не начинали реализовывать.
3.2. Враги
Перед коммерческим релизом из игры удалили множество врагов. Причины удаления зависели, вероятно, от конкретной ситуации: несоответствие дизайну/внешнему виду, недостаток времени разработки или ограничения места в ROM. Учитывая то, насколько плотно розничная игра умещается в 2 мегабайта (16 мегабит) ROM, мы можем только догадываться о балансе принятия решений в каждом случае. Некоторые из этих врагов были полностью рабочими, другие же для своего спасения требовали любви и заботы.
Глотатель мечей
Глотатель мечей (Sword Swallower) по своему дизайну очень похож на жонглёра кинжалами (Knife Juggler) и должен был стать частью линейки врагов на рыночных уровнях. Он сидит в одном месте, вытаскивает изо рта бесконечный поток мечей и бросает их по экрану. Потребовалось также подключить код его мечей, но он был рабочим без дополнительных модификаций. Похоже, он действует точно так, как в реализации из демо-сборки для CES.
Заключённый
Заключённый (Prisoner) должен был появиться на уровне с подземельем султана (Sultan’s Dungeon). Он полностью завершён и имеет несколько последовательностей анимации. В режиме ожидания он спиливает цепь со своей ноги, а при приближении начинает размахивать ядром на цепи. У него также есть анимация боли/реакции, которую пришлось реализовывать с нуля, потому что следов связанного с ней кода не сохранилось. Заключённый также появляется в демо-сборке для CES, но в неправильной палитре, а в ROM отсутствует анимация реакции.
Золотая обезьяна
Золотая обезьяна (Golden Monkey) — это довольно простой враг, бросающий в игрока бесконечный поток самоцветов. На видео она показана в неверном контексте (на самом деле она должна была встречаться в пещере чудес (Cave of Wonders)). У неё больше нет других анимаций, и для её работы не требовалось никакого дополнительного кода.
В дизайн-документе поведение золотой обезьяны описывается как аналогичное поведению статуи Шивы в готовой игре. Статуя Шивы тоже должна была стать более интересным врагом, оживающим, когда к ней подлетает Яго и бросает пузырёк. Похоже, в какой-то момент просто решили отказаться от золотой обезьяны и использовать вместо неё статую Шивы.
Яго-фламинго
На уровне «Дворец султана» (Sultan’s Palace) Яго должен был предстать в обличье фламинго. Он ходит по экрану на ходулях и наносит игроку урон при касании.
Последовательность анимации Яго-фламинго также присутствовала в ROM демо-сборки для CES, хотя и этот враг не использовался в игре.
Катящаяся змея
Хотя змея и дожила до релиза игры, изначально она должна была кататься. На самом деле её внутреннее название ROLLY_SNAKE. Я наткнулся на код, который доказывал, что она должна была кататься, если после атаки оказывалась достаточно близко к игроку. Я подключил этот код обратно и увидел довольно любопытное поведение, при котором направление качения было очень случайным. Иногда змея оставалась в режиме «катания» даже после завершения анимации. Мне пришлось немного поработать над исправлением, и удалось вернуть эту атаку качением в состояние, в котором она выглядела логичнее.
Интересно, что в нашей версии дизайн-документа описываемое поведение довольно сильно отличается от того, что видно в коде:
Если змею два раза подряд ударяют метательными предметами, то она превращается в змею-колесо и катится вправо, через других врагов, убивая их. Змея катится так быстро, что Аладдин не может догнать её, и укатывается с экрана.
В исходном коде нет никаких свидетельств того, что это поведение вообще попадало в игру. Можно высказать догадку: это доказательство того, что существующая реализация качения была тестовой, эта функция показалась слабой, но разработчики всё равно пытались использовать уже созданные анимации. Анимации змеи (в том числе анимация катания) тоже присутствуют в ROM демо-сборки для CES, даже несмотря на то, что змея в этом демо не встречается.
3.3. Части тела Джинна
Из релиза игры было удалено несколько связанных с Джинном объектов, хотя ни один из них, похоже, так и не был доведён до совершенства. Эти объекты должны были использоваться на уровне «Внутри лампы» (Inside the Lamp) и влияли на движение игрока по карте.
Рука Джинна
Рука Джинна — это ладонь Джинна, соединённая с шестью шарами. Она двигается по постоянному маршруту и переносит игрока вместе с собой.
Рука Джинна скорее всего должна была дополнять сохранившиеся платформы-руки (которые добрались до розничной игры), как это описано в дизайн-документе:
Это основные «строительные кирпичики» уровня, они составляют большинство платформ, по которым двигается Аладдин. Некоторые из этих платформ уменьшаются и снова увеличиваются в размерах через одинаковые промежутки времени. Очевидно, чем больше рука, тем проще запрыгнуть на неё, потому что она представляет собой большую цель. В дизайне уровня должна максимально использоваться эта механика точного подбора времени для прыжков.
Другие платформы-руки будут выглядеть немного иначе и состоять из тайлов, а не спрайтов. Это позволит нам избежать раздражающего мерцания спрайтов.
Из-за особенностей реализации одновременно может существовать только одна рука Джинна, потому что в коде она написана как синглтон. Когда в область видимости попадает новая рука, предыдущая рука становится новой, то есть предыдущая исчезает.
Руки Джинна
Руки Джинна не упоминаются в документации, и единственное, что осталось в реализации — пара хлопающих рук. Взаимодействие с ними невозможно.
Сложно сказать, были ли они какой-то опасностью или тоже как-то влияли на перемещение. Возможно, что часть важного/связанного с ними кода была удалена (а не сохранилась для справки), потому что она привязана к другой (относящейся к игроку) логике.
Шар Джинна
Шар Джинна возникает при приближении игрока и при касании удерживает игрока на месте:
Назначение шара Джинна описано в дизайн-документе:
Это палка о двух концах. Если Аладдин попадает на верхушку катящегося шара Джинна, он может использовать его как движущийся лифт, чтобы обойти разные области лампы. Также шар даёт дополнительную высоту, которая иногда нужна для прыжка в бонусную или секретную область, но Аладдину может потребоваться какое-то время балансировать на шаре, пока он докатится до места, из которого нужно сделать прыжок.
Код шара Джинна довольно сильно интегрирован в код движения игрока, поэтому будет неудивительно, если в новой воссозданной форме что-то серьёзно испортится. Возможно, объекту также нужны не указанные здесь дополнительные настройки, судя по его поведению в демо-сборке для CES.
3.4. Наброски
В исходниках графики есть несколько оцифрованных набросков. Вот, например, наброски каждого кадра из анимации падения Аладдина:
В наброске второй анимации падения Аладдина есть больше подробностей. На самом изображении обозначены конкретные кадры для циклов и удержаний:
Это даёт нам небольшой намёк на то, каким на самом деле был процесс создания графики. Особо примечательна найденная мной готовая для игры анимация Абу, которая всё ещё находится в состоянии наброска:
В этом фрагменте анимации Абу заглядывает в мешок. Похоже, что эта анимация не отражена в событиях игры или в сохранившемся коде прототипа. Однако связанная с ней механика, которая влияет на битвы с боссами, упоминается в дизайн-документе:
Аладдин приходит к боссу, скроллинг останавливается, музыка сменяется на тему босса, которая используется для всех боссов. После смены музыки на экран вбегает Абу и кладёт волшебный мешок с драгоценностями, которые он неохотно одалживает Аладдину где-то на экране (на последних уровнях и на высокой сложности — в более труднодоступных местах), чтобы помочь ему победить босса.
Потом Абу снова сбегает с экрана, потому что он очевидно не хочет участвовать в последующем «веселье»! Аладдину остаётся только подойти к мешку (так же, как он собирает все объекты и метаемые предметы), после чего мешок исчезает (в инвентарь Аладдина).
Мешок Абу — волшебный, потому что там есть бесконечное количество драгоценных камней, то есть у Аладдина они никогда не кончаются. Однако у Абу, как мы знаем, есть пристрастие к драгоценностям, поэтому после победы над каждым боссом он забирает мешок обратно (мешок автоматически выбрасывается рядом с Аладдином после победы над боссом), Абу снова вбегает на экран, чтобы вернуть себе мешок, после чего опять скрывается.
При возврате волшебного мешка реакция/поведение Абу зависит от количества камней, которые Аладдин потратил на босса. Чем больше драгоценностей было потрачено, тем более яростна жестикуляция обезьяны. Если Аладдин не использует камней, то Абу в свойственном ему стиле демонстрирует свою радость. Скорее всего, в версии для картриджа будет три реакции Абу (радость, невозмутимость, гнев), в CD-версии — пять реакций.
Эта анимация рыбы, также присутствующая в демо-сборке для CES, тоже сохранилась вместе с готовой версией исходников графики:
Она говорит нам, что у нас есть готовая к игре графика с маской, которая всё ещё находится в форме наброска и готова к дальнейшей работе, и что часть её была использована в игре для демо-сборки. Маловероятно, что такое случилось бы, если бы процесс создания графики до этого момента не был невероятно упорядоченным. Это показывает нам довольно интересный рабочий процесс!
3.5. Звук и музыка
Хотя у нас и нет никаких относящихся к GEMS промежуточных данных исходников/проекта, мы нашли в архиве нечто ещё более интересное: «сырые» файлы Cakewalk MIDI и данные сэмплов, предоставленные Томми Талларико. Все эти цифровые сэмплы поставлялись в форме «сырых» 8-битных линейных «блоков» PCM. Именно так Томми называет в сопровождающем письме частоты дискретизации:
Стоит проверить темп всех композиций на случай, если произойдёт что-то странное с PAL-NTSC. Я уверен, что теперь вы в курсе проблем! Все сэмплы имеют частоту 10,4 кГц, за исключением следующих:jl87.vmd 8.7honk.vmd 5.2xplode2.vmd 5.8camel2.vmd 8.7finger.vmd 7.3feet2.vmd 7.3feet3.vmd 8.7cash2.vmd 7.3feet5.vmd 8.7
Томми также упоминает здесь разницу таймингов между NTSC и PAL, что было особенно важно при использовании GEMS, потому что тайминг записывался в конечные данные секвенсора, передаваемые драйверу GEMS. В Aladdin создатели особо позаботились о добавлении отдельных звуковых данных для PAL.
Инструменты и оборудование, которые использовались для передачи данных секвенсора Cakewalk в GEMS, неизвестны, но «сырые» блоки линейных PCM соответствуют тому способу, которым GEMS ожидает обрабатывать данные сэмплов. Взглянув на файлы проекта Cakewalk (вместо изучения двоичного файла, предназначенного для драйвера GEMS), мы могли бы получить более чёткое представление и об исходных треках.
Может оказаться интересным разобраться глубже, чтобы найти больше сравнений между исходниками в MIDI и данными GEMS, вставленными в розничную версию, но, думаю, мы оставим это на будущее.
3.6. Дизайн-документ
Я был потрясён, обнаружив его внутри zip-файла, погребённого внутри другого zip-файла. Там представлен огромный объём информации и больше планировавшихся функций, чем это можно было ожидать. Дизайн-документ имеет версию 3.3 и датирован 27 апреля 1993 года. В него внесли свой вклад многие люди: сам документ писали Дэвид Бишоп, Сет Мендельсон, Майк Диетц и Марк Ямада, а проверял его Дэвид Перри.
Очень много несоответствий между тем, что попало в дизайн-документ, и тем, что оказалось в игре. Я мог бы написать целую статью только об этом материале, но в этом разделе я укажу самые интересные несоответствия.
В целом, этот документ даёт нам много материала, с помощью которого можно воссоздать старые идеи и возможности, особенно те, для которых в какой-то степени есть графика. Также он даёт нам больше информации о небольших фрагментах графики, на которые нет отсылок в игре/коде, например, вот такой:
В оригинале дизайна подразумевалось, что игрок будет собирать бананы, вызывающие появление Абу в случайных местах уровня. Эта анимация создана таким образом, чтобы Абу можно было подхватить во время полёта на ковре (на это намекает поза и движение волос), но в других местах никаких следов подхватывания Абу не сохранилось. Также довольно интересно заметить, что эта анимация присутствует в ROM демо-сборки для CES, несмотря на то, что она никогда не использовалась в геймплее!
Что бы мы ни хотели сделать с исходным кодом и данными, этот дизайн-документ представляет собой невероятно ценный источник информации.
Уровни
В диздоке есть разбивка игры на изначальную схему уровней:
Уровень Цель Босс ------------------------------------------------------------ 1. Marketplace Спасти Жасмин Разул 2. Desert Найти скарабея 1 Нет 3. Marketplace rooftops Найти скарабея 2 Газим 4. Prison Сбежать из тюрьмы Нет 5. Cave of Wonders (gold) Дойти до комнаты с лампой Обезьяна Шива 6 Cave of Wonders (lamp) Взять лампу Нет 7. Fly out of cave Сбежать из пещеры Нет 8. Inside the lamp Найти Джинна Нет 9. 'Good' Palace Схватить Джафара Яго 10. Marketplace Пробиться ко дворцу Разул 2 11. 'Evil' Palace Уничтожить Джафара Джафар
Также там присутствуют планы различных уровней и боссов для версии игры на Sega CD, которые мы рассмотрим в разделе Sega CD. Структура уровней осталась практически нетронутой, за исключением нескольких заметных изменений:
- И Газим, и Разул появляются на уровне с крышами, а на уровне 1 нет босса.
- Похоже, прохождение Cave of Wonders немного улучшено и переходит в пеший побег, ведущий к побегу на ковре.
- Бой на рыночной площади (Marketplace) за путь к дворцу убрали, выполняется переход сразу от Sultan’s Palace к Jafar’s Palace. Также на этом этапе планировалась вторая встреча с Разулом.
Следов удалённого уровня с рыночной площадью не сохранилось, поэтому, вероятно, работу над ним так и не начинали, скорее всего, или из-за временных ограничений, или из-за объёма ROM.
Механики игрока
Между этой версией диздока и готовой игрой было внесено довольно много изменений в механики игрока. Вот некоторые из самых интересных:
- Аладдин не должен был уметь атаковать или метать предметы в падении, только в прыжке, вероятно, только на ведущей вверх дуге. В этом случае игра определённо игралась бы совершенно по-другому!
- В дизайн-документе особо оговаривается, что удар мечом Аладдина не будет использоваться для блокировки рукопашных ударов и ударов холодным оружием, но поведение в релизе оказалось совершенно противоположным, и часто это очень важно, чтобы избежать урона от атак стражи.
- При удерживании разных направлений на крестовине джойстика изначально Аладдин должен был бросать объекты в направлениях «вверх-влево», «вверх» и «вверх-вправо».
- Задержка при смещении взгляда вверх/вниз при удерживании крестовины вверх/вниз изначально была равна трём секундам.
- Даже в версии не для CD на некоторых уровнях в дополнение к яблокам метательными предметами были дыни и камни. Хотя это не упомянуто в документе, на каком-то этапе в игре присутствовали метательные лимоны. Подозреваю, что камни должны были находиться в таких уровнях, как пустыня, но мысль о побивании камнями людей и животных до смерти, скорее всего, была плохо воспринята в Disney!
- На некоторые уровни Аладдина должен был приносить Джинн. Похоже, я нашёл пару анимаций, которые как будто предназначены для этого процесса.
- Планировались дополнительные анимации ожидания, даже для версии игры на картридже:
Над Аладдином появляется облачко с мыслями о принцессе (только после того, как он узнаёт, что девушкой на рыночной площади была Жасмин), это подчёркивает, что он хочет увидеть её снова.
Над Аладдином появляется облачко с мыслями о девушке, которую он спас на рыночной площади (только после спасения, но до того, как он узнаёт, что она принцесса, это может меняться, в зависимости от того, как Разул снова появляется в игре засчёт торговца яблоками).
Ковёр влетает в кадр и жестами приглашает игрока познакомиться с программой (только после уровня в пещере).
- Планировалось, что когда здоровье Аладдина становится ниже определённого уровня, на уровнях под открытым небом появляется несколько падальщиков. Они присутствуют на слое параллакса и кружатся в ожидании его смерти.
В целом, похоже, что в готовой игре осталось самое лучшее, хотя направленные броски и дополнительные метательные объекты, а также чисто эстетические добавления были бы оказаться забавными!
Враги
Судя по тому, что я нашёл в исходной графике (см. выше), есть довольно большие различия между тем, что изложено в диздоке, и тем, что осталось в готовой игре. Кроме перечисления основного списка врагов и распределения их по уровням, в документе определяются уникальные враги в пределах каждого уровня.
Во многих случаях в дизайне определяются совершенно другие характеристики и сценарии поведения врагов:
- Низкие пузатые стражники должны были атаковать, размахивая палкой, а высокие худые стражники должны были метать ножи. В розничной версии они обменялись атаками.
- Крупные стражники, в дополнение к сохранившимся в релизе насмешкам, должны были использовать верхние и нижние атаки. Аладдин должен был уметь прокрадываться под ними или перепрыгивать эти атаки.
- На рыночной площади должны были появляться толстые женщины:
Они бегут влево/вправо, преследуемые мышью, и ударяются об Аладдина, если он не уберётся с их пути (не подпрыгнет). Женщин невозможно убить.
- Обстоятельства и темп битвы с Разулом изначально были совсем другими:
Разул должен стоять на крыше здания тюрьмы. Ширина здания занимает примерно половину экрана, и Разул виден из-за стены (видима только верняя часть его тела). С обеих сторон крыши стоят пирамиды, сложенные из бочек.
Разул шагает вперёд и назад на верхушке крыши. Поскольку здание будет посередине экрана, Аладдин способен подняться по его бокам с помощью серии платформ по обеим сторонам здания, на краях экрана. Платформы позволят Аладдину подобраться под Разула, и или сбоку от него, или прыгнув с самой верхней платформы, прямо над ним. Аладдин не сможет забраться на крышу.
Когда Разул подбирается к краю крыши, он сталкивает с края бочку. Бочка катится вниз, с платформы на платформу, пока не достигает земли (как в Donkey Kong), после чего падает в центральное отверстие. Разул должен сталкивать бочки раз в секунду или около того. Разул продолжает катить бочки, пока Аладдин не достигнет противоположной части крыши, а потом отбегает к другой стороне крыши и снова начинает толкать бочки.
Разула можно ударить только когда он перебегает с одной стороны на другую. Когда Аладдин находится на самом верхней платформе, Разул бросает в него ножи. Броски ножей выполняются между сталкиванием бочек, чтобы Аладдин не оставался на одном месте слишком долго.
Бочки наносят Аладдину урон, и их нельзя уничтожить, за исключением бочек со особой расцветкой. Их можно уничтожать ударом меча, открывая при этом бонусные предметы (здоровье, жизни и т.д.). Для победы над Разулом Аладдин должен бегать из стороны в сторону и вверх по платформам по обе стороны здания. В середине пола будет отверстие, через которое Аладдин должен перепрыгивать, иначе потеряет жизнь. Над серединой пола будет навес, мешающий Аладдину бросать предметы прямо в Разула.
- Планировался вариант зелёной змеи с жёлтыми полосами.
- Были запланированы периодические атаки братьев Яго (отличающихся от Яго цветом перьев):
Каждый из братьев Яго может нести в лапах один красный пузырёк. Красные пузырьки взрываются, касаясь любого объекта. Птицы влетают на экран, пытаются оказаться над Аладдином, а потом бросают пузырёк. Потом они снова улетают с экрана (сохраняя направление, в котором они двигались, когда бросали пузырёк).
Падая на Аладдина, пузырьки наносят ему урон. Аладдин также может попасть в клубы дыма, когда пузырёк падает рядом с ним, при этом он тоже получает урон. Клубы дыма пропадают через 0,5 секунд.
- На уровне с пустыней планировались враги-миражи, которые должны были появляться и исчезать, принимая вид существующих врагов. Миражи могут и наносить урон, и быть убитыми Аладдином.
- Враг «заключённый», обнаруженный в исходной графике, изначально должен был носить робу с чёрно-белым полосатым тюрбаном. Он должен был быть одного роста с Аладдином, а не очень высоким, долговязым персонажем, которого мы видели, и иметь дополнительную атаку с размахиванием цепью.
- Изначально планировалось, что у летучих мышей будет специальная атака пикированием.
- Планировалось, что один из братьев Яго должен прилететь и сбросить пузырёк на первого скелета в подземелье султана (Sultan’s Dungeon). Этим объяснялось бы то, что на этом уровне скелеты возвращаются к жизни.
- Золотые обезьяны изначально планировались для другого золотого уровня Cave of Wonders, в котором пещера должна быть заполнена золотыми монетами, драгоценными камнями и другими сокровищами. Скорее всего, золотую обезьяну убрали потому, что решили полностью вырезать этот уровень, а её поведение передали статуе Шивы.
- На втором уровне Cave of Wonders планировались каменные обезьяны, которые должны были вести себя как золотые обезьяны, но кидаться камнями, а не монетами/золотом/драгоценностями.
- Статуя Шивы, появляющаяся в уровне Cave of Wonders с дизайном золотой/каменной обезьяны, изначально должна была появиться во дворце и иметь следующий дизайн:
Действие:
Остаётся неподвижной, как большинство статуй, пока не прилетит Яго и не сбросит на неё пузырёк. Потом она волшебным образом оживает и начинает атаковать Аладдина.
Атака:
Своими многочисленными руками она должна вытаскивать драгоценные камни из своего головного убора и бросать их в Аладдина. Когда драгоценности падают на землю, они волшебным образом превращаются в пламя и горят 2-3 секунды. Каждый раз, когда её ударяет Аладдин, она теряет одну из своих рук.
Внешний вид:
Ростом примерно с Аладдина, но имеет 8 рук. Одета в шаровары и головной убор со множеством драгоценных камней. Должна иметь цвет и текстуру мраморной статуи даже когда оживает.
- Фламинго во дворце султана изначально имели немного более агрессивную механику:
Если игрок слишком долго стоит на фламинго, птица поворачивается и клюёт его. Одним из фламинго будет замаскированный Яго и он всегда отходит с пути, когда игрок собирается на него приземлиться.
- В битве с боссом Яго изначально делался упор на использование драгоценностей Абу для атаки Яго. Это был единственный способ столкнуть Яго ближе к шестерёнкам.
- Джафар в человеческом обличье должен был иногда бросать вниз красные пузырьки, которые создают долго не рассеивающееся облако опасного дыма.
- Джафар в обличье змеи должен был иметь атаку языком, и если атака удавалась, то он должен был улыбаться. У него было довольно много других вариаций атак/поведений.
Это никоим образом ни на что не влияет, и есть ещё много небольших различий между дизайном и реализацией в игре.
Камень, ножницы, бумага
Хотя не сохранилось ни соответствующего кода, ни данных, но присутствует полное описание игры в «камень, ножницы, бумагу». Стоит процитировать его здесь целиком:
Попав на бонусный экран, игрок видит в левой центральной части экрана ковёр, размахивающий своей левой кистью. Аладдин стоит в правой центральной части экрана и размахивает правой рукой. Камню соответствует кнопка A, бумаге — кнопка B, а ножницам — кнопка C. Подсказка показана в нижней центральной части экрана.
Правила аналогичны правилам обычной игры: каждый игрок выбирает камень, бумагу или ножницы. Камень обозначается кулаком, бумага — раскрытой ладонью, а ножницы — вытянутыми в форме буквы V указательным и средним пальцами. Пользователь играет за Аладдина.
Пока ковёр размахивает своей кистью, а Аладдин — рукой (так продолжается, пока игрок не сделает выбор), игрок должен выбрать одну из трёх кнопок: A, B или C. После выбора нужного предмета ковёр и Аладдин ещё два раза взмахивают кистью и рукой, а затем, на третьем взмахе, показывают свой выбор. Победитель празднует победу и он отображается на экране.
Если Аладдин проигрывает, то игра заканчивается и он возвращается на то же место, в котором он покинул уровень. После этого он на несколько секунд становится неуязвимым (этот процесс происходит также после третьей игры, вне зависимости от того, кто выиграл). Если Аладдин выигрывает, на экране графически (так же, как в обычной игре) и/или текстовой форме (в случае дополнительных очков) показывается его приз.
Затем игрока спрашивают, хочет ли он сыграть снова, чтобы иметь возможность выиграть больше, или покинуть игру, сохранив уже полученные предметы. Если игрок играет снова, он может проиграть и потерять все ранее выигранные предметы (например, если в первой игре Аладдин выиграл одну жизнь, во второй — 10 драгоценностей и ещё две жизни, а потом в третьей игре проигрывает, то он проигрывает всё, что выиграл ранее: 10 драгоценностей и две жизни).
За одно посещение бонусной игры можно сыграть не более трёх раз. Аладдин может сыграть во вторую игру, только если выиграл в первой, а в третью — только если выиграл в первой и второй.
В случае ничьей игра повторяется до тех пор, пока кто-нибудь не выиграет.
Правила
Камень побеждает ножницы
Бумага побеждает камень
Ножницы побеждают бумагу
Если у обоих игроков одинаковые предметы. то засчитывается ничья и игра повторяется.
Призы
Первая победа: жизнь
Вторая победа: 10 драгоценностей и две жизни
Третья победа: одна умная бомба Джинна, 15 драгоценностей, три жизни
Примечание: мы можем изменять призы в соответствии с выбранным уровнем сложности игры (выигрыши лучше при низкой сложности). Это будет решено во время настройки игры.
Примечание: призы суммируются, если Аладдин выигрывает все три игры, то получает шесть жизней, 25 драгоценностей и одну умную бомбу Джинна
Похоже, что эта идея возникла на ранних этапах разработки, как видно, некоторые элементы описания уже не соответствуют другим механикам дизайна и предметов.
Разбивка ROM
В диздоке была предпринята попытка заранее разбить требования к памяти всех персонажей, уровней и функций, несмотря на то, что в реальности этого добиться удалось не в полной мере. Это даёт нам замечательную возможность оценить, насколько внимательными приходилось быть дизайнерам и художникам к техническим ограничениям целевого носителя информации.
2048 КБ — общая доступная память картриджа
Предполагаемое использование памяти
480 КБ — 8 уровней, по 60 КБ на уровень (сюда входит набор тайлов, триггеры, контуры и всё прочее)
132 КБ — три уровня без наборов тайлов, по 44 КБ на уровень
175 КБ — музыка и звуковые эффекты
64 КБ — программа
64 КБ — таблицы спрайтов
64 КБ — контрольные таблицы
120 КБ — начальная заставка/интермедии/конечная заставка/финальный ролик (изображение каждой интерлюдии = 4 КБ)
30 КБ — логотипы Sega, Disney, Aladdin и Virgin
491 КБ — Аладдин и все персонажи, не привязанные к уровням
369 КБ — привязанные к уровням спрайты
241 КБ — боссы
80 КБ — все бонусные игры
___________
Требуется 2274 КБ
2048 КБ -___________
226 КБ лишних. Хм-м-м.
Разбивка 60 КБ по уровням:
11500 байт — данные фоновых персонажей (сжатые)
32768 байт — ссылки и сочетания блоков фона
1200 байт — пол и информация переключения спрайтов (сжатая)
400 байт — информация контуров
10699 байт — данные карт (сжатые)
2171 байт — данные параллакса карт (сжатые)
___________
Приблизительно по 58738 байт на уровень. [Эта оценка уменьшится, если графический стиль будет более простым, или если размеры уровней будут меньше максимально возможного размера]
Такая тщательная координация и планирование на самом деле по многим причинам являются здравой практикой, и это очень далеко от того дисбаланса, который мы часто наблюдаем между графикой, дизайном и программированием в современной разработке игр. Хотел бы я сказать, что ни разу не ругался на художника, засунувшего в игру огромную одноцветную текстуру 4096×4096, или на дизайнеров, которые сначала делают так, что загрузка уровня длится три минуты, а потом надеются, что за них всё починят. Раньше я стыдил сотрудников словами «твоя пустая текстура занимает больше места, чем 20 лет назад занимала целая игра».
3.7. Sega CD
Похоже, что версия игры для Sega CD планировалась с самого начала. К сожалению, несмотря на частое упоминание Sega CD в дизайн-документе, похоже, что исходная графика не дожила до нашего архива с Aladdin. Вот все относящиеся к CD особенности и элементы, которые мне удалось вытащить из диздока:
- Планировалось что во многих дополнительных уровнях Sega CD Аладдин появится в обличье принца Али. Диздок упоминает, что принц Али появится только в одном уровне версии на картридже, но он намеренно был вырезан для экономии места в ROM.
- Планировалось, что в CD-версии игры у Джафара будет третья форма в виде Джинна. Следов графики для этого этапа в архиве не сохранилось.
- На случай, если волшебный мешок Абу доживёт до розничной версии, для CD-версии планировались ещё две дополнительные реакции Абу на количество использованных Аладдином драгоценностей.
- В CD-версии планировалось заменить босса рыночной площади Разула на босса «торговец яблоками» (Apple Merchant). Сам Разул должен был стать боссом уровня с тюрьмой.
- В CD-версии на уровне с пустыней должен был появиться босс «песчаный скорпион». По этому боссу в дизайне нет никакой дополнительной информации.
- На втором уровне с рыночной площадью, ведущей к дворцу Джафара (которая не добралась до релиза), в CD-версии игры вместо второй встречи с Разулом планировался босс «пожиратель огня» (Fire Eater).
- Для CD-версии планировался допонительный метательный предмет — снежок.
- Специально для CD-версии планировались дополнительные анимации ожидания:
- Джинн влетает на экран и говорит одну из фраз (только после уровня с пещерой в CD-версии)
- Ковёр влетает на экран, похлопывает Аладдина по плечу и снова улетает (только после уровня с пещерой в CD-версии)
- В CD-версии должно было иногда появляться препятствие в виде человека, лежащего на гвоздях, оно позволяло Аладдину отпрыгнуть от него один раз, не получив урона. После первого прыжка человек «в негодовании» поднимался и его больше нельзя было использовать для прыжков.
- На уровне с пустыней в CD-версии планировались зыбучие пески:
Когда Аладдин проходит по определённым участкам песка, он начинает тонуть. Прыгая, он может постепенно выбраться из песка и пройти эти участки, не утонув. Если игрок оставляет его слишком надолго, Аладдин утопает в песке и теряет жизнь (или игра заканчивается, если это была последняя жизнь). Зыбучие пески внешне должны немного отличаться от обычных песков, чтобы внимательный игрок мог предусмотреть эту опасность.
Один участок зыбучих песков ведёт в секретную область. Чтобы попасть туда, Аладдин должен преодолеть своё естественное стремление спастись из ловушки, и оставаться на месте. Когда Аладдин проваливается под поверхность этого участка зыбучих песков, то прилетают и улетают скарабеи, сообщая, что он открыл новую область в пустыне, возможно что-то вроде пещеры (если у нас будут эти тайлы), где Аладдин может найти дополнительную жизнь, продолжение игры и разные другие бонусы.
С визуальной и геймплейной механикой возврата Аладдина на поверхность пустыни нужно ещё определиться, но для целостности мы используем ещё один переход кадра со скарабеем.
- Для CD-версии также планировалась вероятность использования кактусов:
Они будут различной формы и размера (возможно двух видов). Мы удалим их из игры, если они не будут соответствовать стилю мира Аладдина. Прикосновение к кактусу наносит Аладдину урон (1 очко урона при каждом касании).
Один тип кактуса можно уничтожить броском предмета или ударом меча. Другой, более основательно выглядящий вид кактуса никуда не девается, его можно только избегать.
Оба типа кактуса графически будут устроены таким образом, чтобы можно было создать несколько различно выглядящих кактусов, не используя слишком много графики, а значит и памяти.
- В дополнение к статичным канатам, по которым можно взбираться на уровне с рыночной площадью, для CD-версии игры планировались раскачивающиеся бельевые верёвки.
- Ковёр должен был иметь особую анимацию с горящими кистями после того, как слишком близко приближался к языкам пламени.
Планы для CD-версии часто переплетаются с элементами/функциями, которые были запланированы (но не дожили до релиза) версии игры на картридже.
3.8. Код
Можно многое рассказать о самом исходном коде. Один из наиболее интересных аспектов самого игрового кода заключается в том, что он управляется механизмом, в сущности явлющимся невероятно простым конечным автоматом. В этом фрагменте кода видно, как в ассемблере задаются такие аспекты, как последовательности анимаций:
; Скольжение
AN_ROLLY_SNAKE:
dc.w SN_SLTHR_FRAME1
mface_man
R_S: dc.w SN_SLTHR_FRAME1
dc.w SN_SLTHR_FRAME1
dc.w SN_SLTHR_FRAME1
mif_within_X 85,AN_ROLLY_SNAKE_BITE
dc.w SN_SLTHR_FRAME2
dc.w SN_SLTHR_FRAME2
dc.w SN_SLTHR_FRAME2
dc.w SN_SLTHR_FRAME3
dc.w SN_SLTHR_FRAME3
dc.w SN_SLTHR_FRAME3
Так генерируются байты/слова для каждой «команды». Каждый кадр анимации задаётся генерированием слова, и это слово является указателем на список указателей кадров примерно в начале ROM. Затем идёт множество макросов для таких вещей, как показанная выше условная логика mif_within_X, которая генерирует соответствующий командный байт. Командные байты удобно расположены за пределами диапазона значений известных значений указателей кадров. В результате этой команды для следующего цикла выполнения указатель данных состояния может иметь какое-то другое значение.
Элементы (объекты/акторы) чаще всего управляются обработкой кода таких данных состояний. Движение также обрабатывается похожим образом. Логика движения определяется генерируемыми байтами, а каждый элемент может передать указатель на свои данные состояния движения. Также очень часто данные состояния анимации заменяют указатель на данные состояния движения, поэтому здесь есть специальный макрос, используемый для генерации соответствующих байтов для этой операции.
Есть довольно большой объём кода, посвящённый выполнению этих небольших блоков состояний и управляющий расчётом таких вещей, как физика/коллизии и даже иерархия основных движений. Разумеется, игрок обрабатывается по-своему. Он, как и стандартные элементы, использует данные состояний, но имеет собственную ассемблерную boilerplate-логику, обрабатывающую большую часть более сложной логики состояний, которая также часто непосредственно задаёт указатели на состояния.
Такой способ обработки упрощает работу по добавлению новых объектов, и позволяет снизить затраты памяти, минимизируя количество нового кода, необходимого для каждого объекта и упаковывая логику в достаточно эффективные команды состояний. В сочетании с тем фактом, что сама логика состояний очень проста и есть специальные макросы для всех достаточно сложных случаев логики, то для игры масштаба Aladdin это отличная система.
Кроме того, существует много boilerplate-кода для обработки таких аспектов системного уровня, как передача данных с прямым доступом к памяти в VRAM. Процедура DMA_IT являлась основой для записи тайлов Chopper бласт-процессингом во VRAM. Chopper предназначен был для довольно эффективного минимизирования затрат. Он избегал затрат на распаковку в ЦП, при этом сводя к минимуму количество уникальных тайлов на кадр анимации. Я не работал над профилированием Aladdin и не изучал, сколько здесь обычно тратится циклов, но судя по конечному результату, система справляется со своей работой достаточно хорошо.
Здесь мы можем глубоко погрузиться в изучение бесчисленного количества систем, но если не слишком вдаваться в подробности, то я перечислил самые примечательные высокоуровневые операции в кодовой базе Aladdin.
Кроме всего сказанного выше, есть и другие интересные фрагменты, которые я заметил при изучении:
- Существует переменная времени ассемблирования MAKEDEMO, которую можно использовать для записи демо. При записи игра каждый кадр пишет команды с контроллера во VRAM. Интересно, что при записи демо можно увидеть, как на фоновых тайлах постепенно появляются артефакты. После заполнения выделенного буфера VRAM игра копирует данные из VRAM обратно в основную ОЗУ, потом бесконечно зацикливается на месте (потому что она только уничтожила основную память), поэтому можно подключить отладчик и выгрузить данные демо с известного адреса. Ради забавы я создал таким образом собственное демо.
- Другие интересные факты о демо: сами данные демо — это необработанный поток покадрового ввода с контроллера. И запись, и воспроизведение демо используют одинаковое начальное число генератора псевдослучайных чисел «12345678» для обеспечения детерминированных результатов.
- Есть также переменная времени ассемблирования MASTER. Похоже, в розничной копии она имеет значение OFF. При значении ON она отключает части дожившего до релиза экрана читов, но когда она включена, код без модификаций не ассемблируется. Можно предположить, что экран читов (по-прежнему содержащий номера телефонов и факсов) на должен был остаться в розничной версии.
- Чит-коды вместе с многими другими статичными данными перечислены в файле TABLES.68K. Они считываются по одному байту. Логика чит-кодов увеличивает указатель на соответствующую таблицу чит-кодов, и сбрасывает его при нажатии неверной кнопки. В исходниках не сохранилось дополнительных (кроме известных/задокументированных) скрытых/отключенных в релизе чит-кодов.
- Во время записи видео для этой статьи я хотел отключить высокочастотное мерцание, которое происходит, когда Аладдину наносят урон. Это нужно было, чтобы избежать его полного исчезновения на несколько кадров при перекодировании видео на более низкие частоты кадров. Найдя нужный участок кода, я обнаружил вокруг него ассемблерную проверку «IF TO_DEMO=OFF». Очевидно, я был не первым, кто столкнулся с этой проблемой при записи рекламного ролика! Похоже, TO_DEMO убрали из демо-сборки для CES или эту конкретную часть добавили позднее, исходя из того, что в этой сборке мерцание присутствует (когда отключена неуязвимость).
Не знаю, как насчёт вас, но лично меня все эти вещи заставили поностальгировать о золотой эре разработки игр.
4.0. Что дальше?
У каждой игры есть своя история, и иногда двоичный код говорит громче слов. Но исходный код обычно говорит ещё громче! Из-за отменённых прототипов, выброшенных демо и сбоев оборудования мы и так уже потеряли слишком много потрясающих моментов истории видеоигр. Если мы не начнём относиться к сохранению и архивированию в индустрии видеоигр более внимательно, особенно в случае аппаратных технологий DRM, то можем потерять гораздо больше.
Я начал этот проект с целью подготовки архив Aladdin к надлежащему сохранению, сделав первые шаги к стандартизации сохранения и архивации исходного кода на VGHF. Это подразумевало документирование исходного кода с верхнего уровня с целью определения его назначения и всех внешних зависимостей от других инструментов и/или данных, чтобы можно было стандартизированным образом отслеживать и эти зависимости. В процессе работы мне сразу стало очевидно, что Aladdin может рассказать интересную историю. Я надеюсь, что это только первая история из многих других, и мне не терпится выяснить, что же ещё скрывается в игре!
До встречи!
Автор: PatientZero