Моды Sega-игр

2026-11-08 - 2026-11-09 #article

Много смотрел про то, что творят нейросетями по направлению моддинга игр. "Марио в Майнкрафте" и подобное безобразие. Больше всего меня заинтересовало добавление кооператива в игры, где он хорошо бы вписался, да в оригинале нет.

До этого уже пробовал вернуть деревянную стену из Stronghold HD в Stronghold Crusader DE. Ночами жёг лимиты, так и не получил результата. Игры обманчиво похожие, SHD вовсе не понадобился - вся деревянная графика есть в SHDE. Но восстановить оказалось на порядки сложнее, столько ресурсов и желания не нашлось. Возможно, лучшими инструментами когда-нибудь.

Решил попробовать начать с очень простого. Выбрать какую-нибудь игру на Sega Mega Drive (Genesis) с понятной возможностью модификации. Знаю, что Sonic 1 относительно легко поддаётся модификациям. Мне постоянно не хватает хороших кооперативов, поэтому на опыты выбрал 2-ю и 3-ю части, где два персонажа, но полноценного коопа нет.

Кооператив Sonic 2 и 3

Сразу результат:

Оригинальные ROM, патчи, скрипты сборки, готовые образы с кооперативом.

Доделал кооператив в Sonic 2, заодно добавил аналогичные правки в Sonic 3. В обеих играх Таилс частично играбелен: слушается управления второго геймпада, но не разбивает телевизоры, бессмертен, камера фокусируется только на Сонике, а Таилс постоянно улетает за экран.

Минимальные изменения, которые можно считать кооперативом:

Дополнительно добавил:

Sonic 2

С Sonic 2 почти не возникло проблем. Образ ROM всего 1 МБ. Поначалу.

Потом я захотел добавить счётчик колец Таилса отдельной строкой и пропал на несколько часов. Казалось, всего лишь нарисовать надпись. Только это не надпись, и нужна свободная область видеопамяти, а её не было. Все части памяти чем-то в любой момент могут быть заняты, и "несанкционированное" использование вылезает артефактами в других местах или приводит к зависанию.

Остановился на счётчике в виде двоеточия в той же строке RINGS. Просто 3:14, означающих 3 кольца у Соника и 14 у Таилса.

Попутно пришлось поднять размер образа до 2 МБ, потому что место выжато "до клеточки". На Sega часто использовали "более 100%" ресурсов, когда даже кусочки текстур переиспользовали на совсем другие вещи.

В игре есть соревновательный режим гонки. Как раз под него у Таилса были свои счётчики колец и многие механики. Этот режим не затронут и работает точно как раньше. Изменена только основная история.

Image

Sonic 3

Образ Sonic 3 вдвое больше второго. Игра красивее, думал, это в основном из-за графики, а код примерно такой же. Есть разные виды бонусов, такие как огненный и магнитный щиты, водяной пузырь и т.д., не похоже, что это сильно увеличит размер и повлияет в корневые механики.

Здесь уже, заранее наработав представление об организации памяти, "заказал" лучшие решения из второй части. Счётчик сразу "правильный". Проблем же не должно возникнуть? Простой перенос известных изменений в похожем коде? Нет. Ещё часы правок, запуска пары десятков отладочных образов. Пока сам не начал понимать примерное устройство переменных. Только тогда результат получился похожим на подходящий.

Игры различаются намного глубже. Проще посчитать, что в них общего, кроме названия. Почти ничего. Похожие вещи сделаны совсем по-разному. Даже обработчик получения урона ничем не похож, с другими событиями и порядком их срабатывания. Одна из причин, почему правка по трате жизни Таилсом сюда тоже сначала не применилась корректно.

Во второй части ограничение выхода за экран было сделано через ограничение максимального расстояния между персонажами. Здесь другая система разгона. Персонажи хорошо останавливались у правого края, но почти игнорировали левый, будто визуально стоят в центре экрана, а логически нет. Поставил ограничение на границы экрана и заказал аналогичную правку обратно в Sonic 2. Естественно, не подошло, и персонажи стали телепортироваться, как только каснутся края экрана. Да, камера там устроена не так.

