Spiiin's blog

Способ редактирования уровней Sega игр без знания ассемблера

ЧАСТЬ 1.
В продолжение поста “Взлом NES игр без знания ассемблера“.

Идея та же, с небольшими модификациями. Берётся любой эмулятор Sega Mega Drive, который умеет запускать lua-скрипты (например, Gens Rerecording v11b).

Дальше важный факт о сеговских играх - в большинстве из них используются разные варианты сжатия данных, но для некоторых игр существуют компрессоры-декомпрессоры. Распаковку данных игра чаще всего проводит при загрузке уровня. Процесс распаковки не мгновенный, поэтому допускаем, что уровень распаковывается в оперативную память целиком. Соответственно, начинать поиск можно сразу в оперативной памяти. Однако, следует учесть, что данные на экране зависят оттого, что находится не в оперативной, а в видеопамяти, и поймать момент между загрузкой данных в оперативную память и передачей её видеоадаптеру без отладчика не выйдет. Поэтому заметить измененные в оперативной памяти данные получится только, проскроллив до 2-го игрового экрана. Это можно сделать, загрузив на проигрывание файл с записью нажатий кнопок, или сделать руками.

Второй вариант более простой, поэтому стоит рассмотреть его. Адресное пространство оперативной памяти - 0xFF0000-0xFFFFFF - 64 кб. Луа-скрипт для изменения данных может быть таким:

startAddr = 0xFF0000
size = 0x1000
val = 0x00
savestate.load(1);
for mem = startAddr,startAddr+size ,1 do
memory.writebyte(mem, val);
val = val + 1;
end;

Перед запуском нужно сделать сейв тестируемой игры в момент, когда уровень уже распакован и загружен. Дальше мы забиваем первые 0x1000 байт оперативной памяти своими данными и пробегаемся по уровню, чтобы обнаружить изменения. Их с первого раза обнаружить, естественно, не удаётся, поэтому надо сделать следующий шаг в организации поиска. Эмулятор сам обнаруживает изменение скрипта и перезагружает его, поэтому можно изменять скрипт “налету”. Для этого удобно использовать внешний метаскрипт (например, на python), который будет перезаписывать файл скрипта, меняя значение startAddr, затем засыпать на несколько секунд, давая игроку доскроллить до экрана и заметить наличие/отсутствие изменений, а потом инкрементировать начальный адрес коррапта, чтобы эмулятор перезапустил скрипт и снова отправил игрока на исследования.

В случае неоднозначных изменений (например, персонаж проваливается сквозь пол, застревает в пустоте или мгновенно умирает), можно сужать пространство поиска, уменьшая размер size в два раза и проверяя отдельные половины оперативной памяти, пока не обнаружатся такие блоки уровня, которые не мешают персонажу пройти, но в то же время видны визуально на соседнем экране.

После сужения поиска до обнаружения одного-двух рядов блоков (см. скрин ниже), можно переписать метаскрипт так, чтобы он больше не менял значение адреса и размера, зато менял значение val в оперативной памяти. Это нужно, чтобы сделать скриншоты всех возможных блоков уровня для блочного редактора. Для удобства снятия скриншотов можно отключить фоны и/или отображение спрайтов в эмуляторе (клавишами Ctrl+F1/F2/F3). Процесс нужно будет повторить для блоков переднего и заднего фонов (Layer A & Layer B), они обычно находятся в памяти рядом друг с другом.

Quack Shot Starring Donald Duck_000

После этого остаётся вырезать со скриншотов линии с блоками и “сшить” их в ленту, чтобы засунуть в редактор CadEditor. После этого нужно сохранить дамп оперативной памяти в файл (в меню эмулятора - Tools->Ram dump) и написать конфиг для редактора, в котором указать файл с картинками и найденное смещение начала данных в дампе.

Метод протестирован на играх Tiny Toon Buster’s Hidden Treasure, QuackShot и Contra Hard Corps (^_^), все получилось добавить в редактор уровней:
cad_editor_contra
cad_editor_quackshot
cad_editor_tt

Игры используют системы построения уровней из блоков размером 32x32 (16x16 для QuackShot) пиксела, как и большинство NES-овских). Разница только в том, что Tiny Toon и Quackshot хранят их поэкранно, и используют раскладку(layout), в которой записаны номера экранов (они частенько повторяются в первых четырёх подуровнях первой зоны Tiny Toon), а Contra описывает весь уровень длинными линиями в 256 блоков и 16 блоков в высоту (причём в местах, куда игрок не может добраться, здания и не дорисованы доверху).

После редактирования уровня его ещё нужно упаковать и засунуть обратно в игру. Этого без кодирования сделать не удастся =\ Про запаковку в следующий раз.