Как настроить монитор с подводной маской для работы с ним
Ты знал, что в Сонике 1 есть 2 неиспользованных монитора - "S" и "Goggle (подводные очки, не Google)? Ты можешь поставить и даже уничтожить их, но ничего не случится. Под "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. The most fitting one is Obj2E_ChkGoggles: in my opinion: <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>
7: Почти все. Осталось лишь изменить команду 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>
Пример
Although that code is perfect now, it still does nothing. Unless you already have plans to do something with it, you can use this very simple code, that gives infinite air in LZ.
Go to the Goggle code and add a line, which is moving $1 to an unused RAM adress: <asm> move.b #1,($FFFFFFA0).w ; move 1 to the goggle check</asm>
It should look like this: <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>
Next go to to Obj0A_ReduceAir: and add these 2 lines right after the label: <asm> tst.b ($FFFFFFFB).w ; was a goggle monitor broken? bne.s Obj0A_GoMakeItem ; if yes, branch</asm>
It should look like this: <asm>Obj0A_ReduceAir: tst.b ($FFFFFFFB).w ; was a goggle monitor broken? bne.s Obj0A_GoMakeItem ; if yes, branch ...</asm>
This is not a perfect code, because you will ALWAYS have infinite time underwater, once destroyed the monitor, but it works.