spiiin: (Default)
Felix The Cat - одна из немногих игр для NES, использующая сжатие данных описания уровня.

Из интереса разобрал формат сжатия (почти не лазил дизассемблером, просто потыкал отдельные байты своими утилитами и проанализировал изменения на экране в эмуляторе).

Уровень состоит из блоков 2x2 (с аттрибутами палитры и физики). Блоков используется 128.

Все подуровни описываются одним массивом, это необязательно в движке, но, видимо, так было удобнее разработчикам). Каждая вертикальная линия описывается отдельно, уровень описывается как массив указателей на линии, если линия полностью повторяет предыдущую, просто используется указатель на эту линию. Повторение линий активно используется, где-то 40-50% линий - повторы. Также в указателях на линии несколько бит используются для кодирования объектов.

Линии сжимаются с помощью алгоритма RLE, после чего из сжатых пар (количество повторов блока, номер блока для повтора) образуется словарь и повторы заменяются на слова из словаря. Обычные блоки имеют индексы от 0x00 до 0x7F, слова из словаря нумеруются от 0x80 и дальше, до 124 слов в словаре.

Последние 4 значения 0xFC-0xFF используются для задания второй формы сжатия. Она устроена интереснее и используется на уровнях с мозаичным фоном (например, узоры на стенах пирамид на уровнях 2-2 и 2-3).
В этом случае в начале линии может использоваться команда из двух байт (номер_базовой_линии, кол-во блоков из базовой линии). На уровне используется 4 базовые линии (их номера кодируются от 0xFC до 0xFF), которые описывают зацикленную мозаику. Первые несколько блоков берутся из этой линии, а затем нижняя часть дорисовывается обычным способом.
Пример таких начал линий на скриншоте:



На нём выделены рамками повторяющиеся базовые линии.

Эти три приёма (индексирование линий, RLE-словарь и базовые линии) позволяют сжимать уровни размером в 18 килобайт до 4-5 килобайт.

Tags:
spiiin: (Default)
http://spiiin.github.io/CadEditor/tutorial-powerblade2.html

Вторая статья по исследованию формата уровней игр и составление конфига для редактора уровней CadEditor, на примере Power Blade 2 [NES]. Работа с дампами памяти и начало работы с отладчиком.


Все статьи по редактору CadEditor .

Tags:
spiiin: (Default)
http://spiiin.github.io/CadEditor/tutorial-tmnt2.html

Написал более подробную статью про использование инструментов для поиска данных в NES-играх и добавление игр  в редактор уровней.
(на основе поста о формате блоков 4x4 + 1 байт атрибутов)

Tags:
spiiin: (totoro)
Обновил мажорную версию своего редактора CadEditor уровней для кучи NES и SMD игр.

За 3 года добавил:

- Поддержку новых режимов аттрибутов (бит палитры и свойств) – поддержка аттрибутов на уровне блоков (уже была, игры Capcom) , макроблоков (Tiny Toon Adventures / серия Ninja Gaiden), описание аттрибутов отдельным слоем поэкранно (Contra Spirits / Mickey Mania / Batman).
- Поддержку иерархий макроблоков любого уровня вложенности (рекорд: Rokin' Kats – 4 уровня иерархии).
- Систему плагинов для редактирования конкретных аспектов игр (примеры - плагин для редактирования глобальной карты или плагин для редактирования фонов в SMD-играх, доработанный редактор фреймов анимаций для Capcom-игр).
- Конфиги для отображения блоков и экранов для десятка сеговских игр (в основном использующих компрессор RNC, для которого есть пакер). Заметки по форматам уровней: Раз, Два, Три. (SMD Earthworm Jim 1-2, Alladin, Jungle Book, Mickey Mania, Pitfall etc)
- Написал универсальную утилиту для поиска блоков и аттрибутов известных форматов для NES игр. Она магическим способом обнаруживает не только известные форматы блоков, но также находит и те, на которые не была запрограммирована!
- С помощью этой утилиты открыл наиболее часто встречающийся способ кодирования блоков в NES играх – 16 байт на блок 4x4 и 1 байт на палитру. Добавил поддержку таких блоков в редактор и описал конфиги для двух десятков игр с таким форматом (серия TMNT, серия Battletoads, серия Adventure Island, серия Power Blade, Jackal, Contra Force, Jackie Chan Action Kung Fu etc.)
- Улучшил утилиту Autocorrupter, для создания скриншотов изменных данных об уровне и их последующего анализа. Утилита используется для упрощения генерации конфигов картинками и блоками для редактора.
- Немного улучшил код редактора и добавил возможность использовать его как библиотеку, управляя ею из скриптов на языке Python (с использовнием Jupyter Notebook). Скриптование своих же программ позволило перейти от реверса конкретных игр к реверсу всех игр на платформе вообще.
- Написал несколько обзорных заметок про ромхакинг и возможности редактора.
- Запустил кампанию на Patreon, собирающую по 3$ в месяц на пиво :)
- Суммарно в проекте около 30к строк кода, 500 конфигов уровней для 85 разных игр.

