Как настроить монитор с подводной маской для работы с ним
(Оригинальное руководство написано Selbi)
Ты знал, что в игре Sonic the Hedgehog есть 2 неиспользованных монитора - "S" и "Goggles" (подводные очки)? Ты можешь поставить и даже уничтожить их, но ничего не случится. Под "Obj2E_ChkS:" в диассембле есть код для монитора "S", но вот кода для монитора с подводными очками нет! Если ты хочешь, чтобы этот монитор что-то делал, придётся его сначала настроить. Это не очень сложно, я объясню всё по шагам.
Быстрое руководство
Я знаю, что есть много людей, которые хотят просто скопировать код, не изучая его, поскольку считают, что у них есть более важные дела. Для них я потратил время на создание простого руководства для копипасты:
Найди Obj2E_ChkS: и замени всё оттуда этим: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code nop
Obj2E_ChkGoggles: cmpi.b #8,d0 ; does monitor contain Goggles? bne.s Obj2E_ChkEnd ; if not, branch to ChkEnd nop</asm> Вот и всё. Если ты не можешь даже добавить/понять это, то бросай затею, поскольку ещё не читал настоящее руководство.
Полное руковоство
В этой версии очень подробно расказано, как это сделать. На деле оно не больше, чем быстрая версия, но так можно чему-то научиться, поэтому рекомендуется это.
Для начала, открой sonic1.asm и иди к роутине содержания мониторов (Obj2E). Прокрути вниз, пока не увидишь: <asm> ... Obj2E_RingSound: move.w #$B5,d0 jmp (PlaySound).l ; play ring sound
- ===========================================================================
Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkEnd nop
Obj2E_ChkEnd: rts ; 'S' and Goggles monitors do nothing
- ===========================================================================
Obj2E_Delete: ; XREF: Obj2E_Index subq.w #1,$1E(a0) bmi.w DeleteObject rts</asm>
Как видишь, кода для подводной маски нет. Но тут есть код, который проверяет, содержит ли монитор "S". Однако, ты можешь открыть SonED2 и добавить новый монитор используя редактор объектов. Просмотри различные мониторы и ты увидишь, что в Obj2E мониторы в таком же порядке, как и в SonED2. Монитор с маской - последний монитор в этом списке. А это значит: тебе нужно добавить свой новый код под кодом для "S".
Добавь новый лейбл перед Obj2E_ChkEnd. Самый подходящий, пожалуй, Obj2E_ChkGoggles:: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkEnd nop
Obj2E_ChkGoggles:
Obj2E_ChkEnd: rts ; 'S' and Goggles monitors do nothing</asm>
В ChkS есть код для перехода к ChkEnd. Прокрути вверх и ты увидишь, что у каждого монитора почти такой же код, но вместо ChkEnd переход происходит к следующему коду монитора. Сделай тоже с кодом "S". Замени bne.s Obj2E_ChkEnd на bne.s Obj2E_ChkGoggles: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code nop
Obj2E_ChkGoggles:
Obj2E_ChkEnd: rts ; 'S' and Goggles monitors do nothing</asm>
Окей, мы кое-что сделали, но это ещё не все. Возможно, на предыдущем шаге ты заметил те две строчки в начале кода каждого монитора ('cmpi.b' и 'bne.s'). Они служат для проверки, был ли уничтожен тот монитор, и если да, исполнить код под ним, иначе проверять следующий монитор. Нам для монитора с маской это тоже потребуется, поэтому скопируй любые из этих двух строчек в твой лейбл Obj2E_ChkGoggles:. Я использую строчки ChkS: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code nop
Obj2E_ChkGoggles: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code
Obj2E_ChkEnd: rts ; 'S' and Goggles monitors do nothing</asm>
Как видишь, работать это не будет, так как они проверяют! Посмоти ещё раз. У каждого монитора в команде cmpi.b номер увеличивается. Номер S был 7. Так какой же будет следующим? Конечно же 8! Поэтому измени 7 на 8 в своем коде маски: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code nop
Obj2E_ChkGoggles: cmpi.b #8,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code
Obj2E_ChkEnd: rts ; 'S' and Goggles monitors do nothing</asm>
Почти все. Осталось лишь изменить команду bne.s в коде подводной маски на ChkEnd. Примерно так: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code nop
Obj2E_ChkGoggles: cmpi.b #8,d0 ; does monitor contain 'S' bne.s Obj2E_ChkEnd ; if not, branch to Goggle code
Obj2E_ChkEnd: rts ; 'S' and Goggles monitors do nothing</asm>
Мы закончили, и ты можешь вставить свой код в монитор. Но если ты не хочешь добавлять код сейчас, добавь nop под командой bne.s, иначе ты получишь ошибку Illegal zero length branch при компиляции. Также, тебе следует изменить комментарии, поскольку они довольно путают. Вот мой код: <asm>Obj2E_ChkS: cmpi.b #7,d0 ; does monitor contain 'S' bne.s Obj2E_ChkGoggles ; if not, branch to Goggle code nop
Obj2E_ChkGoggles: cmpi.b #8,d0 ; does monitor contain Goggles? bne.s Obj2E_ChkEnd ; if not, branch to ChkEnd nop
Obj2E_ChkEnd: rts</asm>
Пример
Хотя с тем кодом сейчас всё в порядке, он до сих пор ничего не делает. В случае, если у тебя ещё нет планов сделать с ним что-то, можешь использовать этот очень простой код, который даёт бесконечный воздух в Labyrinth Zone.
Иди к коду подводной макси и добавь строчку, которая перемещает $1 в неиспользуемый адрес RAM: <asm> move.b #1,($FFFFFFA0).w ; move 1 to the goggle check</asm>
Это должно выглядеть так: <asm> ... nop
Obj2E_ChkGoggles: cmpi.b #8,d0 ; does monitor contain Goggles? bne.s Obj2E_ChkEnd ; if not, branch to ChkEnd move.b #1,($FFFFFFFB).w ; move 1 to the goggle check
Obj2E_ChkEnd: ...</asm>
Затем иди к Obj0A_ReduceAir: и добавь те две строчки сразу после лейбла: <asm> tst.b ($FFFFFFFB).w ; was a goggle monitor broken? bne.s Obj0A_GoMakeItem ; if yes, branch</asm>
Это должно выглядеть примерно так: <asm>Obj0A_ReduceAir: tst.b ($FFFFFFFB).w ; was a goggle monitor broken? bne.s Obj0A_GoMakeItem ; if yes, branch ...</asm>
Код не совершеннен, поскольку после уничтожения монитора у тебя будет постоянно бесконечное время под водой, но работает.