[Перевод] Как работает баг с миром −1 в Super Mario Bros
Мир −1 в оригинальной Super Mario Bros. — один из самых известных багов на NES. Если в зону перехода (Warp Zone) зайти специальным образом, игра глючит, и при входе в трубу вы попадаете в странный мир.
Попасть в мир −1 можно, почти пройдя уровень 1–2 и встав на трубу, ведущую на поверхность земли, к флагштоку и концу уровня. Затем нужно передвинуться к левому краю трубы, пригнуться и подпрыгнуть вправо, чтобы опускаясь Марио находился почти под потолком. Может потребоваться несколько попыток, но в результате он попадёт в нужную точку и автоматически пройдёт сквозь трубу, а затем через стену в комнату с зоной перехода. Если не будет виден хотя бы один пиксель трубы, Марио окажется в ловушке и игроку придётся ждать, пока не закончится время.
Ещё один способ попадания в мир −1: разбить два кирпичных блока на потолке, оставив самый правый. Потом нужно подойти к левому концу трубы и подпрыгнуть вправо. Пригибаться в этом случае не обязательно, потому что Марио может попытаться ударить (на самом деле не разрушая его). При этом в игре произойдёт сбой, и Марио сможет пройти сквозь трубу и стену. Но этот способ более сложен и долог. Если всё сделано правильно, игрок увидит перед собой три трубы зоны перехода. Если залезть в левую или правую трубу, Марио попадёт в мир −1. Если же опуститься в среднюю трубу, он перейдёт на уровень 5–1. В случае, если правая стена зоны перехода становится видимой, баг перестаёт действовать.
Но это не вся история о том, почему работает этот баг. Некоторые говорят, что так происходит, потому что на экране зоны перехода над трубой не отображается номер мира, когда вы заходите в неё. Но это неправда, и те, кто обладает пониманием механики игры, никогда не поверит в такое объяснение. Прочитав эту статью, вы сможете рассказать фантазёрам, что же происходит на самом деле. В этой статье мы подробно разберём и раскроем тайны возникновения бага «мира минус один».
Как работают зоны перехода
Чтобы понять, как мы попадаем мир −1, нам нужно сначала разобраться, как работают Warp Zone. В игре есть три таких зоны: одна в конце мира 1–2 (для перехода в миры 2, 3 или 4), вторая в конце 4–2 (перемещает в мир 5), а в третью можно попасть по лозе в мире 4–2 (и выбрать мир 6, 7 или 8). Давайте посмотрим, как игра узнаёт, в какие миры должна вести зона перехода.
Рисунок 1
Номера зон хранятся начиная со смещения $87F2 запущенной программы, данные выглядят следующим образом: 04 03 02 00 24 05 24 00 08 07 06 00
(00 отделяют зоны друг от друга). Первые 4 байта относятся к зоне в мире 1–2, следующие 4 байта — к подземной зоне мира 4–2, а последние 4 байта — к надземной зоне мира 4–2. Мы можем доказать это, взломав игру. Я использовал HEX-редактор, чтобы изменить значение 04 на 08, и посмотрите, что получилось:
С помощью редактирования памяти можно попасть и в другие миры-баги, например, в мир 0.
Следующая часть данных (на рисунке 1 красного цвета) относится к подземной зоне в мире 4–2, и состоит из 24 05 24. Это соответствует переходу в мир $24 (36) через левую трубу, в мир 5 через среднюю трубу и снова в мир $24 (36) через правую трубу. Но левая и правая трубы не существуют, поэтому мы можем попасть только в мир 5. Что же означает 24 в зоне перехода? Числами $24 в Super Mario Bros. обозначаются пустые места. Они нужны, потому что в смещении $87F2 указывается не только то, КУДА перемещают трубы, но и ЧТО на них писать. Объект зоны перехода должен всегда отрисовывать три тайла, соответствующие трубам зоны, но поскольку во второй зоне есть только одна труба, игра отрисовывает пустые пространства слева и справа. Мы можем показать хак, изменяющий эти значения слева и справа для отрисовки ненужных нам значений. Поэтому использование пустого места оправдано.
Эти переходы технически всё равно работают, мы просто не можем использовать их без трубы. Хаком я вставил ещё одну трубу, чтобы показать вам, что происходит при входе в трубу, переносящую в мир 36. Как труба с цифрой 5 переносит нас в мир 5, так и труба без цифры переносит в мир _, то есть на уровень −1.
Так как технически $24 означает 36, мы на самом деле переносимся в мир 36. Но игра обозначает это число пустым местом, поэтому кажется, что мы попали в мир _. На самом деле это мир 36. Но постойте, значения 24 есть только во второй зоне. Как же мы переходим в этот мир из уровня 1–2?
Как работает баг мира −1
На самом деле все зоны переходов — это один и тот же объект. Игра определяет, какую зону загрузить, на основании значения по адресу $06D6. По умолчанию это значение равно 00, то есть не соответствует никакой зоне. Но это нормально, потому что большую часть времени мы не находимся рядом с зонами перехода. Однако рядом с концом уровня 1–2 мы создаём объект блокировки скроллинга.
Он создаётся, когда мы находимся по горизонтали в этом месте.
Этот объект при создании выполняет код, который также увеличивает значение по адресу $06D6 на единицу, создавая трубы в зоне перехода. Обычно мы попадаем в зону перехода, пробежав по верхней части экрана, при этом создаётся ещё один объект блокировки скроллинга, а тот создаёт правильное значение зоны перехода.
Вот как это работает:
- Сначала игра загружает значение 04 по адресу $06D6. Это означает, что будет использоваться первая зона перехода.
- Потом она проверяет, на каком уровне находится игрок. Если игрок в мире 1, она использует 04 и сохраняет это значение в $06D6, а затем пропускает весь последующий код.
- Если игрок в другом мире, она загружает значение 05. Затем игра проверяет, на каком типе уровня находится игрок. Если игрок на подземном, подводном или замковом уровне, то она сохраняет в $06D6 значение 05.
Как сказано выше, если мы на уровне 1–2, это сохранение не выполняется, потому что игра пропускает эти инструкции и значение остаётся 04. Если же игрок находится на уровне над землёй, игра записывает значение 06 по адресу $06D6.
В результате для зоны уровня 1–2 значение будет 04, для подземной зоны уровня 4–2 — 05, а для надземной зоны — 06. Игра выводит на экран сообщение WELCOME TO WARP ZONE, если значение по адресу $06D6 равно 04, 05 или 06, что всегда истинно, когда мы создаём зоны перехода при обычном игровом процессе. Когда мы проходим объект создания зоны перехода, игра создаёт текст приветствия зоны перехода.
После вывода текста процедура определяет, какую зону перехода нужно загрузить, вычитая 04 из значения $06D6. Так что если значение равно 04, мы получаем 00, если 05, то 01, а если 06 — 02. Но так как мы создали объект блокировки скроллинга, а после этого вошли в стену, значение $06D6 по-прежнему равно 01.
Это значение 01 соответствует зоне перехода уровня 4–2, поэтому игра думает, что мы находимся в зоне уровня 4–2, а не 1–2. Мы можем проверить это, зайдя во вторую трубу, которая переносит нас в мир 5. Если мы заходим в левую или правую трубу, мы переходим в мир 36, или мир −1. Это объясняет, как мы попадаем в мир −1.
Мир −1
Почему этот мир является бесконечно зацикленной копией мира 7–2? Сначала разберёмся, почему мир −1 похож на 7–2. Когда мы заходим в трубу, игра запускает алгоритм, определяющий, в какую комнату нужно поместить Марио. Если значение по адресу $06D6 равно 00, что бывает в большинстве случаев, игра пропускает этот код и отправляет Марио в область, определённую в адресе $0650.
Это значит, что когда мы проходим сквозь изогнутую трубу на уровне 1–2, значение $06D6 равно 00, что возможно только при взломе, мы переходим туда, куда нас отправляет смещение со значением 25, что соответствует концу уровня. Так происходит, когда Марио заходит в изогнутую трубу. Но если значение не равно 00 и это не случай мира −1, потому что блокировка скроллинга устанавливает значение 01, то игра использует номер мира для поиска соответствующего смещения области в таблице поиска, чтобы понять, данные какого уровня нужно загрузить.
Если установить в качестве номера уровня $24, то код зоны перехода, определяющий место для перехода, использует значение $24 для смещения мира и получает значение $33, которое говорит игре искать смещение на $33 (51) байта от начала таблицы поиска, которое имеет значение 01, соответствующее миру 7–2. Таблица поиска состоит всего из 34 байтов, потому что обычно этого хватает для игры, поэтому смещение на 51 байт находится за пределами области таблицы поиска, в области таблицы данных врагов. Мы берём эти данные из таблицы, к которым таблица поиска на самом деле не должна иметь доступа. И так же работают другие миры-баги. Итак, игра загружает то, что она считает уровнем 36–1, но содержащий данные уровня 7–2.
Теперь давайте узнаем, почему уровни зациклены. Всё потому, что игра изменяет объекты в данных врагов. Посмотрим, как это работает. Объект изменения области имеет длину 3 байта. Первый байт — это расположение объекта в игре, второй — смещение адреса области, сообщающее игре, куда отправить игрока, когда он спускается в трубу или поднимается по лозе. Третий байт разделён на две части. Важная часть — это первые три бита: номер мира.
Текущий номер мира не соответствует номеру в объекте. Смещение области не обновляется, поэтому загружает клон уровня 7–2, который предназначен для изменения объекта области, но поскольку смещение области установлено на $25, мы перемещаемся в мир 7. Когда мы на самом деле находимся на уровне 7–2, смещению области установлено значение $25, потому что номер мира соответствует текущему номеру мира объекта.
Однако мир −1, считывающий данные с 7–2, находится не в мире 7, поэтому игра не загружает смещение области $25 в переменную смещения, что позволило бы нам покинуть уровень. Вместо этого, оно по-прежнему содержит значение 01, установленное на уровне 1–2. Поскольку смещение никогда не меняется, вместо выхода на поверхность уровень загружается сначала. Поэтому мир −1 бесконечно зациклен.
Так мы разрешили загадку бага с миром −1 в Super Mario Bros.! Теперь мы знаем, что такое мир −1 и как он появляется, а самое главное — как нам удаётся туда попасть. Надеюсь, вам было интересно.