Зачем всё это?
Если долго и упорно годами бить в одну точку, пространство раскрывается и показывает тайны скрытых неизведанных миров между строчек ассемблерного кода. Даже если эти миры существуют только для тебя и ещё нескольких сотен энтузиастов по всему миру.
Tags:
spiiin: (2D)
После праздников взял в руки NesBlockFinder, и прошёлся им по играм, добавленным в CadEditor с помощью Autocorrupter'а. Схема простая – меняем в редакторе в тестовом РОМе один из блоков на первом экране на 0-й (по нему проще находить начало списка блоков), и запускаем поиск блоков в BlockFinder'е.

С помощью применения такого подхода обнаружилась целая группа игр, в основе описания уровней которых содержится одна и та же структура:


Она состоит из 16 байт, которые построчно кодируют номера 16-тайлов видеопамяти,  по ним строится блок размером 4x4 тайла (именно блок, а не макроблок, как в играх капком).

В дополнение к индексам тайлов с таким блоком связан 1 байт, в котором закодированы индексы палитры для каждой группы 2x2 блока (выделены на скриншоте разными цветами), по 2 бита на каждую группу из 4х блоков слева-направо сверху-вниз. Биты палитры применяются сразу к группе тайлов из-за аппаратных особенностей NES, именно так на ней хранится описание бекграунда. NesBlockFinder не ищет такие биты палитры, но во всех проверенных случаях это описание оказывалось либо сразу за массивом описания блока тайлами, либо сразу перед ним, так что обнаружить поинтер на эти биты очень просто.

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


Эта структура оказалась настолько универсальной, что она обнаружилась в следующих играх:
Power Blade 1-2 (разработчик Natsume)
Adventure Island 2-3 (Hudson soft)
Yo-Noid (Now production)
Jackie Chan Action Kung Fu (Now production)
Contra Force (Konami)
Batman Returns (Konami)
Super C (Konami)
Monster in My Pocket (Konami)
Bucky O'Hare (Konami)
Jackal (Konami)
Teenage Mutant Ninja Turtles 1-3 (Konami)
Alien 3 (Probe entertaiment)
Battletoads (Rare)
Battletoads & Double Dragon (Rare)
Darkman (Ocean software)


И, возможно, обнаружится ещё в паре десятков других игр для этой платформы. Такая универсальность объясняется тем, что её легко закодировать (легче, чем иерархическую систему из блоков и макроблоков).
Tags:
spiiin: (2D)

Скрипт для поиска секретов в Утиных Историях 2. Отмечает квадратиками все игровые объекты, за счёт чего получается найти все секретные места.
https://github.com/spiiin/CadEditor/blob/master/Stuff/nes_lua/duck_tales_2_show_objects.lua
Tags:
spiiin: (2D)
Тестировал свой редактор трасс для Battletoads, собрал гипер-туннель, который очень хотелось бы отправить поиграть разработчикам Боевых Жаб, чтобы они поняли, как игроки мучались в детстве, когда после первых двух простых уровней они попадали в третий и видели нечто такое:

После этого, конечно же, надо представить, что в гости зашёл друг поиграть на двоих, а уровень перезапускается, если ошибается хотя бы один.
Tags:
spiiin: (2D)
Изобрёл ещё один способ реверса формата уровней NES-игр.

