Wednesday, June 14, 2017

Sprite Status Tables, part 2

More often than not, objects need to go through some initialization at the start of their life, such as setting up their own attributes, loading a palette or queueing a PLC. In this scenario, an object may elect to overwrite its own code pointer by writing to (a0), which points at the base address of its SST.
Obj_MechaSonicHead:
    lea     ObjDat_MechaSonicHead(pc),a1
    jsr     (SetUp_ObjAttributes).l
    move.l  #Obj_MechaSonicHeadMain,(a0)
    lea     (ArtKosM_MechaSonicHead).l,a1
    move.w  #-$5A40,d2
    jmp     (Queue_Kos_Module).l
; ---------------------------------------------------------------------------

Obj_MechaSonicHeadMain:
    jsr     (Refresh_ChildPositionAdjusted).l
    ...
In the example above, Obj_MechaSonicHead replaces its own pointer with the address for Obj_MechaSonicHeadMain. Starting the very next frame, the object processor will instead jump to that address, so the init code will no longer run.

Objects that follow this pattern frequently let control fall through directly to the main bit of code, as seen in the example below. This ensures the object is running the moment it is created.
Obj_AIZHollowTree:
    move.b  #$D0,width_pixels(a0)
    move.l  #loc_1F752,(a0)

loc_1F752:
    bsr.w   sub_1F7B8
    ...
An alternative pattern is to use the routine attribute, stored in the 5th byte of an object's SST. The overall convention is shown below: the routine byte, which must always be even, is used as an index to an offset table stored directly below. The resulting offset is then used to perform a relative jump from the table to the appropriate routine, hence the name.
Obj_MonitorContents:
    moveq   #0,d0
    move.b  5(a0),d0
    move.w  off_1D7C8(pc,d0.w),d1
    jmp     off_1D7C8(pc,d1.w)
; ---------------------------------------------------------------------------
off_1D7C8:
    dc.w loc_1D7CE-off_1D7C8
    dc.w loc_1D81A-off_1D7C8
    dc.w loc_1DB2E-off_1D7C8
; ---------------------------------------------------------------------------

loc_1D7CE:
    addq.b  #2,5(a0)
    move.w  #$84C4,$A(a0)
    ...
This pattern is frequent in bosses and similarly complicated objects which cycle through a large number of states. It is also common to see it in "old" objects, such as rings and monitors, because this was the only pattern in Sonic 1 and 2. In those games, SSTs did not directly store a code pointer: it was read from the object list every time.

No comments:

Post a Comment