На этом моменте стал вести две независимые ветки разработки, не пытаясь переносить "такие же" изменения из образа в образ. Архивы стали похожи на нормальные сборки, а не помойку с десятками промежуточных патчей и сборочных скриптов.

Несмотря на большой образ, S3 упакован даже плотнее S2. Не нашлось свободной видеопамяти одним куском, чтоб на пару десятков пикселей расширить область счётчика колец. Пришлось переносить всю область в другое место памяти. Почти вся память может быть чем-то занята, вместо цифр может появиться пиксельный мусор. Или, наоборот, цифра вместо другого спрайта. Получилось далеко не с первого раза.

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

Image

Как устроен патч

IPS (International Patching System) - бинарный формат патчей, содержимое которого нельзя прочитать как обычный текст. Он хранит смещения в ROM и данные, которыми нужно заменить исходные байты. Обычно такие файлы очень небольшие. Мои получились по 3–6 КБ, что для машинного кода немало.

Меня немного удивило, что при сопоставимом объёме изменений в Sonic 3 времени на разработку ушло значительно больше, включая работу с переносом графических тайлов в другие области видеопамяти, а IPS-файл оказался вдвое меньше, чем у Sonic 2.

Объясняется это расположением изменений в ROM: патч Sonic 2 содержит 574 отдельных участка, а Sonic 3 - всего 108. Объём изменённых данных сопоставим, но в Sonic 3 они сгруппированы в более крупные блоки. Поэтому на служебные данные IPS уходит значительно меньше места.

Скрипт build.py создаёт модифицированный ROM из оригинального образа и формирует IPS-патч, поэтому сборка воспроизводима. В обоих случаях я использовал версии игр REV00, которые легко найти. Оригиналы тоже приложил к архивам. Получившиеся архивы можно целиком передать боту с просьбой объяснить устройство модификаций или внести дополнительные изменения.

Например, я считаю версию с общим счётчиком колец и ограничением выпадения до 50 за раз тоже удачной. Патч не сохранился, но при необходимости его можно восстановить.

Выводы

В целом получил, что хотел. Но из-за устройства разработки на Sega всё оказалось сильно сложнее пары промптов. Первые результаты типа общей камеры в Sonic 2 действительно получены за один запрос. Чем дальше, тем медленнее. Хоть сколько-то играбельные сборки обоих Соников по всем пунктам заняли более 12 часов практически непрерывной работы агентов на максимальном усилии. Некоторых тупиков можно было бы избежать, но это ретроспектива. Пока не попадёшь - не узнаешь, что он есть и как выйти.

Должно работать в любом эмуляторе. Тестировал на BlastEm под MacOS вручную. Sonic 3 сложно тестировать из-за долгой заставки и времени до появления Таилса. Во втором всё нужное для тестов буквально в первые секунды на первых двух экранах.

Боты хорошо справляются с ассемблером, хоть и работают с ним очень долго. А вот организация памяти Sega для них слишком сложна, постоянно допускают графические баги из-за неспособности проследить за всеми хаками разработчиков.

Проблемы обычно начинаются при работе с видеопамятью. Изменения игровой логики, не затрагивающие графику, как правило, реализуются просто, и редко вызывают ошибки. Всё же логика игр тех лет была бесхитростной. Добавить систему прокачки персонажа с "невидимым" усилением - легко. Добавить одну циферку счётчика уровня - остальные 95% работы.

Своя разработка

Было бы интересно поиграть в "своё" хотя бы на железке типа Powkiddy rgb220s. Особенно с нормальным кооперативом, заложенным в основу. Были мысли о разработке своих небольших игр под Sega.

Сейчас нет жёстких требований запихать игру в 1-2 мегабайта. ROM спокойно может быть размером 8 мегабайт, возможно, эмуляторы обработают намного больше. Это снимает необходимость плотных хаков по месту в образе, но не в видеопамяти.

При длительной работе даже с чужим образом, наверное, проще сохранить его дизассемблированный вид, править код и собирать обратно. Возможно, даже переписать asm на нормальный язык, править в нём логику, потом переносить правки обратно. С таким подходом выглядит, будто можно сразу переводить какой-нибудь Go в образ ROM. Интересное направление, наверное, будет следующим шагом.