Способ во многом лучше предыдущего (автокорраптера) и работает практически в любой игре:

- не надо ловить момент старта уровня, достаточно сделать дамп памяти PPU в любой момент.
- не надо использовать графику вообще, метод работает напрямую с данными от PPU консоли.
- намного меньше усилий со стороны пользователя.
- способ сочетается с предыдущим (можно использовать оба метода для достижения лучшего результата).
- работает быстрее - перебирает все возможные варианты размещения блоков в ROM за 15-20 секунд.
- универсальнее (сработал в 48 из 50 проверенных игр, будет время – прогоню более полные тесты).

Теория
Read more... )

Идея метода
Read more... )

Результаты находок разных типов
Read more... )
Возможные улучшения

Read more... )
Ссылки
Исходники
Скомпилированный бинарник
Tags:
spiiin: (2D)
Нашёл отличное шоу.
Tags:
spiiin: (2D)
После промотра фильма Jungle Book решил вернуться к ромхак-анализу игр этой серии.

Существует несколько различных портов Jungle Book для разных консолей, выпущенных одной и той же командой разработчиков.
Версии для PC и Sega практически идентичны, Snes версия обладает схожей графикой, но полностью другими уровнями, а NES и GameBoy – очень похожими по структуре уровнями, но отличаются по используемому физическому движку и графике.
Для примера карты уровней для NES и SMD версии (можно сравнить позиции деревьев).

Однако при всей схожести сеговская версия проходится легко и приятно, а NES-версия – хардкорный ад, как будто разработчики намерянно решили усложнить игру в разы. Смотрите сами:

Во-первых, физический движок на NES написан так, чтобы усложнить жизнь игроку – медленно летящие снаряды, вроде осколков ореха наносят урон не один раз, а 4-5, что отбирает почти всё здоровье, попасть на врага сверху очень сложно, нужно чётко знать область повреждения, чтобы не промахнуться по ней (в сега версии можно хоть ударить врага снизу, игра всё равно вытолкнет Маугли наверх и нанесёт урон врагу), вдобавок иногда Маугли просто промахивается мимо лианы, пролетая сквозь неё. Дальше – на наклонной поверхности или после бега в NES версии Маугли начинает не останавливается сразу, а пробуксовывает вперёд, что часто приводит к незапланированным падениям. Ещё он умеет прыгать двумя способами, с места и с разбега, в обеих версиях, но в сеге отличия заключаются только в анимации прыжка, на NES же уровни построенны так, что иногда требуется прыгнуть только конкретным типом прыжка, иначе не хватит длины или высоты полёта. Особенно это ощущается в уровне Falling Ruins, целиком состоящем из падающих под весом Маугли платформ.

Во-вторых, в версии на SMD кристалы, необходимые для окончания уровня, чаще всего лежат на видном месте и для прохождения нужно найти не все из них, а только (8/10/12 из 15 в зависимости от выбранной сложности), причём можно найти компас, который показывает, где лежит ближайший кристал. В NES, соотвественно, некоторые кристалы спрятаны в секретных нычках, которые ещё нужно найти, иногда даже совершив "прыжок веры" вслепую, причём какую бы сложность вы ни выбрали, придётся собирать все кристалы. Часто приходится отыскивать по всему уровню последний лучше всего спрятанный кристал в условиях, когда кончается время (для справедливости отмечу, что в GameBoy версии всё ещё сложнее, в ней кристалы часто спрятаны внутри врагов, и для их отыскания приходится устраивать уничтожение всех животных, встреченных на пути в поисках драгоценностей).

В-третьих, Балу. В мультфильме есть эпизод, в котором он обучает Маугли жизни в джунглях и поёт песню:

Уровень The River в игре про этот момент. В Sega версии Маугли доходит до Балу со стороны реки, рядом три камня, Балу бросает фрукты, их надо ловить, если упасть в речку, бонус закончится, и начнётся следующий уровень. В NES же Балу просто пытается утопить Маугли, и его нужно победить. Друг называется...

