Как настроить монитор с подводной маской для работы с ним
Ты знал, что в Сонике 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> Вот и всё. Если ты не можешь даже добавить/понять это, то бросай затею, поскольку ещё не читал настоящее руководство.
Полное руковоство
This version tells you very well explained how to do this. It's not more than what you can see in the quick version, but with the extended guide you can learn something, so this one is recommended.
First off, open sonic1.asm and go to the Routine for the monitor contents (Obj2E). Scroll down until you see this: <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>
As you can see, there is no Goggle Code. But there is code that checks if the monitor contains 'S'. However, you can open SonED2 and add a new monitor using the object editor. Scroll through the different monitors, and you will see, in Obj2E are the monitors in the same order as in SonED2. The Goggle monitor is the last monitor in this list. This means: You have to add your new code under the code for the S.
Before Obj2E_ChkEnd add a new label. 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>
In ChkS is a code to branch to ChkEnd. Scroll up and you will see, there is in every monitor a code like this, but instead of branching to ChkEnd, they are branching to the next monitor code. So do the same with the S code. Change bne.s Obj2E_ChkEnd to 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>
Okay, we've set a few things up, but we are not done yet. Maybe you've noticed with the last step, those 2 lines in each monitor at the beginning (a 'cmpi.b' code and a 'bne.s' code). They are there to check if that monitor was destroyed and if so, do the code under it, otherwise check for the next monitor. We need that for the goggle monitor as well, so copy any of these 2 lines to your Obj2E_ChkGoggles: label. I'm using the lines of 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>
As you can see, this can't work, because they are checking for the same things! Look up again. Every monitor has a higher number in the cmpi.b command. The number in S was 7. So what is the next number? 8 of course! So change the 7 to 8 in your Goggle code: <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: We are nearly done. The last thing we have to do is to change the bne.s command in your Goggle code to ChkEnd. Like this: <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>
Now we are done, and you can insert coding in your Goggle monitor. But if you don't wanna add code for now, you have to add a nop under the bne.s command, otherwise you will get an Illegal zero length branch error when building. Also, you should change the comments, because they are really misleading. Here is my code: <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.