Monday, June 5, 2017

The Great PLC Race

I briefly mentioned it before, but the graphics for both Robotnik and his flying machine are stored in the same Nemesis archive, called ArtNem_RobotnikShip in the current disassembly. However, when playing as Knuckles, the game needs to display Egg Robo instead of Eggman. The code responsible for this is in the init routine for the Robotnik head object:
Obj_RobotnikHeadInit:
    ...
    cmpi.b  #2,($FFFFB038).w
    bne.s   Obj_RobotnikHeadEnd
    move.l  #Map_EggRoboHead,$C(a0)        ; If player is Knuckles, use Egg Robo head
    move.l  #AniRaw_EggRoboHead,$30(a0)
    lea     (ArtKosM_EggRoboHead).l,a1
    move.w  #-$5A40,d2
    jmp     (Queue_Kos_Module).l
If the sight of a negative PLC destination address confuses you, fear not: that's just the disassembler being goofy. It's interpreting the value $A5C0 as a signed 16-bit integer because it doesn't know any better. They're the same thing.

Anyway, this works because the Nemesis decompressor unpacks directly to VRAM, three tiles at a time, whereas the KosM one has to unpack an entire module to 68000 RAM before being able to DMA it to VRAM. The animation below illustrates this process. Don't blink!


However, it also only works because normally, both the Nem and KosM queues are empty when the boss object loads. If the Nemesis queue happened to have stuff still in processing though, the Egg Robo art would race ahead, and later be overwritten by the Robotnik art when the Nemesis decompressor finally got around to it.

Remember how the main level art is stored in KosM format? It would be a shame if the level started and there were still some bits loading, so the game checks whether there are any Kos modules left to decompress before starting the level.

Yet...
loc_7870:
    move.b  #$C,(V_int_routine).w
    jsr     (Process_Kos_Queue).l
    bsr.w   Wait_VSync
    bsr.w   Process_Nem_Queue_Init
    jsr     (Process_Kos_Module_Queue).l
    tst.b   (Kos_modules_left).w
    bne.s   loc_7870
    rts
...There's no such check for the Nemesis queue. Which means, if you manage to load the boss object very quickly after the level starts, while Nemesis art is still decompressing...


Oh yeah, it's that other time where Knuckles fought Robotnik.

The easiest way to fix this is by compressing Egg Robo's head in Nemesis format too. That way, both art files go in the same queue, so there's no chance they'll get pushed to VRAM in the wrong order.

2 comments:

  1. In regards to the last paragraph, is that how the glitch is fixed in Sonic 3 Complete?

    ReplyDelete
  2. There was one time my brothers and I were playing and the boss's head swapped each frame between Eggrobo and Robotnik! Interesting!

    ReplyDelete