Чтобы хоть немного облегчить NES-версию, я написал Lua-скрипт для эмулятора FCEUX, который добавляет в игру компас, который, как и в Sega-версии показывает направление к ближайшему ещё не собранному кристалу.
https://gist.github.com/spiiin/14acca27ded1989f86622eaa3ad1b515
Так что можно перепройти игру, не путаясь в лабиринтах из лиан:
Tags:
spiiin: (2D)
Когда-то я для тестов автоматического корраптера игр я находил массивы с описаниями экранов уровней обеих игр серии Flintstones для NES.
С помощью цепочки логических рассуждений (и скриптов для их автоматизации) можно получить полное описание формата уровней.

Read more... )

Заметки по формату уровней
- Часто используются хитрости для уменьшения размера, причём для разных уровней - свои. Для уровня замка используется полбанка видеопамяти, которые дублируются во вторую половину видеопамяти,  Для некоторых подуровней одного уровня используется общая "раскладка", например, для ночных джунглей, т.е. они используют общие наборы блоков и макроблоков, а также координатную сетку для описания объектов).
- После разметки обнаруживается небольшое различие в экранах для европейской, американской и японской версии игры, для уровня 3 данные не влезли в первые два банка, поэтому он находится в последнем банке с данными, в котором хранятся и строки, из-за чего смещения отличаются.
- В Surprise at the Dinosaur Peak размер макроблока уменьшен до 4x2, при этом удалось достичь того, что уровни состоят из намного меньшего числа макроблоков, при таком размере их функциональность намного увеличена.
- В описании уровней нету данных о физике блоков, она хранится где-то среди других данных, возможно, рядом со списками объектов.

(полноразмерные скрины)
Tags:
spiiin: (2D)

CaH4e3 (последний босс всех отечественных nes-ромхакеров) выложил видео процесса дизассемблирования «Чёрного Плаща» с нуля, с комментированием процесса. Эх, где он пару лет назад был...
Дизасмов игр такого размера в интернетах всего пара десятков, многие делаются годами (я за дизасмом ЧП недели две-три каждый вечер просидел, и то только формат карт и объектов исследовал для редактора, а не всю игру), а тут за несколько часов реверс движка и его оптимизация с освобождением места под три новых уровня — скрипты рулят.

В ходе просмотра ловил себя на мысли, что до сих пор визуально помню некоторые массивы данных и что именно в них хранится.
Tags:
spiiin: (2D)
Систематизировал немного свои заметки про устройство уровней в NES-играх:
http://habrahabr.ru/post/259171/ — Устройство уровней в NES-играх (про систему блоков и макроблоков)
http://habrahabr.ru/post/259483/ — Исследование формата карты уровней NES-игры «Jackal» (пример поиска данных об уровнях конкретной игры)
http://habrahabr.ru/post/259761/ — Устройство игрового движка для NES на примере игр «Capcom» (обзорно про всё)

Ради второй статьи улучшил скрипт автокоррапта образов игр (потребовалось немного модифицировать эмулятор Fceux, но теперь он и официально поддерживает фичи, нужные для коррапта) и прогнал через него ещё десяток игр, благодаря чему получил карты лабиринтов от Alien 3 (всегда забывал, как они проходятся):
Tags:
spiiin: (Default)
Прослушал лекции Мартина Одерски на курсере по Scala.
Курс читался два раза, и следующего набора пока нет (да и курсера логиниться не даёт с крымским IP, санкции, мать их), поэтому вместо решения предложенных заданий и для теста языка, я решил попробовать портировать Алгоритм разминирования бомб Джеймса Бонда, написанный мной на Python'e 5 лет назад.

За основу взял код Мартина из итоговой лекции, которой использовался для решения задачи The Water Pouring Problem (как получить X литров воды, имея заданное число стаканов разного литража без маркировки), так как она решается в общем случае тем же алгоритмом - методом поиска в ширину.

Именно эту задачу было интересно решить по нескольким причинам:
- В лекции алгоритм оставлен "сырым" (в него добавлен для оптимизации список уже пройденных вершин и кеширование последнего состояния вместо его вычисления, и то, только для того, чтобы он не тормозил на совсем простых данных). В моей задаче исходные данные из игры, из которых одна из загадок методом полного перебора решается очень долго, поэтому алгоритм нужно оптимизировать.
Так что была и простая подзадача - переделать алгоритм для решения задачи с бомбами, а не со стаканами; и более сложная - ускорить его работу.
- После окончания можно сравнить результаты с решением оригинальной задачи. В частности, по количеству строк кода, а то Python нравится как раз лаконичностью и удобным Repl, простые задачки можно решать, не выходя из него.
Так что:
james_bond_jr

Оригинальный код, перезаточенный для решения задачи разминирования бомбы, решил 3 задачи из 5, на остальных стал выдавать "java.lang.OutOfMemoryError: GC overhead limit exceeded" из-за разрастающегося размера массива входных данных.
Решение проблемы - не исследовать все возможные пути, а в первую очередь подробно рассматривать те, которые приближают к ответу.
Для того, чтобы реализовать это, к классу описания пути нужно примешать trait Ordered:

  class Path(path: List[Move], val endState: State) extends Ordered[Path]{
    def compare(that: Path): Int = {
      def diffFromEnd(x:Path) :Int = (x.endState zip endState).count( {case (x,y) => x!=y} )
      diffFromEnd(this) - diffFromEnd(that)
    }
   ...
  }

функции сравнения - количество символов, которые стоят не своих местах (diffFromEnd).

Также надо сменить контейнер, хранящий Path, с Set на Vector или любой другой, поддерживающий хранение данных в отсортированном виде, и в определённый момент (например, после раскрытия всех вершин из начала потока), отсортировать вершины по порядку наибольшей близости к желаемому состоянию endState.

Ещё один шаг оптимизации - можно допустить, что из состояния, более близкого к решению (похожего на решение), до самого решения нужно будет сделать меньшее количество шагов, чем из состояния, менее похожего на решение. Тогда можно отбросить более далёкие от решения варианты и перестать их обрабатывать(при этом есть риск выбросить и само оптимальное решение, всё зависит от качества оценивающей функции). Я решил обрубать по 50000 вариантов - решение при этом всё равно нашлось за 9 ходов, как и в Python-версии:

val sortedMore = (more take 50000).sorted


Итог:
 val initialState: State = Vector(1,2,2,1, 3,4,4,3, 3,4,4,3, 2,4,4,2)
 val endState: State = Vector(4,3,4,2, 3,1,2,4, 4,2,4,3, 2,4,3,1)

MoveLeft(2) //двигаем третью строку влево
MoveUp(3)  //двигаем четвёртый столбец вверх
MoveRight(1) //двигаем вторую строку вправо
MoveDown(2) //двигаем третий столбец вниз
MoveRight(0) //двигаем первую строку вправо
MoveDown(1) //двигаем второй столбец вниз
MoveRight(0) //двигаем первую строку вправо
MoveLeft(2) //двигаем третью строку влево
MoveLeft(2) //двигаем третью строку влево

Что полностью аналогично решению на Python для той же злополучной 4-й ракеты.

В итоге, получилось по строкам кода:
Решение на Python - 120 строк
Решение на Scala    - 65 строк
(выбросил для подсчёта функции вывода результата на python, на scala результат по умолчанию оказался читаем - список из "Имя кейскласса + параметр" - это как раз то, в каком виде хотелось увидеть ответ).
Кажется, можно попробовать поэкспериментировать со Scala Worksheets для решения простых задач вместо Idle with Python.
Tags:
spiiin: (totoro)
Завершение моего первого разбора формата уровней (3 года прошло).

Read more... )

Итоги:
Система из блоков и макроблоков похожа на систему, используемую в играх Capcom, с отличием, что наборы блоков и макроблоков состоят из двух частей - в первой половине блоков собраны общие для всех уровней элементы (пеньки, листья, деревья - почти вся игра проходит в джунглях), а во второй - уникальные для каждого уровня элементы. На скрине блоки только первой половины:

Такая схема позволяет съэкономить множество наборов повторяющихся для всех уровней наборов из 128 блоков.

Уровень не разделен на экраны, а описан одним большим экраном, объекты отсортированы сверху-вниз и слева-направо, на описание объекта выделены 2 байта, которые кодируют его тип, и выпадающий из объекта бонус (для кристаллов ещё его порядковый номер).

Загруженный в редактор уровней CadEditor уровень:
Tags:
spiiin: (totoro)
Продолжении серии.

Duck Tales 2 New impressions

Авторы: Цехмистров Данил
Описание:
Переделаны комнаты уровней, старые загадки переделаны на новый лад, форма уровней изменена для линейного прохождения (добавлены и изменены проходы между комнатами).
Сложность: уровни - чуть сложнее оригинала, боссы - без изменений.
Готовность: готов
Ссылки:
на ромхакинге


Duck Tales 2 No Gyro

Авторы: Цехмистров Данил
Описание:
"Без винта" - простой хак, в котором убраны все преграды, которые можно было предодолеть только с помощью специальных приспособлений, так что теперь уровни можно проходить в любом порядке без потери бонусов.
Готовность: готов
Ссылки:
на ромхакинге

Chip and Dale 2 Hack by Roket
chip_and_dale_2_rocket
Авторы: Roket
Описание:
Переделка уровней, боссов и объектов.
Готовность: 4 уровня из 9.
Состояние: дожидается своего часа.

Cat Ninden Teyandee 2014 (Beta 0.4)
chip_and_dale_2_rocket
Авторы: Excold
Описание:
Переделка уровней и перестановка объектов.
Готовность: все уровни по чуть-чуть.
Состояние: заморожен.
Ссылка:
на эму-ленде

Jungle Book level 1 change
jungle_book
Авторы: spin
Описание:
Мой старый тестовый хак 1-го уровня Jungle Book, в котором перепрятаны кристалы на первом уровне. Для тех, кто хорошо знает оригинал и хочет переиграть его по новому.
Готовность: 1 из 10 уровней.
Состояние: сделан ради теста редактора.
Ссылка:
дропбокс


Не на CadEditor'е, но очень перпективное начинание Ti_, добавление мультиплейера:
Duck Tales 2 Multiplayer hack

Публичной версии пока нету, но планируется.
Tags:
spiiin: (totoro)
В сети валяются несколько версий эмуляторов NES с открытыми исходниками. В основном это либо едва начатые учебные проекты, либо порты написанного на C универсального эмулятора FCE. Версия под android называется Nesoid, исходники её разбросаны по интернету:
http://sourceforge.net/projects/nesoid/
https://code.google.com/p/androidnes/source/browse/
https://f-droid.org/repository/browse/?fdfilter=nesoid&fdid=com.androidemu.nes

Полные исходники, с библиотекой Emudroid-Common, (без неё при сборке будет ругаться на нехватку файла utils/Log.h) и интерфейсом на Java, есть только на f-droid, там же есть и собранный из них готовый apk, так что для старта лучше выбрать их.

1. Библиотеки на C собирается с помощью Android Native SDK, после установки в папке с Nesoid достаточно набрать ndk-build, чтобы собрать нужные для эмулятора библиотека libnes, libemu и libnativehelper.

2. Для сборки самого эмулятора необходим Android SDK, с доустановленным через SDK Manager Android API 10 (под него по умолчанию собирается эмулятор). Сами Build tools лучше использовать версии > 19.0, потому что на 19.0 компилятор падает с Buffer overflow exception.

3. После установки всех необходимых sdk осталось установить систему сборки Ant, и для него указать в файле (PATH_TO_EMULATOR_SOURCES)/local.properties пути к sdk и ndk, например:
sdk.dir=C:/android-sdk
ndk.dir=C:/android-ndk-r9d


Далее можно собрать эмулятор с помощью команды
ant debug
и установить на подключенное по usb устройство с android:
ant installd

4. После этого при открытии рома эмулятор будет падать из-за ошибки в сигнатуре метода, поэтому в файле common\emumedia.cpp стоит поправить строчку 116:
- env->CallStaticIntMethod(jPeerClass, midSetSurfaceRegion, x, y, w, h);
+ env->CallStaticVoidMethod(jPeerClass, midSetSurfaceRegion, x, y, w, h);

После этого эмулятор будет работать нормально.

5. Что можно добавить в эмулятор полезного?
Практически любую фичу из реализованных в современной версии fceux.
Например, можно вернуть поддерживаемую в FCE опцию автоматической загрузки ips-патчей и проигрывание повторений игры. Если открыть файл romname.nes.ips или romname.nes.fcm, то эмулятор использует его, чтобы открыть игру romname.nes и загрузить данный файл - функция FCEUI_LoadGamе.
Всё, что нужно для активации данной фишки -добавить в GUI эмулятора отображение файлов нужных типов. Они описаны в файле (EMU_PATH)/res/values/arrays.xml:
<string-array name="file_chooser_filters">
  <item>.nes</item>
  <item>.fds</item>
  <item>.zip</item>
  <item>.ips</item> <!-- ips patches -->
  <item>.fcm</item> <!-- movies      -->
</string-array>


6. Можно также начать возвращение скриптовых возможностей. Встроить lua быстро не выйдет, но можно добавить свой обработчик в главный цикл эмуляции процессора X6502. Для этого сначала отредактировать файл (EMU_PATH)/neslib/Android.mk:
#LOCAL_CFLAGS += -DASM_6502  #убрать директиву, которая включает код реализации главного цикла на ассемблере.
LOCAL_SRC_FILES +=x6502.c    #добавить код реализации главного цикла процессора на C.


Дальше можно просто добавить в функцию X6502_Run_c вызов своего кода:
  ...
   CallInjected();  //вызов функции обработки каждый такт процессора.
   _PC++;
   switch(b1) {
   ...

 
Затем надо реализовать обработчик для конкретной игры и сделать распознавание конкретных игр по хэшу при открытии.

7. Можно для теста найти места переключения уровней в Super Mario Bros.
Lua-скрипт для win версии FCEUltra:
function logLevel()
  local logStr = string.format("Level %01X-%01X\n", memory.readbyte(0x75F)+1, memory.readbyte(0x75C)+1)
  print(logStr)
end

memory.registerexec(0xB8A5, logLevel) -- переключение обычных сцен
memory.registerexec(0x845A, logLevel) -- конец мира

8. Если подключить к эмулятору Google Play Services (про это нужна отдельная статья), то можно играть в Марио и получать ачивменты за пройденные уровни ^_^.

Screenshot_2014-07-31-18-43-43

Ссылка на приложение в маркете:
https://play.google.com/store/apps/details?id=com.androidemu.nesachiev
Tags:
spiiin: (totoro)
Семестровый пост про CadEditor.

cad_editor_v30

Добавил в редактор конфиги игр на Sega/GBA (Contra Hards Corps, Lost Vikings, Tiny Toon Buster's Hidden Adventure, Quack Shot, Zombies Ate My Neighbors, Final Fantasy Tactics Advance) – общие принципы построения уровней из тайлов такие же, разве что часто требуются внешние компрессор-декомпрессор из внутриигровых архивов.

Разобрал с десяток систем хранения списков игровых объектов (Tale Spin, Little Mermaid, Ninja Cat, Tiny Toon Adventures, Chip & Dale 2, Flintstones 1 & 2, Tom & Jerry, New Ghostbusters 2, Jungle Book, Zombies Ate My Neignborns), вдобавок к тем, что уже были разобраны. В них тоже много общих идей, прослеживаются два типа устройства систем – с равными по длине списками и с переменными по длине (часто со встроенной системой команд). У объекта имеется тип (иногда может быть несколько разных списков с разными форматами), координаты на экране (либо одномерные, либо двумерные) и, часто, несколько байт дополнительных данных (подтип, кол-во жизней, радиус появления и т.п.).

Из улучшений редактора:
- Нормальный интерфейс главного окна.
- Возможность работать с двумя реальными слоями и произвольным количеством виртуальных.
- Подредактор виртуальных макроблоков (структур), для составления и расставления по карте блоков произвольного размеры и формы.

Cписок поддерживаемых игр (8 игр полностью и ещё 33 в режиме редактора картинками).
Ссылка на редактор
Tags:
spiiin: (totoro)
Предыдущая часть

0.
Duck Tales 2 - одна из технически наиболее продвинутых игр Capcom на NES.

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

Для чистоты построения уровней решил сделать декомпрессор/компрессор данных видеопамяти, а не просто дампать уже разархивированную VRAM.


1.
Работа алгоритма понятна без дизассемблера, но архив разбит на 4 части (это сделано, потому что 1/4 часть видеопамяти общая для всех банков - там хранятся шрифт игры и стандартные для всех уровней объекты - бочки и сундуки), так что для сборки видеобанка надо написать логгер, который отследит начала частей архива в ROM.
После небольшого анализа кода выясняется, что процедуру распаковки можно остановить по адресу PC == $CFC0.
В этот момент в ячейках оперативной памяти хранится:
$67-$68 - адрес считывания данных.
$69         - банк считывания данных.
$6A-$6B - адрес записи в видеопамять.
$6C         - первый считанный байт архива (символ повтора).

2.
Для сбора информации о архивах можно использовать Lua-скрипт, который будет логгировать вызовы процедуры распаковки и копировать содержимое ячеек памяти в файл.
Основа Lua-скрипта универсальная и подходит для логгирования данных под любой поддерживающий скрипты эмулятор (требуется модуль binio).
https://gist.github.com/spiiin/88f80daaac6ab6bf5822



Read more... )

Чтобы со старта попасть в секретный бонусный уровень, можно в момент выбора уровня записать по адресу $С8 номер уровня 5.

Теперь надо последовательно запустить все уровни, чтобы получить лог с адресами архивов.
https://gist.github.com/spiiin/8a5107f473b42cb17c62
(если процедура декомпрессии не вызывается достаточно долго, в логах ставится разделитель, это позволяет разделять архивы конкретных уровней).
Область видеопамяти, в которую сохраняются фоны уровня - 0x0000 - 0x1000 (4 килобайта).
По логу видно, что некоторые участки памяти после первичной распаковки частично переписываются другими.

3.
Для извлечения данных надо реконструировать процедуру декомпрессии. Так как данных немного, можно написать это на python. После этого можно сделать процедуру обратной запаковки (для уменьшения количества кода используется модуль itertools:



Read more... )



Полный текст модуля.

Кроме используемых банков в игре есть неиспользуемый архив с графикой белки-летяги (найден Ti_):
BelkaUnuzed

4.
На этом можно остановиться, но для улучшения компрессии можно перестроить исходные данные. Так как ячейки памяти используются только в качестве индексов в описании малых блоков уровней, то их можно переставлять в любом порядка, просто изменяя их индексы в описании. Единственное ограничение – вторая четверть видеопамяти общая для всех уровней, поэтому безопастно изменять можно только 1,3 и 4-ю четверти. Алгоритм эффективного упорядочивания тайлов заключается в склеивании концов тайлов с одинаковыми байтами (один тайл видеопамяти на NES кодируется 16 байтами, для таких массивов и надо считать повторы байт в голове и хвосте массива). Так получатся более длинные цепочки из повторяющихся байт, а, следовательно, повысится эффективность сжатия. Получается бонус в 10-20 байт.
#Суть алгоритма:
# 1. Находим для всех массивов, какой длины у него есть "торчащие" голова и хвост из одинаковых элементов. Получаем массив из туплов - голова, хвост, индекс элемента.
# 2. Выбираем самую лучшую пару для соединения - ищем, какие голова и хвост могут образовать самую длинную цепочку
# 3. Соединяем два элемента массива в один - склеиваем голову и хвост, получаем элемент с новыми концами. Запоминаем также, какая пара элементов была склеена - храним список того, какие именно элементы были соединены.
# 4. Повторяем шаг 2 до тех пор, пока это возможно - пока будут находится пары элементов, у которых значение головы первого элемента пары совпадает со значением хвоста второго элемента.
# 5. Когда таких пар не нашлось - список невозможно дальше склеивать, теперь проходим по нему слева направо и восстанавливаем все списки индексов элементов - это лучшая последовательность для сжатия её алгоритмом RLE.

https://gist.github.com/spiiin/2ca831a508605c1706c3

Результаты переноса видеопамяти из игры Duck Tales в Duck Tales 2:
Tags:

Profile

spiiin: (Default)
spiiin

July 2017

S M T W T F S
      1
2345 678
9101112131415
16171819202122
23242526272829
3031     

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 24th, 2017 06:31 am
Powered by Dreamwidth Studios